From 07f4a98b95635b27beb0fa7efdb5adf131539563 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 6 Jun 2023 23:35:59 +1000 Subject: [PATCH] Replacing Toy_Literal function bytecode with Toy_RefFunction, addressing #77 This seems to have worked way too easily. --- source/toy_compiler.c | 5 ++-- source/toy_interpreter.c | 18 +++++-------- source/toy_literal.c | 12 +++------ source/toy_literal.h | 37 ++++++++++++++------------- source/toy_reffunction.c | 55 ++++++++++++++++++++++++++++++++++++++++ source/toy_reffunction.h | 23 +++++++++++++++++ 6 files changed, 110 insertions(+), 40 deletions(-) create mode 100644 source/toy_reffunction.c create mode 100644 source/toy_reffunction.h diff --git a/source/toy_compiler.c b/source/toy_compiler.c index 4629daa..c0258ba 100644 --- a/source/toy_compiler.c +++ b/source/toy_compiler.c @@ -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) - Toy_Literal fnLiteral = TOY_TO_FUNCTION_LITERAL(fnCompiler, 0); - fnLiteral.type = TOY_LITERAL_FUNCTION_INTERMEDIATE; //NOTE: changing type + Toy_Literal fnLiteral = ((Toy_Literal){ .as = { .generic = fnCompiler }, .type = TOY_LITERAL_FUNCTION_INTERMEDIATE}); //push the name 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: { //extract the compiler 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) size_t size = 0; diff --git a/source/toy_interpreter.c b/source/toy_interpreter.c index 3668dcf..a48dd2b 100644 --- a/source/toy_interpreter.c +++ b/source/toy_interpreter.c @@ -1323,8 +1323,8 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter //init the inner interpreter manually Toy_initLiteralArray(&inner.literalCache); inner.scope = Toy_pushScope(func.as.function.scope); - inner.bytecode = TOY_AS_FUNCTION(func).inner.bytecode; - inner.length = TOY_AS_FUNCTION_BYTECODE_LENGTH(func); + inner.bytecode = ((Toy_RefFunction*)(TOY_AS_FUNCTION(func).inner.ptr))->data; + inner.length = ((Toy_RefFunction*)(TOY_AS_FUNCTION(func).inner.ptr))->length; inner.count = 0; inner.codeStart = -1; inner.depth = interpreter->depth + 1; @@ -2428,20 +2428,16 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) { //get the size of the function 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 - 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"); - TOY_FREE_ARRAY(unsigned char, bytes, size); return; } - //change the type to normal - interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size); + //copies internally, since functions can exist independant of literalCache + interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(Toy_createRefFunction(interpreter->bytecode + interpreter->count, size)); + + interpreter->count += size; } } diff --git a/source/toy_literal.c b/source/toy_literal.c index ba37f67..9ceb3c9 100644 --- a/source/toy_literal.c +++ b/source/toy_literal.c @@ -59,7 +59,7 @@ void Toy_freeLiteral(Toy_Literal literal) { if (TOY_IS_FUNCTION(literal)) { Toy_popScope(TOY_AS_FUNCTION(literal).scope); 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) { @@ -84,12 +84,8 @@ bool Toy_private_isTruthy(Toy_Literal x) { 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) { - 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) { @@ -146,10 +142,8 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) { } case TOY_LITERAL_FUNCTION: { - unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION_BYTECODE_LENGTH(original)); - memcpy(buffer, TOY_AS_FUNCTION(original).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(original)); + Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(Toy_copyRefFunction( TOY_AS_FUNCTION(original).inner.ptr )); - 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); return literal; diff --git a/source/toy_literal.h b/source/toy_literal.h index 2d428bc..c730e39 100644 --- a/source/toy_literal.h +++ b/source/toy_literal.h @@ -3,6 +3,7 @@ #include "toy_common.h" #include "toy_refstring.h" +#include "toy_reffunction.h" //forward delcare stuff struct Toy_Literal; @@ -55,7 +56,7 @@ typedef struct Toy_Literal { struct { union { - void* bytecode; //8 + Toy_RefFunction* ptr; //8 Toy_NativeFn native; //8 Toy_HookFn hook; //8 } inner; //8 @@ -79,10 +80,13 @@ typedef struct Toy_Literal { void* ptr; //8 int tag; //4 } opaque; //16 + + void* generic; //8 } as; //16 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; #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_OPAQUE(value) ((value).as.opaque.ptr) -#define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL, 0}) -#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN, 0}) -#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER, 0}) -#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT, 0}) -#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value) -#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY, 0}) -#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY, 0}) -#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){{ .function = { .inner = { .bytecode = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION, l}) -#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE, 0}) -#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK, 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}) +#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}) +#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}) +#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY}) +#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}) +#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_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE, 0}) -#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE, 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}) //BUGFIX: For blank indexing #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); #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_HASH_I(lit) ((lit).as.identifier.hash) @@ -143,7 +147,6 @@ TOY_API void Toy_freeLiteral(Toy_Literal literal); //BUGFIX: macros are not functions 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_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype); diff --git a/source/toy_reffunction.c b/source/toy_reffunction.c new file mode 100644 index 0000000..ce25cd9 --- /dev/null +++ b/source/toy_reffunction.c @@ -0,0 +1,55 @@ +#include "toy_reffunction.h" + +#include + +//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); +} diff --git a/source/toy_reffunction.h b/source/toy_reffunction.h new file mode 100644 index 0000000..b51b876 --- /dev/null +++ b/source/toy_reffunction.h @@ -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); +