diff options
author | Jo-Philipp Wich <jo@mein.io> | 2022-02-07 10:13:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-07 10:13:38 +0100 |
commit | 78cdd2691a24dcb62f8342eabecfa8eeb2f301c2 (patch) | |
tree | d2c3aed28eb7c043c73b84ea3af0837225ee02a5 | |
parent | 5bd764a35aeaf50b54957bfa94ba94198514baf0 (diff) | |
parent | 11adf0c4ea91e63ec523849c2846fd07bf4348f5 (diff) |
Merge pull request #38 from jow-/function-memory-model
treewide: rework function memory model
-rw-r--r-- | compiler.c | 49 | ||||
-rw-r--r-- | examples/exception-handler.c | 10 | ||||
-rw-r--r-- | examples/execute-file.c | 6 | ||||
-rw-r--r-- | examples/execute-string.c | 13 | ||||
-rw-r--r-- | examples/native-function.c | 13 | ||||
-rw-r--r-- | examples/state-reset.c | 15 | ||||
-rw-r--r-- | examples/state-reuse.c | 15 | ||||
-rw-r--r-- | include/ucode/compiler.h | 4 | ||||
-rw-r--r-- | include/ucode/program.h | 33 | ||||
-rw-r--r-- | include/ucode/source.h | 11 | ||||
-rw-r--r-- | include/ucode/types.h | 35 | ||||
-rw-r--r-- | include/ucode/vallist.h | 3 | ||||
-rw-r--r-- | include/ucode/vm.h | 3 | ||||
-rw-r--r-- | lib.c | 17 | ||||
-rw-r--r-- | main.c | 12 | ||||
-rw-r--r-- | program.c | 118 | ||||
-rw-r--r-- | source.c | 44 | ||||
-rw-r--r-- | types.c | 121 | ||||
-rw-r--r-- | vallist.c | 24 | ||||
-rw-r--r-- | vm.c | 14 |
20 files changed, 265 insertions, 295 deletions
@@ -178,7 +178,7 @@ uc_compiler_syntax_error(uc_compiler_t *compiler, size_t off, const char *fmt, . buf = compiler->parser->error = xprintbuf_new(); if (!off) - off = ucv_function_srcpos(compiler->function, + off = uc_program_function_srcpos(compiler->function, uc_compiler_current_chunk(compiler)->count); if (off) { @@ -603,12 +603,12 @@ uc_compiler_finish(uc_compiler_t *compiler) uc_vector_clear(upvals); if (compiler->parser->error) { - ucv_put(compiler->function); + uc_program_function_free(compiler->function); return NULL; } - return (uc_function_t *)compiler->function; + return compiler->function; } static void @@ -1156,7 +1156,7 @@ uc_compiler_compile_arrowfn(uc_compiler_t *compiler, uc_value_t *args, bool rest if (fn) uc_compiler_set_u32(compiler, load_off, - uc_program_add_constant(compiler->program, &fn->header)); + uc_program_function_id(compiler->program, fn)); return true; } @@ -1595,7 +1595,7 @@ uc_compiler_compile_function(uc_compiler_t *compiler) if (fn) uc_compiler_set_u32(compiler, load_off, - uc_program_add_constant(compiler->program, &fn->header)); + uc_program_function_id(compiler->program, fn)); /* if a local variable of the same name already existed, overwrite its value * with the compiled function here */ @@ -2833,7 +2833,7 @@ uc_compiler_compile_declaration(uc_compiler_t *compiler) #endif /* NO_COMPILE */ -static uc_function_t * +static uc_program_t * uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, char **errp) { #ifdef NO_COMPILE @@ -2842,11 +2842,11 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, char **er return NULL; #else - uc_function_t *fn = NULL; uc_exprstack_t expr = { .token = TK_EOF }; uc_parser_t parser = { .config = config }; uc_compiler_t compiler = { .parser = &parser, .exprstack = &expr }; uc_program_t *prog; + uc_function_t *fn; prog = uc_program_new(source); @@ -2871,44 +2871,45 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, char **er uc_lexer_free(&parser.lex); - return fn; + if (!fn) { + ucv_put(&prog->header); + + return NULL; + } + + return prog; #endif } -static uc_function_t * +static uc_program_t * uc_compile_from_bytecode(uc_parse_config_t *config, uc_source_t *source, char **errp) { - uc_function_t *fn = NULL; uc_program_t *prog; prog = uc_program_load(source, errp); - if (prog) { - fn = uc_program_entry(prog); - - if (!fn) { - if (errp) - xasprintf(errp, "Program file contains no entry function\n"); + if (prog && !uc_program_entry(prog)) { + if (errp) + xasprintf(errp, "Program file contains no entry function\n"); - uc_program_free(prog); - } + ucv_put(&prog->header); } - return fn; + return prog; } -uc_function_t * +uc_program_t * uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp) { - uc_function_t *fn = NULL; + uc_program_t *prog = NULL; switch (uc_source_type_test(source)) { case UC_SOURCE_TYPE_PLAIN: - fn = uc_compile_from_source(config, source, errp); + prog = uc_compile_from_source(config, source, errp); break; case UC_SOURCE_TYPE_PRECOMPILED: - fn = uc_compile_from_bytecode(config, source, errp); + prog = uc_compile_from_bytecode(config, source, errp); break; default: @@ -2918,5 +2919,5 @@ uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp) break; } - return fn; + return prog; } diff --git a/examples/exception-handler.c b/examples/exception-handler.c index a9a0299..324a350 100644 --- a/examples/exception-handler.c +++ b/examples/exception-handler.c @@ -23,7 +23,7 @@ #define MULTILINE_STRING(...) #__VA_ARGS__ -static const char *program = MULTILINE_STRING( +static const char *program_code = MULTILINE_STRING( {% function fail() { /* invoke not existing function to raise runtime error */ @@ -58,17 +58,17 @@ int main(int argc, char **argv) int exit_code = 0; /* create a source buffer containing the program code */ - uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + uc_source_t *src = uc_source_new_buffer("my program", strdup(program_code), strlen(program_code)); /* compile source buffer into function */ char *syntax_error = NULL; - uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + uc_program_t *program = uc_compile(&config, src, &syntax_error); /* release source buffer */ uc_source_put(src); /* check if compilation failed */ - if (!progfunc) { + if (!program) { fprintf(stderr, "Failed to compile program: %s\n", syntax_error); return 1; @@ -85,7 +85,7 @@ int main(int argc, char **argv) uc_vm_exception_handler_set(&vm, log_exception); /* execute program function */ - int return_code = uc_vm_execute(&vm, progfunc, NULL); + int return_code = uc_vm_execute(&vm, program, NULL); /* handle return status */ if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { diff --git a/examples/execute-file.c b/examples/execute-file.c index 12910e3..1895cda 100644 --- a/examples/execute-file.c +++ b/examples/execute-file.c @@ -49,13 +49,13 @@ int main(int argc, char **argv) /* compile source buffer into function */ char *syntax_error = NULL; - uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + uc_program_t *program = uc_compile(&config, src, &syntax_error); /* release source buffer */ uc_source_put(src); /* check if compilation failed */ - if (!progfunc) { + if (!program) { fprintf(stderr, "Failed to compile program: %s\n", syntax_error); return 1; @@ -74,7 +74,7 @@ int main(int argc, char **argv) /* execute compiled program function */ uc_value_t *last_expression_result = NULL; - int return_code = uc_vm_execute(&vm, progfunc, &last_expression_result); + int return_code = uc_vm_execute(&vm, program, &last_expression_result); /* handle return status */ switch (return_code) { diff --git a/examples/execute-string.c b/examples/execute-string.c index 1fcc966..fe5e8e9 100644 --- a/examples/execute-string.c +++ b/examples/execute-string.c @@ -28,7 +28,7 @@ #define MULTILINE_STRING(...) #__VA_ARGS__ -static const char *program = MULTILINE_STRING( +static const char *program_code = MULTILINE_STRING( {% function add(a, b) { c = a + b; @@ -55,17 +55,17 @@ int main(int argc, char **argv) int exit_code = 0; /* create a source buffer containing the program code */ - uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + uc_source_t *src = uc_source_new_buffer("my program", strdup(program_code), strlen(program_code)); /* compile source buffer into function */ char *syntax_error = NULL; - uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + uc_program_t *program = uc_compile(&config, src, &syntax_error); /* release source buffer */ uc_source_put(src); /* check if compilation failed */ - if (!progfunc) { + if (!program) { fprintf(stderr, "Failed to compile program: %s\n", syntax_error); return 1; @@ -84,7 +84,10 @@ int main(int argc, char **argv) /* execute compiled program function */ uc_value_t *last_expression_result = NULL; - int return_code = uc_vm_execute(&vm, progfunc, &last_expression_result); + int return_code = uc_vm_execute(&vm, program, &last_expression_result); + + /* release program */ + uc_program_put(program); /* handle return status */ switch (return_code) { diff --git a/examples/native-function.c b/examples/native-function.c index 9c643ec..5c2f6da 100644 --- a/examples/native-function.c +++ b/examples/native-function.c @@ -23,7 +23,7 @@ #define MULTILINE_STRING(...) #__VA_ARGS__ -static const char *program = MULTILINE_STRING( +static const char *program_code = MULTILINE_STRING( {% print("add() = " + add(5, 3.1, 2) + "\n"); print("multiply() = " + multiply(7.3, 5) + "\n"); @@ -61,17 +61,17 @@ int main(int argc, char **argv) int exit_code = 0; /* create a source buffer containing the program code */ - uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + uc_source_t *src = uc_source_new_buffer("my program", strdup(program_code), strlen(program_code)); /* compile source buffer into function */ char *syntax_error = NULL; - uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + uc_program_t *program = uc_compile(&config, src, &syntax_error); /* release source buffer */ uc_source_put(src); /* check if compilation failed */ - if (!progfunc) { + if (!program) { fprintf(stderr, "Failed to compile program: %s\n", syntax_error); return 1; @@ -89,7 +89,10 @@ int main(int argc, char **argv) uc_function_register(uc_vm_scope_get(&vm), "multiply", multiply_two_numbers); /* execute program function */ - int return_code = uc_vm_execute(&vm, progfunc, NULL); + int return_code = uc_vm_execute(&vm, program, NULL); + + /* release program */ + uc_program_put(program); /* handle return status */ if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { diff --git a/examples/state-reset.c b/examples/state-reset.c index 692aa76..ce61e7f 100644 --- a/examples/state-reset.c +++ b/examples/state-reset.c @@ -23,7 +23,7 @@ #define MULTILINE_STRING(...) #__VA_ARGS__ -static const char *program = MULTILINE_STRING( +static const char *program_code = MULTILINE_STRING( {% /* the global test variable should've been reset since the previous run */ print("Global variable is null? " + (global.test == null) + "\n"); @@ -43,17 +43,17 @@ int main(int argc, char **argv) int exit_code = 0; /* create a source buffer containing the program code */ - uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + uc_source_t *src = uc_source_new_buffer("my program", strdup(program_code), strlen(program_code)); /* compile source buffer into function */ char *syntax_error = NULL; - uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + uc_program_t *program = uc_compile(&config, src, &syntax_error); /* release source buffer */ uc_source_put(src); /* check if compilation failed */ - if (!progfunc) { + if (!program) { fprintf(stderr, "Failed to compile program: %s\n", syntax_error); return 1; @@ -70,11 +70,8 @@ int main(int argc, char **argv) printf("Iteration %d: ", i + 1); - /* take additional reference to progfunc to avoid freeing it after execution */ - ucv_get(&progfunc->header); - /* execute program function */ - int return_code = uc_vm_execute(&vm, progfunc, NULL); + int return_code = uc_vm_execute(&vm, program, NULL); /* handle return status */ if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { @@ -88,7 +85,7 @@ int main(int argc, char **argv) } /* release program function */ - ucv_put(&progfunc->header); + uc_program_put(program); return exit_code; } diff --git a/examples/state-reuse.c b/examples/state-reuse.c index 7e2c44f..f7321f6 100644 --- a/examples/state-reuse.c +++ b/examples/state-reuse.c @@ -23,7 +23,7 @@ #define MULTILINE_STRING(...) #__VA_ARGS__ -static const char *program = MULTILINE_STRING( +static const char *program_code = MULTILINE_STRING( {% let n = global.value || 1; @@ -44,17 +44,17 @@ int main(int argc, char **argv) int exit_code = 0; /* create a source buffer containing the program code */ - uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + uc_source_t *src = uc_source_new_buffer("my program", strdup(program_code), strlen(program_code)); /* compile source buffer into function */ char *syntax_error = NULL; - uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + uc_program_t *program = uc_compile(&config, src, &syntax_error); /* release source buffer */ uc_source_put(src); /* check if compilation failed */ - if (!progfunc) { + if (!program) { fprintf(stderr, "Failed to compile program: %s\n", syntax_error); return 1; @@ -71,11 +71,8 @@ int main(int argc, char **argv) for (int i = 0; i < 5; i++) { printf("Iteration %d: ", i + 1); - /* take additional reference to progfunc to avoid freeing it after execution */ - ucv_get(&progfunc->header); - /* execute program function */ - int return_code = uc_vm_execute(&vm, progfunc, NULL); + int return_code = uc_vm_execute(&vm, program, NULL); /* handle return status */ if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { @@ -89,7 +86,7 @@ int main(int argc, char **argv) } /* release program function */ - ucv_put(&progfunc->header); + uc_program_put(program); /* free VM context */ uc_vm_free(&vm); diff --git a/include/ucode/compiler.h b/include/ucode/compiler.h index df242dc..c112027 100644 --- a/include/ucode/compiler.h +++ b/include/ucode/compiler.h @@ -114,7 +114,7 @@ typedef struct uc_compiler { uc_upvals_t upvals; uc_patchlist_t *patchlist; uc_exprstack_t *exprstack; - uc_value_t *function; + uc_function_t *function; uc_parser_t *parser; uc_program_t *program; size_t scope_depth, current_srcpos, last_insn; @@ -126,7 +126,7 @@ typedef struct { uc_precedence_t precedence; } uc_parse_rule_t; -uc_function_t *uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp); +uc_program_t *uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp); #define uc_compiler_exprstack_push(compiler, token, flags) \ uc_exprstack_t expr = { compiler->exprstack, flags, token }; \ diff --git a/include/ucode/program.h b/include/ucode/program.h index 39131eb..2b2817b 100644 --- a/include/ucode/program.h +++ b/include/ucode/program.h @@ -22,11 +22,36 @@ uc_program_t *uc_program_new(uc_source_t *); -void uc_program_free(uc_program_t *); +static inline uc_program_t * +uc_program_get(uc_program_t *prog) { + return (uc_program_t *)ucv_get(prog ? &prog->header : NULL); +} + +static inline void +uc_program_put(uc_program_t *prog) { + ucv_put(prog ? &prog->header : NULL); +} + +#define uc_program_function_foreach(prog, fn) \ + uc_function_t *fn; \ + for (fn = (uc_function_t *)prog->functions.prev; \ + fn != (uc_function_t *)&prog->functions; \ + fn = (uc_function_t *)fn->progref.prev) + +#define uc_program_function_foreach_safe(prog, fn) \ + uc_function_t *fn, *fn##_tmp; \ + for (fn = (uc_function_t *)prog->functions.prev, \ + fn##_tmp = (uc_function_t *)fn->progref.prev; \ + fn != (uc_function_t *)&prog->functions; \ + fn = fn##_tmp, \ + fn##_tmp = (uc_function_t *)fn##_tmp->progref.prev) + +uc_function_t *uc_program_function_new(uc_program_t *, const char *, size_t); +size_t uc_program_function_id(uc_program_t *, uc_function_t *); +uc_function_t *uc_program_function_load(uc_program_t *, size_t); +size_t uc_program_function_srcpos(uc_function_t *, size_t); +void uc_program_function_free(uc_function_t *); -uc_value_t *uc_program_function_new(uc_program_t *, const char *, size_t); -size_t uc_program_function_id(uc_program_t *, uc_value_t *); -uc_value_t *uc_program_function_load(uc_program_t *, size_t); uc_value_t *uc_program_get_constant(uc_program_t *, size_t); ssize_t uc_program_add_constant(uc_program_t *, uc_value_t *); diff --git a/include/ucode/source.h b/include/ucode/source.h index b05e84b..e0339a4 100644 --- a/include/ucode/source.h +++ b/include/ucode/source.h @@ -37,8 +37,15 @@ uc_source_t *uc_source_new_buffer(const char *name, char *buf, size_t len); size_t uc_source_get_line(uc_source_t *source, size_t *offset); -uc_source_t *uc_source_get(uc_source_t *source); -void uc_source_put(uc_source_t *source); +static inline uc_source_t * +uc_source_get(uc_source_t *source) { + return (uc_source_t *)ucv_get(source ? &source->header : NULL); +} + +static inline void +uc_source_put(uc_source_t *source) { + ucv_put(source ? &source->header : NULL); +} uc_source_type_t uc_source_type_test(uc_source_t *source); diff --git a/include/ucode/types.h b/include/ucode/types.h index cc55150..8e2030a 100644 --- a/include/ucode/types.h +++ b/include/ucode/types.h @@ -36,11 +36,12 @@ typedef enum uc_type { UC_ARRAY, UC_OBJECT, UC_REGEXP, - UC_FUNCTION, UC_CFUNCTION, UC_CLOSURE, UC_UPVALUE, - UC_RESOURCE + UC_RESOURCE, + UC_PROGRAM, + UC_SOURCE } uc_type_t; typedef struct uc_value { @@ -66,9 +67,10 @@ typedef struct { uc_declare_vector(uc_lineinfo_t, uint8_t); typedef struct { + uc_value_t header; char *filename, *runpath, *buffer; FILE *fp; - size_t usecount, off; + size_t off; uc_lineinfo_t lineinfo; } uc_source_t; @@ -106,6 +108,17 @@ typedef struct uc_weakref { struct uc_weakref *next; } uc_weakref_t; +typedef struct uc_function { + uc_weakref_t progref; + bool arrow, vararg, strict; + size_t nargs; + size_t nupvals; + size_t srcpos; + uc_chunk_t chunk; + struct uc_program *program; + char name[]; +} uc_function_t; + typedef struct { uc_value_t header; double dbl; @@ -147,18 +160,6 @@ typedef struct { char source[]; } uc_regexp_t; -typedef struct uc_function { - uc_value_t header; - bool arrow, vararg, strict, root; - size_t nargs; - size_t nupvals; - size_t srcpos; - uc_chunk_t chunk; - struct uc_program *program; - uc_weakref_t progref; - char name[]; -} uc_function_t; - typedef struct uc_upval_tref { uc_value_t header; size_t slot; @@ -202,6 +203,7 @@ uc_declare_vector(uc_resource_types_t, uc_resource_type_t *); /* Program structure definitions */ typedef struct uc_program { + uc_value_t header; uc_value_list_t constants; uc_weakref_t functions; uc_source_t *source; @@ -350,9 +352,6 @@ size_t ucv_object_length(uc_value_t *); : 0); \ entry##key = entry_next##key) -uc_value_t *ucv_function_new(const char *, size_t, uc_program_t *); -size_t ucv_function_srcpos(uc_value_t *, size_t); - uc_value_t *ucv_cfunction_new(const char *, uc_cfn_ptr_t); uc_value_t *ucv_closure_new(uc_vm_t *, uc_function_t *, bool); diff --git a/include/ucode/vallist.h b/include/ucode/vallist.h index f1c1437..f3f1b06 100644 --- a/include/ucode/vallist.h +++ b/include/ucode/vallist.h @@ -37,8 +37,7 @@ typedef enum { TAG_LNUM = 2, TAG_DBL = 3, TAG_STR = 4, - TAG_LSTR = 5, - TAG_FUNC = 6 + TAG_LSTR = 5 } uc_value_type_t; uc_value_t *uc_number_parse(const char *buf, char **end); diff --git a/include/ucode/vm.h b/include/ucode/vm.h index caebb7a..4ba4627 100644 --- a/include/ucode/vm.h +++ b/include/ucode/vm.h @@ -24,6 +24,7 @@ #include "util.h" #include "lexer.h" #include "types.h" +#include "program.h" #define __insns \ __insn(NOOP) \ @@ -139,7 +140,7 @@ uc_exception_type_t uc_vm_call(uc_vm_t *vm, bool mcall, size_t nargs); void __attribute__((format(printf, 3, 0))) uc_vm_raise_exception(uc_vm_t *vm, uc_exception_type_t type, const char *fmt, ...); -uc_vm_status_t uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval); +uc_vm_status_t uc_vm_execute(uc_vm_t *vm, uc_program_t *fn, uc_value_t **retval); uc_value_t *uc_vm_invoke(uc_vm_t *vm, const char *fname, size_t nargs, ...); #endif /* __VM_H_ */ @@ -38,6 +38,7 @@ #include "ucode/vm.h" #include "ucode/lib.h" #include "ucode/source.h" +#include "ucode/program.h" static void format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact) @@ -692,7 +693,6 @@ uc_type(uc_vm_t *vm, size_t nargs) switch (t) { case UC_CFUNCTION: - case UC_FUNCTION: case UC_CLOSURE: return ucv_string_new("function"); @@ -1519,7 +1519,7 @@ static bool uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t **res) { uc_exception_type_t extype; - uc_function_t *function; + uc_program_t *program; uc_value_t *prev_scope; uc_value_t *closure; uc_source_t *source; @@ -1538,21 +1538,23 @@ uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t ** return true; } - function = uc_compile(vm->config, source, &err); + program = uc_compile(vm->config, source, &err); - if (!function) { + uc_source_put(source); + + if (!program) { uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "Unable to compile module '%s':\n%s", path, err); - uc_source_put(source); free(err); return true; } - closure = ucv_closure_new(vm, function, false); + closure = ucv_closure_new(vm, uc_program_entry(program), false); uc_vm_stack_push(vm, closure); + uc_program_put(program); if (scope) { prev_scope = ucv_get(uc_vm_scope_get(vm)); @@ -1567,9 +1569,6 @@ uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t ** if (extype == EXCEPTION_NONE) *res = uc_vm_stack_pop(vm); - uc_source_put(source); - ucv_put(&function->header); - return true; } @@ -81,13 +81,13 @@ static int compile(uc_vm_t *vm, uc_source_t *src, FILE *precompile, bool strip) { uc_value_t *res = NULL; - uc_function_t *entry; + uc_program_t *program; int rc = 0; char *err; - entry = uc_compile(vm->config, src, &err); + program = uc_compile(vm->config, src, &err); - if (!entry) { + if (!program) { fprintf(stderr, "%s", err); free(err); rc = -1; @@ -95,13 +95,12 @@ compile(uc_vm_t *vm, uc_source_t *src, FILE *precompile, bool strip) } if (precompile) { - uc_program_write(entry->program, precompile, !strip); - uc_program_free(entry->program); + uc_program_write(program, precompile, !strip); fclose(precompile); goto out; } - rc = uc_vm_execute(vm, entry, &res); + rc = uc_vm_execute(vm, program, &res); switch (rc) { case STATUS_OK: @@ -122,6 +121,7 @@ compile(uc_vm_t *vm, uc_source_t *src, FILE *precompile, bool strip) } out: + uc_program_put(program); ucv_put(res); return rc; @@ -21,6 +21,7 @@ #include "ucode/program.h" #include "ucode/source.h" #include "ucode/vallist.h" +#include "ucode/chunk.h" uc_program_t * @@ -30,6 +31,9 @@ uc_program_new(uc_source_t *source) prog = xalloc(sizeof(*prog)); + prog->header.type = UC_PROGRAM; + prog->header.refcount = 1; + prog->functions.next = &prog->functions; prog->functions.prev = &prog->functions; @@ -40,80 +44,83 @@ uc_program_new(uc_source_t *source) return prog; } -static inline uc_function_t * -ref_to_function(uc_weakref_t *ref) -{ - return (uc_function_t *)((uintptr_t)ref - offsetof(uc_function_t, progref)); -} - -static inline uc_value_t * -ref_to_uv(uc_weakref_t *ref) -{ - return (uc_value_t *)((uintptr_t)ref - offsetof(uc_function_t, progref)); -} - -void -uc_program_free(uc_program_t *prog) +uc_function_t * +uc_program_function_new(uc_program_t *prog, const char *name, size_t srcpos) { - uc_weakref_t *ref, *tmp; uc_function_t *func; + size_t namelen = 0; - if (!prog) - return; + if (name) + namelen = strlen(name); - for (ref = prog->functions.next, tmp = ref->next; ref != &prog->functions; ref = tmp, tmp = tmp->next) { - func = ref_to_function(ref); - func->program = NULL; - func->progref.next = NULL; - func->progref.prev = NULL; + func = xalloc(sizeof(*func) + namelen + 1); - ucv_put(&func->header); - } - - uc_vallist_free(&prog->constants); - uc_source_put(prog->source); - free(prog); -} - -uc_value_t * -uc_program_function_new(uc_program_t *prog, const char *name, size_t srcpos) -{ - uc_function_t *func; + if (name) + strcpy(func->name, name); - func = (uc_function_t *)ucv_function_new(name, srcpos, prog); - func->root = (prog->functions.next == &prog->functions); + func->nargs = 0; + func->nupvals = 0; + func->srcpos = srcpos; + func->program = prog; + func->vararg = false; + uc_chunk_init(&func->chunk); ucv_ref(&prog->functions, &func->progref); - return &func->header; + return func; } size_t -uc_program_function_id(uc_program_t *prog, uc_value_t *func) +uc_program_function_id(uc_program_t *prog, uc_function_t *func) { - uc_weakref_t *ref; - size_t i; + size_t i = 1; - for (ref = prog->functions.prev, i = 1; ref != &prog->functions; ref = ref->prev, i++) - if (ref_to_uv(ref) == func) + uc_program_function_foreach(prog, fn) { + if (fn == func) return i; + i++; + } + return 0; } -uc_value_t * +uc_function_t * uc_program_function_load(uc_program_t *prog, size_t id) { - uc_weakref_t *ref; - size_t i; + size_t i = 1; - for (ref = prog->functions.prev, i = 1; ref != &prog->functions; ref = ref->prev, i++) - if (i == id) - return ref_to_uv(ref); + uc_program_function_foreach(prog, fn) + if (i++ == id) + return fn; return NULL; } +size_t +uc_program_function_srcpos(uc_function_t *fn, size_t off) +{ + size_t pos; + + if (!fn) + return 0; + + pos = uc_chunk_debug_get_srcpos(&fn->chunk, off); + + return pos ? fn->srcpos + pos : 0; +} + +void +uc_program_function_free(uc_function_t *func) +{ + if (!func) + return; + + ucv_unref(&func->progref); + uc_chunk_free(&func->chunk); + free(func); +} + uc_value_t * uc_program_get_constant(uc_program_t *prog, size_t idx) { @@ -295,8 +302,7 @@ void uc_program_write(uc_program_t *prog, FILE *file, bool debug) { uint32_t flags = 0; - uc_weakref_t *ref; - size_t i; + size_t i = 0; if (debug) flags |= UC_PROGRAM_F_DEBUG; @@ -328,13 +334,15 @@ uc_program_write(uc_program_t *prog, FILE *file, bool debug) write_vallist(&prog->constants, file); /* write program sections */ - for (i = 0, ref = prog->functions.prev; ref != &prog->functions; ref = ref->prev) + uc_program_function_foreach(prog, fn1) { + (void)fn1; i++; + } write_u32(i, file); - for (ref = prog->functions.prev; ref != &prog->functions; ref = ref->prev) - write_function(ref_to_function(ref), file, debug); + uc_program_function_foreach(prog, fn2) + write_function(fn2, file, debug); } static bool @@ -779,7 +787,7 @@ uc_program_load(uc_source_t *input, char **errp) return program; out: - uc_program_free(program); + uc_program_put(program); return NULL; } @@ -790,5 +798,5 @@ uc_program_entry(uc_program_t *program) if (program->functions.prev == &program->functions) return NULL; - return ref_to_function(program->functions.prev); + return (uc_function_t *)program->functions.prev; } @@ -31,13 +31,15 @@ uc_source_new_file(const char *path) return NULL; src = xalloc(ALIGN(sizeof(*src)) + strlen(path) + 1); + + src->header.type = UC_SOURCE; + src->header.refcount = 1; + src->fp = fp; src->buffer = NULL; src->filename = strcpy((char *)src + ALIGN(sizeof(*src)), path); src->runpath = src->filename; - src->usecount = 1; - src->lineinfo.count = 0; src->lineinfo.entries = NULL; @@ -54,12 +56,14 @@ uc_source_new_buffer(const char *name, char *buf, size_t len) return NULL; src = xalloc(ALIGN(sizeof(*src)) + strlen(name) + 1); + + src->header.type = UC_SOURCE; + src->header.refcount = 1; + src->fp = fp; src->buffer = buf; src->filename = strcpy((char *)src + ALIGN(sizeof(*src)), name); - src->usecount = 1; - src->lineinfo.count = 0; src->lineinfo.entries = NULL; @@ -91,38 +95,6 @@ uc_source_get_line(uc_source_t *source, size_t *offset) return 0; } -uc_source_t * -uc_source_get(uc_source_t *source) -{ - if (!source) - return NULL; - - source->usecount++; - - return source; -} - -void -uc_source_put(uc_source_t *source) -{ - if (!source) - return; - - if (source->usecount > 1) { - source->usecount--; - - return; - } - - if (source->runpath != source->filename) - free(source->runpath); - - uc_vector_clear(&source->lineinfo); - fclose(source->fp); - free(source->buffer); - free(source); -} - uc_source_type_t uc_source_type_test(uc_source_t *source) { @@ -51,11 +51,12 @@ ucv_typename(uc_value_t *uv) case UC_ARRAY: return "array"; case UC_OBJECT: return "object"; case UC_REGEXP: return "regexp"; - case UC_FUNCTION: return "function"; case UC_CFUNCTION: return "cfunction"; case UC_CLOSURE: return "closure"; case UC_UPVALUE: return "upvalue"; case UC_RESOURCE: return "resource"; + case UC_PROGRAM: return "program"; + case UC_SOURCE: return "source"; } return "unknown"; @@ -124,6 +125,7 @@ ucv_gc_mark(uc_value_t *uv) uc_object_t *object; uc_array_t *array; uc_resource_t *resource; + uc_program_t *program; struct lh_entry *entry; size_t i; @@ -167,7 +169,7 @@ ucv_gc_mark(uc_value_t *uv) for (i = 0; i < function->nupvals; i++) ucv_gc_mark(&closure->upvals[i]->header); - ucv_gc_mark(&function->header); + ucv_gc_mark(&function->program->header); break; @@ -184,6 +186,14 @@ ucv_gc_mark(uc_value_t *uv) break; + case UC_PROGRAM: + program = (uc_program_t *)uv; + + if (program->source) + ucv_gc_mark(&program->source->header); + + break; + default: break; } @@ -196,7 +206,9 @@ ucv_free(uc_value_t *uv, bool retain) uc_resource_t *resource; uc_function_t *function; uc_closure_t *closure; + uc_program_t *program; uc_upvalref_t *upval; + uc_source_t *source; uc_regexp_t *regexp; uc_object_t *object; uc_array_t *array; @@ -237,19 +249,6 @@ ucv_free(uc_value_t *uv, bool retain) regfree(®exp->regexp); break; - case UC_FUNCTION: - function = (uc_function_t *)uv; - - if (function->program) { - ucv_unref(&function->progref); - - if (function->root) - uc_program_free(function->program); - } - - uc_chunk_free(&function->chunk); - break; - case UC_CLOSURE: closure = (uc_closure_t *)uv; function = closure->function; @@ -258,7 +257,7 @@ ucv_free(uc_value_t *uv, bool retain) for (i = 0; i < function->nupvals; i++) ucv_put_value(&closure->upvals[i]->header, retain); - ucv_put_value(&function->header, retain); + ucv_put_value(&function->program->header, retain); break; case UC_RESOURCE: @@ -274,6 +273,27 @@ ucv_free(uc_value_t *uv, bool retain) upval = (uc_upvalref_t *)uv; ucv_put_value(upval->value, retain); break; + + case UC_PROGRAM: + program = (uc_program_t *)uv; + + uc_program_function_foreach_safe(program, func) + uc_program_function_free(func); + + uc_vallist_free(&program->constants); + ucv_put_value(&program->source->header, retain); + break; + + case UC_SOURCE: + source = (uc_source_t *)uv; + + if (source->runpath != source->filename) + free(source->runpath); + + uc_vector_clear(&source->lineinfo); + fclose(source->fp); + free(source->buffer); + break; } if (!ref || !retain) { @@ -950,48 +970,6 @@ ucv_object_length(uc_value_t *uv) uc_value_t * -ucv_function_new(const char *name, size_t srcpos, uc_program_t *program) -{ - size_t namelen = 0; - uc_function_t *fn; - - if (name) - namelen = strlen(name); - - fn = xalloc(sizeof(*fn) + namelen + 1); - fn->header.type = UC_FUNCTION; - fn->header.refcount = 1; - - if (name) - strcpy(fn->name, name); - - fn->nargs = 0; - fn->nupvals = 0; - fn->srcpos = srcpos; - fn->program = program; - fn->vararg = false; - - uc_chunk_init(&fn->chunk); - - return &fn->header; -} - -size_t -ucv_function_srcpos(uc_value_t *uv, size_t off) -{ - uc_function_t *fn = (uc_function_t *)uv; - size_t pos; - - if (ucv_type(uv) != UC_FUNCTION) - return 0; - - pos = uc_chunk_debug_get_srcpos(&fn->chunk, off); - - return pos ? fn->srcpos + pos : 0; -} - - -uc_value_t * ucv_cfunction_new(const char *name, uc_cfn_ptr_t fptr) { uc_cfunction_t *cfn; @@ -1028,7 +1006,7 @@ ucv_closure_new(uc_vm_t *vm, uc_function_t *function, bool arrow_fn) if (vm) ucv_ref(&vm->values, &closure->ref); - ucv_get(&function->header); + uc_program_get(function->program); return &closure->header; } @@ -1370,9 +1348,10 @@ ucv_to_json(uc_value_t *uv) case UC_CLOSURE: case UC_CFUNCTION: - case UC_FUNCTION: case UC_RESOURCE: case UC_UPVALUE: + case UC_PROGRAM: + case UC_SOURCE: case UC_NULL: return NULL; } @@ -1691,14 +1670,6 @@ ucv_to_stringbuf_formatted(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, size break; - case UC_FUNCTION: - ucv_stringbuf_printf(pb, "%s<function %p>%s", - json ? "\"" : "", - uv, - json ? "\"" : ""); - - break; - case UC_RESOURCE: resource = (uc_resource_t *)uv; restype = resource->type; @@ -1718,6 +1689,20 @@ ucv_to_stringbuf_formatted(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, size json ? "\"" : ""); break; + + case UC_PROGRAM: + ucv_stringbuf_printf(pb, "%s<program %p>%s", + json ? "\"" : "", + uv, + json ? "\"" : ""); + + break; + + case UC_SOURCE: + ucv_stringbuf_printf(pb, "%s<source %p>%s", + json ? "\"" : "", + uv, + json ? "\"" : ""); } ucv_clear_mark(uv); @@ -465,16 +465,6 @@ find_str(uc_value_list_t *list, const char *s, size_t slen) return -1; } -static void -add_func(uc_value_list_t *list, uc_function_t *func) -{ - size_t id = uc_program_function_id(func->program, &func->header); - - assert(id != 0 && TAG_FIT_NV(id)); - - list->index[list->isize++] = (TAG_TYPE)(TAG_FUNC | TAG_SET_NV(id)); -} - ssize_t uc_vallist_add(uc_value_list_t *list, uc_value_t *value) { @@ -525,10 +515,6 @@ uc_vallist_add(uc_value_list_t *list, uc_value_t *value) break; - case UC_FUNCTION: - add_func(list, (uc_function_t *)value); - break; - default: return -1; } @@ -545,15 +531,10 @@ uc_vallist_type(uc_value_list_t *list, size_t idx) return TAG_GET_TYPE(list->index[idx]); } -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - uc_value_t * uc_vallist_get(uc_value_list_t *list, size_t idx) { char str[sizeof(TAG_TYPE)]; - uc_program_t *program; size_t n, len; switch (uc_vallist_type(list, idx)) { @@ -591,11 +572,6 @@ uc_vallist_get(uc_value_list_t *list, size_t idx) return ucv_string_new_length(list->data + TAG_GET_OFFSET(list->index[idx]) + sizeof(uint32_t), len); - case TAG_FUNC: - program = container_of(list, uc_program_t, constants); - - return uc_program_function_load(program, TAG_GET_NV(list->index[idx])); - default: return NULL; } @@ -598,7 +598,7 @@ uc_dump_insn(uc_vm_t *vm, uint8_t *pos, uc_vm_insn_t insn) uc_source_t *source; size_t srcpos; - srcpos = ucv_function_srcpos(&frame->closure->function->header, pos - chunk->entries); + srcpos = uc_program_function_srcpos(frame->closure->function, pos - chunk->entries); source = uc_vm_frame_source(frame); if (last_srcpos == 0 || last_source != source || srcpos != last_srcpos) { @@ -828,7 +828,7 @@ uc_vm_capture_stacktrace(uc_vm_t *vm, size_t i) source = function->program->source; off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1; - srcpos = ucv_function_srcpos(&function->header, off); + srcpos = uc_program_function_srcpos(function, off); ucv_object_add(entry, "filename", ucv_string_new(source->filename)); ucv_object_add(entry, "line", ucv_int64_new(uc_source_get_line(source, &srcpos))); @@ -883,7 +883,7 @@ uc_vm_get_error_context(uc_vm_t *vm) return NULL; chunk = uc_vm_frame_chunk(frame); - offset = ucv_function_srcpos(&frame->closure->function->header, (frame->ip - chunk->entries) - 1); + offset = uc_program_function_srcpos(frame->closure->function, (frame->ip - chunk->entries) - 1); stacktrace = uc_vm_capture_stacktrace(vm, i); buf = ucv_stringbuf_new(); @@ -1136,8 +1136,7 @@ static void uc_vm_insn_load_closure(uc_vm_t *vm, uc_vm_insn_t insn) { uc_callframe_t *frame = uc_vm_current_frame(vm); - uc_value_t *fno = uc_program_get_constant(uc_vm_current_program(vm), vm->arg.u32); - uc_function_t *function = (uc_function_t *)fno; + uc_function_t *function = uc_program_function_load(uc_vm_current_program(vm), vm->arg.u32); uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, function, insn == I_ARFN); volatile int32_t uv; size_t i; @@ -2559,8 +2558,9 @@ uc_vm_execute_chunk(uc_vm_t *vm) } uc_vm_status_t -uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval) +uc_vm_execute(uc_vm_t *vm, uc_program_t *program, uc_value_t **retval) { + uc_function_t *fn = uc_program_entry(program); uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, fn, false); uc_vm_status_t status; uc_callframe_t *frame; @@ -2615,8 +2615,6 @@ uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval) break; } - ucv_put(&fn->header); - return status; } |