summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-02-06 00:12:48 +0100
committerJo-Philipp Wich <jo@mein.io>2022-02-07 00:04:35 +0100
commit3a49192f3a1e8a5d348cdbfccd0a16d74ba61e3d (patch)
tree6d8a4b620b362ab4f707678a5b626a85e1531c0b
parent5bd764a35aeaf50b54957bfa94ba94198514baf0 (diff)
treewide: rework function memory model
- Instead of treating individual program functions as managed ucode types, demote uc_function_t values to pointers into a uc_program_t entity - Promote uc_program_t to a managed type - Let uc_closure_t claim references to the owning program of the enclosed uc_function_t - Redefine public APIs uc_compile() and uc_vm_execute() APIs to return and expect an uc_program_t object respectively - Remove vallist indirection for function loading and let the compiler emit the function id directly when producing function construction code Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--compiler.c49
-rw-r--r--examples/exception-handler.c10
-rw-r--r--examples/execute-file.c6
-rw-r--r--examples/execute-string.c13
-rw-r--r--examples/native-function.c13
-rw-r--r--examples/state-reset.c15
-rw-r--r--examples/state-reuse.c15
-rw-r--r--include/ucode/compiler.h4
-rw-r--r--include/ucode/program.h33
-rw-r--r--include/ucode/types.h31
-rw-r--r--include/ucode/vallist.h3
-rw-r--r--include/ucode/vm.h3
-rw-r--r--lib.c17
-rw-r--r--main.c12
-rw-r--r--program.c118
-rw-r--r--types.c90
-rw-r--r--vallist.c24
-rw-r--r--vm.c14
18 files changed, 214 insertions, 256 deletions
diff --git a/compiler.c b/compiler.c
index c29d80a..3582386 100644
--- a/compiler.c
+++ b/compiler.c
@@ -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/types.h b/include/ucode/types.h
index cc55150..ff87ca7 100644
--- a/include/ucode/types.h
+++ b/include/ucode/types.h
@@ -36,11 +36,11 @@ 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_type_t;
typedef struct uc_value {
@@ -106,6 +106,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 +158,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 +201,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 +350,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_ */
diff --git a/lib.c b/lib.c
index 5ad08e7..aaa3eac 100644
--- a/lib.c
+++ b/lib.c
@@ -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;
}
diff --git a/main.c b/main.c
index 4b6738d..f9ce6f0 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/program.c b/program.c
index de7e747..1810b06 100644
--- a/program.c
+++ b/program.c
@@ -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;
}
diff --git a/types.c b/types.c
index dac0efb..b096b71 100644
--- a/types.c
+++ b/types.c
@@ -51,11 +51,11 @@ 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";
}
return "unknown";
@@ -167,7 +167,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;
@@ -196,6 +196,7 @@ 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_regexp_t *regexp;
uc_object_t *object;
@@ -237,19 +238,6 @@ ucv_free(uc_value_t *uv, bool retain)
regfree(&regexp->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 +246,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 +262,16 @@ 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);
+ uc_source_put(program->source);
+ break;
}
if (!ref || !retain) {
@@ -950,48 +948,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 +984,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 +1326,9 @@ 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_NULL:
return NULL;
}
@@ -1691,14 +1647,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 +1666,12 @@ 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 ? "\"" : "");
}
ucv_clear_mark(uv);
diff --git a/vallist.c b/vallist.c
index 777529a..2cea983 100644
--- a/vallist.c
+++ b/vallist.c
@@ -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;
}
diff --git a/vm.c b/vm.c
index 3e027bf..e0cac6f 100644
--- a/vm.c
+++ b/vm.c
@@ -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;
}