2022-01-20 21:45:09 +00:00
|
|
|
#ifndef APFL_VALUE_H
|
|
|
|
|
#define APFL_VALUE_H
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
#include <stdbool.h>
|
2022-01-20 21:45:09 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include "apfl.h"
|
|
|
|
|
|
2022-07-11 19:41:05 +00:00
|
|
|
#include "bytecode.h"
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
#include "gc.h"
|
|
|
|
|
|
|
|
|
|
#include "hashmap.h"
|
|
|
|
|
|
2022-02-10 20:55:40 +00:00
|
|
|
enum value_type {
|
|
|
|
|
VALUE_NIL,
|
|
|
|
|
VALUE_BOOLEAN,
|
|
|
|
|
VALUE_NUMBER,
|
|
|
|
|
VALUE_STRING,
|
2022-04-23 20:14:42 +00:00
|
|
|
VALUE_CONST_STRING,
|
2022-02-10 20:55:40 +00:00
|
|
|
VALUE_LIST,
|
|
|
|
|
VALUE_DICT,
|
2022-07-11 19:41:05 +00:00
|
|
|
VALUE_FUNC,
|
|
|
|
|
VALUE_CFUNC,
|
|
|
|
|
VALUE_USERDATA,
|
2023-01-29 15:46:00 +00:00
|
|
|
VALUE_NATIVE_OBJECT,
|
2022-01-20 21:45:09 +00:00
|
|
|
};
|
|
|
|
|
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
struct list_header {
|
|
|
|
|
struct apfl_value *items;
|
|
|
|
|
size_t len;
|
|
|
|
|
size_t cap;
|
|
|
|
|
bool copy_on_write;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct dict_header {
|
|
|
|
|
struct apfl_hashmap map;
|
|
|
|
|
bool copy_on_write;
|
|
|
|
|
};
|
2022-01-20 21:45:09 +00:00
|
|
|
|
2022-08-12 22:50:26 +00:00
|
|
|
struct subfunction {
|
|
|
|
|
struct matcher *matcher;
|
2022-07-11 19:41:05 +00:00
|
|
|
struct instruction_list *body;
|
2022-08-12 22:50:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct function {
|
|
|
|
|
struct subfunction *subfunctions;
|
|
|
|
|
size_t subfunctions_len;
|
|
|
|
|
size_t subfunctions_cap;
|
2022-07-11 19:41:05 +00:00
|
|
|
struct scope *scope;
|
2023-01-24 20:59:54 +00:00
|
|
|
struct apfl_string *name;
|
2023-01-26 20:22:34 +00:00
|
|
|
int line_defined;
|
2023-01-30 21:50:01 +00:00
|
|
|
struct apfl_string *filename;
|
2022-07-11 19:41:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct cfunction {
|
|
|
|
|
apfl_cfunc func;
|
|
|
|
|
struct apfl_value **slots;
|
|
|
|
|
size_t slots_len;
|
2023-01-24 20:59:54 +00:00
|
|
|
struct apfl_string *name;
|
2022-07-11 19:41:05 +00:00
|
|
|
};
|
|
|
|
|
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
typedef struct dict_header *apfl_dict;
|
2022-01-20 21:45:09 +00:00
|
|
|
|
2023-01-29 15:46:00 +00:00
|
|
|
struct native_object {
|
|
|
|
|
void *memory;
|
|
|
|
|
const struct apfl_native_object_type *type;
|
|
|
|
|
};
|
|
|
|
|
|
2022-01-20 21:45:09 +00:00
|
|
|
struct apfl_value {
|
2022-02-10 20:55:40 +00:00
|
|
|
enum value_type type;
|
2022-01-20 21:45:09 +00:00
|
|
|
union {
|
|
|
|
|
bool boolean;
|
|
|
|
|
apfl_number number;
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
struct apfl_string *string;
|
2022-04-23 20:14:42 +00:00
|
|
|
struct apfl_string_view const_string;
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
struct list_header *list;
|
|
|
|
|
struct dict_header *dict;
|
2022-07-11 19:41:05 +00:00
|
|
|
struct function *func;
|
|
|
|
|
struct cfunction *cfunc;
|
|
|
|
|
void *userdata;
|
2023-01-29 15:46:00 +00:00
|
|
|
struct native_object *native_object;
|
2022-01-20 21:45:09 +00:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
enum apfl_value_type apfl_value_type_to_abstract_type(enum value_type);
|
|
|
|
|
|
|
|
|
|
#define VALUE_IS_A(v, t) (apfl_value_type_to_abstract_type((v).type) == (t))
|
2022-01-20 21:45:09 +00:00
|
|
|
|
|
|
|
|
bool apfl_value_eq(const struct apfl_value, const struct apfl_value);
|
|
|
|
|
struct apfl_value apfl_value_move(struct apfl_value *src);
|
2023-02-10 20:38:54 +00:00
|
|
|
bool apfl_value_format(struct apfl_value, struct apfl_io_writer);
|
|
|
|
|
bool apfl_value_print(struct apfl_value, struct apfl_io_writer);
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
apfl_hash apfl_value_hash(const struct apfl_value);
|
2022-01-20 21:45:09 +00:00
|
|
|
|
2022-11-20 12:47:38 +00:00
|
|
|
enum comparison_result {
|
|
|
|
|
CMP_LT,
|
|
|
|
|
CMP_EQ,
|
|
|
|
|
CMP_GT,
|
|
|
|
|
CMP_UNCOMPARABLE,
|
|
|
|
|
CMP_INCOMPATIBLE_TYPES,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum comparison_result apfl_value_cmp(const struct apfl_value a, const struct apfl_value b);
|
|
|
|
|
|
2022-02-10 20:51:19 +00:00
|
|
|
enum get_item_result {
|
|
|
|
|
GET_ITEM_OK,
|
|
|
|
|
GET_ITEM_KEY_DOESNT_EXIST,
|
|
|
|
|
GET_ITEM_NOT_A_CONTAINER,
|
|
|
|
|
GET_ITEM_WRONG_KEY_TYPE,
|
2022-01-20 21:45:09 +00:00
|
|
|
};
|
|
|
|
|
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
enum get_item_result apfl_value_get_item(struct apfl_value container, struct apfl_value key, struct apfl_value *out);
|
|
|
|
|
|
|
|
|
|
// Set the Copy On Write flag of a value (if it's a value with such a flag).
|
|
|
|
|
// Returns the same value again.
|
|
|
|
|
struct apfl_value apfl_value_set_cow_flag(struct apfl_value);
|
|
|
|
|
|
|
|
|
|
struct list_header *apfl_list_new(struct gc *, size_t initial_cap);
|
|
|
|
|
|
|
|
|
|
size_t apfl_list_len(struct list_header *);
|
|
|
|
|
void apfl_list_deinit(struct apfl_allocator, struct list_header *);
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
apfl_list_splice(
|
|
|
|
|
struct gc *gc,
|
|
|
|
|
struct list_header **dst_ptr,
|
|
|
|
|
size_t cut_start,
|
|
|
|
|
size_t cut_len,
|
|
|
|
|
const struct apfl_value *other,
|
|
|
|
|
size_t other_len
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
struct dict_header *apfl_dict_new(struct gc *);
|
|
|
|
|
bool apfl_dict_set_raw(
|
|
|
|
|
struct gc *gc,
|
|
|
|
|
struct dict_header **_dict,
|
|
|
|
|
struct apfl_value k,
|
|
|
|
|
struct apfl_value v
|
|
|
|
|
);
|
2022-07-12 20:13:07 +00:00
|
|
|
size_t apfl_dict_len(struct dict_header *);
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
void apfl_dict_deinit(struct dict_header *);
|
|
|
|
|
|
2023-01-30 21:50:01 +00:00
|
|
|
struct function *apfl_func_new(
|
|
|
|
|
struct gc *,
|
|
|
|
|
size_t cap,
|
|
|
|
|
struct scope *,
|
|
|
|
|
int line_defined,
|
|
|
|
|
struct apfl_string *filename
|
|
|
|
|
);
|
2022-08-12 22:50:26 +00:00
|
|
|
bool apfl_func_add_subfunc(struct function *, struct instruction_list *, struct matcher *);
|
2023-01-24 20:59:54 +00:00
|
|
|
bool apfl_func_get_name(struct function *, struct apfl_string_view *name);
|
|
|
|
|
void apfl_func_set_name(struct function *, struct apfl_string *name);
|
2022-07-11 19:41:05 +00:00
|
|
|
void apfl_function_deinit(struct apfl_allocator, struct function *);
|
|
|
|
|
|
|
|
|
|
struct cfunction *apfl_cfunc_new(struct gc *, apfl_cfunc, size_t nslots);
|
|
|
|
|
void apfl_cfunction_deinit(struct apfl_allocator, struct cfunction *);
|
|
|
|
|
|
2023-01-29 15:46:00 +00:00
|
|
|
struct native_object *apfl_native_object_new(struct gc *, const struct apfl_native_object_type *);
|
|
|
|
|
void apfl_native_object_deinit(struct apfl_allocator, struct native_object *);
|
|
|
|
|
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
// Functions for garbage collection
|
|
|
|
|
struct gc_object *apfl_value_get_gc_object(struct apfl_value);
|
2022-11-19 21:06:23 +00:00
|
|
|
void apfl_value_visit_gc_object(struct apfl_value value, gc_visitor cb, void *opaque);
|
2022-11-20 15:26:38 +00:00
|
|
|
bool apfl_value_add_as_tmproot(struct gc *, struct apfl_value);
|
Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).
The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.
The tri-color abstraction was chosen for two reasons:
- We don't have to maintain a list of objects that need to be marked, we
can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
we only do a stop-the-world collection).
This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.
As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 20:24:22 +00:00
|
|
|
void apfl_gc_list_traverse(struct list_header *, gc_visitor, void *);
|
|
|
|
|
void apfl_gc_dict_traverse(struct dict_header *, gc_visitor, void *);
|
2022-07-11 19:41:05 +00:00
|
|
|
void apfl_gc_func_traverse(struct function*, gc_visitor, void *);
|
|
|
|
|
void apfl_gc_cfunc_traverse(struct cfunction*, gc_visitor, void *);
|
2022-01-20 21:45:09 +00:00
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif
|