mirror of
https://github.com/janet-lang/janet
synced 2025-01-12 00:20:26 +00:00
Add janet_vm_save and janet_vm_load.
This lets a user multiplex multiple Janet VMs on a single thread or process if they are willing to implement context switching themselves.
This commit is contained in:
parent
230b734663
commit
1ef6db16ed
1
Makefile
1
Makefile
@ -113,6 +113,7 @@ JANET_CORE_SOURCES=src/core/abstract.c \
|
||||
src/core/regalloc.c \
|
||||
src/core/run.c \
|
||||
src/core/specials.c \
|
||||
src/core/state.c \
|
||||
src/core/string.c \
|
||||
src/core/strtod.c \
|
||||
src/core/struct.c \
|
||||
|
@ -127,6 +127,7 @@ core_src = [
|
||||
'src/core/regalloc.c',
|
||||
'src/core/run.c',
|
||||
'src/core/specials.c',
|
||||
'src/core/state.c',
|
||||
'src/core/string.c',
|
||||
'src/core/strtod.c',
|
||||
'src/core/struct.c',
|
||||
|
@ -3681,6 +3681,7 @@
|
||||
"src/core/regalloc.c"
|
||||
"src/core/run.c"
|
||||
"src/core/specials.c"
|
||||
"src/core/state.c"
|
||||
"src/core/string.c"
|
||||
"src/core/strtod.c"
|
||||
"src/core/struct.c"
|
||||
|
@ -35,7 +35,7 @@ JanetArray *janet_array(int32_t capacity) {
|
||||
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
|
||||
Janet *data = NULL;
|
||||
if (capacity > 0) {
|
||||
janet_vm_next_collection += capacity * sizeof(Janet);
|
||||
janet_vm.next_collection += capacity * sizeof(Janet);
|
||||
data = (Janet *) janet_malloc(sizeof(Janet) * (size_t) capacity);
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
@ -72,7 +72,7 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth) {
|
||||
if (NULL == newData) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_next_collection += (capacity - array->capacity) * sizeof(Janet);
|
||||
janet_vm.next_collection += (capacity - array->capacity) * sizeof(Janet);
|
||||
array->data = newData;
|
||||
array->capacity = capacity;
|
||||
}
|
||||
|
@ -51,15 +51,15 @@ JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
|
||||
}
|
||||
|
||||
void janet_signalv(JanetSignal sig, Janet message) {
|
||||
if (janet_vm_return_reg != NULL) {
|
||||
*janet_vm_return_reg = message;
|
||||
if (NULL != janet_vm_fiber) {
|
||||
janet_vm_fiber->flags |= JANET_FIBER_DID_LONGJUMP;
|
||||
if (janet_vm.return_reg != NULL) {
|
||||
*janet_vm.return_reg = message;
|
||||
if (NULL != janet_vm.fiber) {
|
||||
janet_vm.fiber->flags |= JANET_FIBER_DID_LONGJUMP;
|
||||
}
|
||||
#if defined(JANET_BSD) || defined(JANET_APPLE)
|
||||
_longjmp(*janet_vm_jmp_buf, sig);
|
||||
_longjmp(*janet_vm.signal_buf, sig);
|
||||
#else
|
||||
longjmp(*janet_vm_jmp_buf, sig);
|
||||
longjmp(*janet_vm.signal_buf, sig);
|
||||
#endif
|
||||
} else {
|
||||
const char *str = (const char *)janet_formatc("janet top level signal - %v\n", message);
|
||||
@ -358,26 +358,26 @@ JanetRange janet_getslice(int32_t argc, const Janet *argv) {
|
||||
}
|
||||
|
||||
Janet janet_dyn(const char *name) {
|
||||
if (!janet_vm_fiber) {
|
||||
if (!janet_vm_top_dyns) return janet_wrap_nil();
|
||||
return janet_table_get(janet_vm_top_dyns, janet_ckeywordv(name));
|
||||
if (!janet_vm.fiber) {
|
||||
if (!janet_vm.top_dyns) return janet_wrap_nil();
|
||||
return janet_table_get(janet_vm.top_dyns, janet_ckeywordv(name));
|
||||
}
|
||||
if (janet_vm_fiber->env) {
|
||||
return janet_table_get(janet_vm_fiber->env, janet_ckeywordv(name));
|
||||
if (janet_vm.fiber->env) {
|
||||
return janet_table_get(janet_vm.fiber->env, janet_ckeywordv(name));
|
||||
} else {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
}
|
||||
|
||||
void janet_setdyn(const char *name, Janet value) {
|
||||
if (!janet_vm_fiber) {
|
||||
if (!janet_vm_top_dyns) janet_vm_top_dyns = janet_table(10);
|
||||
janet_table_put(janet_vm_top_dyns, janet_ckeywordv(name), value);
|
||||
if (!janet_vm.fiber) {
|
||||
if (!janet_vm.top_dyns) janet_vm.top_dyns = janet_table(10);
|
||||
janet_table_put(janet_vm.top_dyns, janet_ckeywordv(name), value);
|
||||
} else {
|
||||
if (!janet_vm_fiber->env) {
|
||||
janet_vm_fiber->env = janet_table(1);
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(1);
|
||||
}
|
||||
janet_table_put(janet_vm_fiber->env, janet_ckeywordv(name), value);
|
||||
janet_table_put(janet_vm.fiber->env, janet_ckeywordv(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -944,10 +944,10 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
|
||||
/* C Function for compiling */
|
||||
static Janet cfun(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 4);
|
||||
JanetTable *env = argc > 1 ? janet_gettable(argv, 1) : janet_vm_fiber->env;
|
||||
JanetTable *env = argc > 1 ? janet_gettable(argv, 1) : janet_vm.fiber->env;
|
||||
if (NULL == env) {
|
||||
env = janet_table(0);
|
||||
janet_vm_fiber->env = env;
|
||||
janet_vm.fiber->env = env;
|
||||
}
|
||||
const uint8_t *source = NULL;
|
||||
if (argc >= 3) {
|
||||
|
@ -269,8 +269,8 @@ static Janet janet_core_expand_path(int32_t argc, Janet *argv) {
|
||||
static Janet janet_core_dyn(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
Janet value;
|
||||
if (janet_vm_fiber->env) {
|
||||
value = janet_table_get(janet_vm_fiber->env, argv[0]);
|
||||
if (janet_vm.fiber->env) {
|
||||
value = janet_table_get(janet_vm.fiber->env, argv[0]);
|
||||
} else {
|
||||
value = janet_wrap_nil();
|
||||
}
|
||||
@ -282,10 +282,10 @@ static Janet janet_core_dyn(int32_t argc, Janet *argv) {
|
||||
|
||||
static Janet janet_core_setdyn(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 2);
|
||||
if (!janet_vm_fiber->env) {
|
||||
janet_vm_fiber->env = janet_table(2);
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(2);
|
||||
}
|
||||
janet_table_put(janet_vm_fiber->env, argv[0], argv[1]);
|
||||
janet_table_put(janet_vm.fiber->env, argv[0], argv[1]);
|
||||
return argv[1];
|
||||
}
|
||||
|
||||
@ -428,14 +428,14 @@ static Janet janet_core_gcsetinterval(int32_t argc, Janet *argv) {
|
||||
janet_panic("interval too large");
|
||||
}
|
||||
#endif
|
||||
janet_vm_gc_interval = s;
|
||||
janet_vm.gc_interval = s;
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
static Janet janet_core_gcinterval(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_number((double) janet_vm_gc_interval);
|
||||
return janet_wrap_number((double) janet_vm.gc_interval);
|
||||
}
|
||||
|
||||
static Janet janet_core_type(int32_t argc, Janet *argv) {
|
||||
@ -1215,8 +1215,8 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
||||
|
||||
JanetTable *janet_core_env(JanetTable *replacements) {
|
||||
/* Memoize core env, ignoring replacements the second time around. */
|
||||
if (NULL != janet_vm_core_env) {
|
||||
return janet_vm_core_env;
|
||||
if (NULL != janet_vm.core_env) {
|
||||
return janet_vm.core_env;
|
||||
}
|
||||
|
||||
JanetTable *dict = janet_core_lookup_table(replacements);
|
||||
@ -1232,7 +1232,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
||||
/* Memoize */
|
||||
janet_gcroot(marsh_out);
|
||||
JanetTable *env = janet_unwrap_table(marsh_out);
|
||||
janet_vm_core_env = env;
|
||||
janet_vm.core_env = env;
|
||||
|
||||
/* Invert image dict manually here. We can't do this in boot.janet as it
|
||||
* breaks deterministic builds */
|
||||
@ -1265,7 +1265,7 @@ JanetTable *janet_core_lookup_table(JanetTable *replacements) {
|
||||
if (!janet_checktype(kv.key, JANET_NIL)) {
|
||||
janet_table_put(dict, kv.key, kv.value);
|
||||
if (janet_checktype(kv.value, JANET_CFUNCTION)) {
|
||||
janet_table_put(janet_vm_registry, kv.value, kv.key);
|
||||
janet_table_put(janet_vm.registry, kv.value, kv.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ void janet_debug_find(
|
||||
JanetFuncDef **def_out, int32_t *pc_out,
|
||||
const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) {
|
||||
/* Scan the heap for right func def */
|
||||
JanetGCObject *current = janet_vm_blocks;
|
||||
JanetGCObject *current = janet_vm.blocks;
|
||||
/* Keep track of the best source mapping we have seen so far */
|
||||
int32_t besti = -1;
|
||||
int32_t best_line = -1;
|
||||
@ -144,7 +144,7 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
} else {
|
||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||
if (cfun) {
|
||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||
Janet name = janet_table_get(janet_vm.registry, janet_wrap_cfunction(cfun));
|
||||
if (!janet_checktype(name, JANET_NIL))
|
||||
janet_eprintf(" %s", (const char *)janet_to_string(name));
|
||||
else
|
||||
@ -252,7 +252,7 @@ static Janet doframe(JanetStackFrame *frame) {
|
||||
} else {
|
||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||
if (cfun) {
|
||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||
Janet name = janet_table_get(janet_vm.registry, janet_wrap_cfunction(cfun));
|
||||
if (!janet_checktype(name, JANET_NIL)) {
|
||||
janet_table_put(t, janet_ckeywordv("name"), name);
|
||||
}
|
||||
|
300
src/core/ev.c
300
src/core/ev.c
@ -56,12 +56,6 @@
|
||||
#endif
|
||||
|
||||
/* Ring buffer for storing a list of fibers */
|
||||
typedef struct {
|
||||
int32_t capacity;
|
||||
int32_t head;
|
||||
int32_t tail;
|
||||
void *data;
|
||||
} JanetQueue;
|
||||
|
||||
typedef struct {
|
||||
JanetFiber *fiber;
|
||||
@ -143,31 +137,9 @@ struct JanetTask {
|
||||
JanetSignal sig;
|
||||
};
|
||||
|
||||
/* Min priority queue of timestamps for timeouts. */
|
||||
typedef int64_t JanetTimestamp;
|
||||
typedef struct JanetTimeout JanetTimeout;
|
||||
struct JanetTimeout {
|
||||
JanetTimestamp when;
|
||||
JanetFiber *fiber;
|
||||
JanetFiber *curr_fiber;
|
||||
uint32_t sched_id;
|
||||
int is_error;
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
static void janet_unlisten(JanetListenerState *state);
|
||||
|
||||
/* Global data */
|
||||
JANET_THREAD_LOCAL size_t janet_vm_tq_count = 0;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_tq_capacity = 0;
|
||||
JANET_THREAD_LOCAL JanetQueue janet_vm_spawn;
|
||||
JANET_THREAD_LOCAL JanetTimeout *janet_vm_tq = NULL;
|
||||
JANET_THREAD_LOCAL JanetRNG janet_vm_ev_rng;
|
||||
JANET_THREAD_LOCAL JanetListenerState **janet_vm_listeners = NULL;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_listener_count = 0;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_listener_cap = 0;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_extra_listeners = 0;
|
||||
|
||||
/* Get current timestamp (millisecond precision) */
|
||||
static JanetTimestamp ts_now(void);
|
||||
|
||||
@ -180,58 +152,58 @@ static JanetTimestamp ts_delta(JanetTimestamp ts, double delta) {
|
||||
/* Look at the next timeout value without
|
||||
* removing it. */
|
||||
static int peek_timeout(JanetTimeout *out) {
|
||||
if (janet_vm_tq_count == 0) return 0;
|
||||
*out = janet_vm_tq[0];
|
||||
if (janet_vm.tq_count == 0) return 0;
|
||||
*out = janet_vm.tq[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove the next timeout from the priority queue */
|
||||
static void pop_timeout(size_t index) {
|
||||
if (janet_vm_tq_count <= index) return;
|
||||
janet_vm_tq[index] = janet_vm_tq[--janet_vm_tq_count];
|
||||
if (janet_vm.tq_count <= index) return;
|
||||
janet_vm.tq[index] = janet_vm.tq[--janet_vm.tq_count];
|
||||
for (;;) {
|
||||
size_t left = (index << 1) + 1;
|
||||
size_t right = left + 1;
|
||||
size_t smallest = index;
|
||||
if (left < janet_vm_tq_count &&
|
||||
(janet_vm_tq[left].when < janet_vm_tq[smallest].when))
|
||||
if (left < janet_vm.tq_count &&
|
||||
(janet_vm.tq[left].when < janet_vm.tq[smallest].when))
|
||||
smallest = left;
|
||||
if (right < janet_vm_tq_count &&
|
||||
(janet_vm_tq[right].when < janet_vm_tq[smallest].when))
|
||||
if (right < janet_vm.tq_count &&
|
||||
(janet_vm.tq[right].when < janet_vm.tq[smallest].when))
|
||||
smallest = right;
|
||||
if (smallest == index) return;
|
||||
JanetTimeout temp = janet_vm_tq[index];
|
||||
janet_vm_tq[index] = janet_vm_tq[smallest];
|
||||
janet_vm_tq[smallest] = temp;
|
||||
JanetTimeout temp = janet_vm.tq[index];
|
||||
janet_vm.tq[index] = janet_vm.tq[smallest];
|
||||
janet_vm.tq[smallest] = temp;
|
||||
index = smallest;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a timeout to the timeout min heap */
|
||||
static void add_timeout(JanetTimeout to) {
|
||||
size_t oldcount = janet_vm_tq_count;
|
||||
size_t oldcount = janet_vm.tq_count;
|
||||
size_t newcount = oldcount + 1;
|
||||
if (newcount > janet_vm_tq_capacity) {
|
||||
if (newcount > janet_vm.tq_capacity) {
|
||||
size_t newcap = 2 * newcount;
|
||||
JanetTimeout *tq = janet_realloc(janet_vm_tq, newcap * sizeof(JanetTimeout));
|
||||
JanetTimeout *tq = janet_realloc(janet_vm.tq, newcap * sizeof(JanetTimeout));
|
||||
if (NULL == tq) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_tq = tq;
|
||||
janet_vm_tq_capacity = newcap;
|
||||
janet_vm.tq = tq;
|
||||
janet_vm.tq_capacity = newcap;
|
||||
}
|
||||
/* Append */
|
||||
janet_vm_tq_count = (int32_t) newcount;
|
||||
janet_vm_tq[oldcount] = to;
|
||||
janet_vm.tq_count = (int32_t) newcount;
|
||||
janet_vm.tq[oldcount] = to;
|
||||
/* Heapify */
|
||||
size_t index = oldcount;
|
||||
while (index > 0) {
|
||||
size_t parent = (index - 1) >> 1;
|
||||
if (janet_vm_tq[parent].when <= janet_vm_tq[index].when) break;
|
||||
if (janet_vm.tq[parent].when <= janet_vm.tq[index].when) break;
|
||||
/* Swap */
|
||||
JanetTimeout tmp = janet_vm_tq[index];
|
||||
janet_vm_tq[index] = janet_vm_tq[parent];
|
||||
janet_vm_tq[parent] = tmp;
|
||||
JanetTimeout tmp = janet_vm.tq[index];
|
||||
janet_vm.tq[index] = janet_vm.tq[parent];
|
||||
janet_vm.tq[parent] = tmp;
|
||||
/* Next */
|
||||
index = parent;
|
||||
}
|
||||
@ -242,7 +214,7 @@ static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener
|
||||
if (stream->_mask & mask) {
|
||||
janet_panic("cannot listen for duplicate event on stream");
|
||||
}
|
||||
if (janet_vm_root_fiber->waiting != NULL) {
|
||||
if (janet_vm.root_fiber->waiting != NULL) {
|
||||
janet_panic("current fiber is already waiting for event");
|
||||
}
|
||||
if (size < sizeof(JanetListenerState))
|
||||
@ -252,8 +224,8 @@ static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
state->machine = behavior;
|
||||
state->fiber = janet_vm_root_fiber;
|
||||
janet_vm_root_fiber->waiting = state;
|
||||
state->fiber = janet_vm.root_fiber;
|
||||
janet_vm.root_fiber->waiting = state;
|
||||
state->stream = stream;
|
||||
state->_mask = mask;
|
||||
stream->_mask |= mask;
|
||||
@ -261,17 +233,17 @@ static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener
|
||||
stream->state = state;
|
||||
|
||||
/* Keep track of a listener for GC purposes */
|
||||
int resize = janet_vm_listener_cap == janet_vm_listener_count;
|
||||
int resize = janet_vm.listener_cap == janet_vm.listener_count;
|
||||
if (resize) {
|
||||
size_t newcap = janet_vm_listener_count ? janet_vm_listener_cap * 2 : 16;
|
||||
janet_vm_listeners = janet_realloc(janet_vm_listeners, newcap * sizeof(JanetListenerState *));
|
||||
if (NULL == janet_vm_listeners) {
|
||||
size_t newcap = janet_vm.listener_count ? janet_vm.listener_cap * 2 : 16;
|
||||
janet_vm.listeners = janet_realloc(janet_vm.listeners, newcap * sizeof(JanetListenerState *));
|
||||
if (NULL == janet_vm.listeners) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_listener_cap = newcap;
|
||||
janet_vm.listener_cap = newcap;
|
||||
}
|
||||
size_t index = janet_vm_listener_count++;
|
||||
janet_vm_listeners[index] = state;
|
||||
size_t index = janet_vm.listener_count++;
|
||||
janet_vm.listeners[index] = state;
|
||||
state->_index = index;
|
||||
|
||||
/* Emit INIT event for convenience */
|
||||
@ -299,8 +271,8 @@ static void janet_unlisten_impl(JanetListenerState *state) {
|
||||
}
|
||||
/* Untrack a listener for gc purposes */
|
||||
size_t index = state->_index;
|
||||
janet_vm_listeners[index] = janet_vm_listeners[--janet_vm_listener_count];
|
||||
janet_vm_listeners[index]->_index = index;
|
||||
janet_vm.listeners[index] = janet_vm.listeners[--janet_vm.listener_count];
|
||||
janet_vm.listeners[index]->_index = index;
|
||||
janet_free(state);
|
||||
}
|
||||
|
||||
@ -459,7 +431,7 @@ void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig) {
|
||||
fiber->flags |= JANET_FIBER_FLAG_SCHEDULED;
|
||||
fiber->sched_id++;
|
||||
JanetTask t = { fiber, value, sig };
|
||||
janet_q_push(&janet_vm_spawn, &t, sizeof(t));
|
||||
janet_q_push(&janet_vm.spawn, &t, sizeof(t));
|
||||
}
|
||||
|
||||
void janet_cancel(JanetFiber *fiber, Janet value) {
|
||||
@ -482,34 +454,34 @@ void janet_fiber_did_resume(JanetFiber *fiber) {
|
||||
void janet_ev_mark(void) {
|
||||
|
||||
/* Pending tasks */
|
||||
JanetTask *tasks = janet_vm_spawn.data;
|
||||
if (janet_vm_spawn.head <= janet_vm_spawn.tail) {
|
||||
for (int32_t i = janet_vm_spawn.head; i < janet_vm_spawn.tail; i++) {
|
||||
JanetTask *tasks = janet_vm.spawn.data;
|
||||
if (janet_vm.spawn.head <= janet_vm.spawn.tail) {
|
||||
for (int32_t i = janet_vm.spawn.head; i < janet_vm.spawn.tail; i++) {
|
||||
janet_mark(janet_wrap_fiber(tasks[i].fiber));
|
||||
janet_mark(tasks[i].value);
|
||||
}
|
||||
} else {
|
||||
for (int32_t i = janet_vm_spawn.head; i < janet_vm_spawn.capacity; i++) {
|
||||
for (int32_t i = janet_vm.spawn.head; i < janet_vm.spawn.capacity; i++) {
|
||||
janet_mark(janet_wrap_fiber(tasks[i].fiber));
|
||||
janet_mark(tasks[i].value);
|
||||
}
|
||||
for (int32_t i = 0; i < janet_vm_spawn.tail; i++) {
|
||||
for (int32_t i = 0; i < janet_vm.spawn.tail; i++) {
|
||||
janet_mark(janet_wrap_fiber(tasks[i].fiber));
|
||||
janet_mark(tasks[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pending timeouts */
|
||||
for (size_t i = 0; i < janet_vm_tq_count; i++) {
|
||||
janet_mark(janet_wrap_fiber(janet_vm_tq[i].fiber));
|
||||
if (janet_vm_tq[i].curr_fiber != NULL) {
|
||||
janet_mark(janet_wrap_fiber(janet_vm_tq[i].curr_fiber));
|
||||
for (size_t i = 0; i < janet_vm.tq_count; i++) {
|
||||
janet_mark(janet_wrap_fiber(janet_vm.tq[i].fiber));
|
||||
if (janet_vm.tq[i].curr_fiber != NULL) {
|
||||
janet_mark(janet_wrap_fiber(janet_vm.tq[i].curr_fiber));
|
||||
}
|
||||
}
|
||||
|
||||
/* Pending listeners */
|
||||
for (size_t i = 0; i < janet_vm_listener_count; i++) {
|
||||
JanetListenerState *state = janet_vm_listeners[i];
|
||||
for (size_t i = 0; i < janet_vm.listener_count; i++) {
|
||||
JanetListenerState *state = janet_vm.listeners[i];
|
||||
if (NULL != state->fiber) {
|
||||
janet_mark(janet_wrap_fiber(state->fiber));
|
||||
}
|
||||
@ -544,22 +516,22 @@ static void run_one(JanetFiber *fiber, Janet value, JanetSignal sigin) {
|
||||
|
||||
/* Common init code */
|
||||
void janet_ev_init_common(void) {
|
||||
janet_q_init(&janet_vm_spawn);
|
||||
janet_vm_listener_count = 0;
|
||||
janet_vm_listener_cap = 0;
|
||||
janet_vm_listeners = NULL;
|
||||
janet_vm_tq = NULL;
|
||||
janet_vm_tq_count = 0;
|
||||
janet_vm_tq_capacity = 0;
|
||||
janet_rng_seed(&janet_vm_ev_rng, 0);
|
||||
janet_q_init(&janet_vm.spawn);
|
||||
janet_vm.listener_count = 0;
|
||||
janet_vm.listener_cap = 0;
|
||||
janet_vm.listeners = NULL;
|
||||
janet_vm.tq = NULL;
|
||||
janet_vm.tq_count = 0;
|
||||
janet_vm.tq_capacity = 0;
|
||||
janet_rng_seed(&janet_vm.ev_rng, 0);
|
||||
}
|
||||
|
||||
/* Common deinit code */
|
||||
void janet_ev_deinit_common(void) {
|
||||
janet_q_deinit(&janet_vm_spawn);
|
||||
janet_free(janet_vm_tq);
|
||||
janet_free(janet_vm_listeners);
|
||||
janet_vm_listeners = NULL;
|
||||
janet_q_deinit(&janet_vm.spawn);
|
||||
janet_free(janet_vm.tq);
|
||||
janet_free(janet_vm.listeners);
|
||||
janet_vm.listeners = NULL;
|
||||
}
|
||||
|
||||
/* Short hand to yield to event loop */
|
||||
@ -569,7 +541,7 @@ void janet_await(void) {
|
||||
|
||||
/* Set timeout for the current root fiber */
|
||||
void janet_addtimeout(double sec) {
|
||||
JanetFiber *fiber = janet_vm_root_fiber;
|
||||
JanetFiber *fiber = janet_vm.root_fiber;
|
||||
JanetTimeout to;
|
||||
to.when = ts_delta(ts_now(), sec);
|
||||
to.fiber = fiber;
|
||||
@ -580,11 +552,11 @@ void janet_addtimeout(double sec) {
|
||||
}
|
||||
|
||||
void janet_ev_inc_refcount(void) {
|
||||
janet_vm_extra_listeners++;
|
||||
janet_vm.extra_listeners++;
|
||||
}
|
||||
|
||||
void janet_ev_dec_refcount(void) {
|
||||
janet_vm_extra_listeners--;
|
||||
janet_vm.extra_listeners--;
|
||||
}
|
||||
|
||||
/* Channels */
|
||||
@ -699,8 +671,8 @@ static int janet_channel_push(JanetChannel *channel, Janet x, int mode) {
|
||||
if (mode == 2) return 0;
|
||||
/* Pushed successfully, but should block. */
|
||||
JanetChannelPending pending;
|
||||
pending.fiber = janet_vm_root_fiber,
|
||||
pending.sched_id = janet_vm_root_fiber->sched_id,
|
||||
pending.fiber = janet_vm.root_fiber,
|
||||
pending.sched_id = janet_vm.root_fiber->sched_id,
|
||||
pending.mode = mode ? JANET_CP_MODE_CHOICE_WRITE : JANET_CP_MODE_ITEM;
|
||||
janet_q_push(&channel->write_pending, &pending, sizeof(pending));
|
||||
return 1;
|
||||
@ -724,8 +696,8 @@ static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice)
|
||||
if (janet_q_pop(&channel->items, item, sizeof(Janet))) {
|
||||
/* Queue empty */
|
||||
JanetChannelPending pending;
|
||||
pending.fiber = janet_vm_root_fiber,
|
||||
pending.sched_id = janet_vm_root_fiber->sched_id;
|
||||
pending.fiber = janet_vm.root_fiber,
|
||||
pending.sched_id = janet_vm.root_fiber->sched_id;
|
||||
pending.mode = is_choice ? JANET_CP_MODE_CHOICE_READ : JANET_CP_MODE_ITEM;
|
||||
janet_q_push(&channel->read_pending, &pending, sizeof(pending));
|
||||
return 0;
|
||||
@ -757,7 +729,7 @@ static Janet cfun_channel_pop(int32_t argc, Janet *argv) {
|
||||
JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT);
|
||||
Janet item;
|
||||
if (janet_channel_pop(channel, &item, 0)) {
|
||||
janet_schedule(janet_vm_root_fiber, item);
|
||||
janet_schedule(janet_vm.root_fiber, item);
|
||||
}
|
||||
janet_await();
|
||||
}
|
||||
@ -825,7 +797,7 @@ static Janet cfun_channel_count(int32_t argc, Janet *argv) {
|
||||
/* Fisher yates shuffle of arguments to get fairness */
|
||||
static void fisher_yates_args(int32_t argc, Janet *argv) {
|
||||
for (int32_t i = argc; i > 1; i--) {
|
||||
int32_t swap_index = janet_rng_u32(&janet_vm_ev_rng) % i;
|
||||
int32_t swap_index = janet_rng_u32(&janet_vm.ev_rng) % i;
|
||||
Janet temp = argv[swap_index];
|
||||
argv[swap_index] = argv[i - 1];
|
||||
argv[i - 1] = temp;
|
||||
@ -903,14 +875,14 @@ void janet_loop1(void) {
|
||||
}
|
||||
|
||||
/* Run scheduled fibers */
|
||||
while (janet_vm_spawn.head != janet_vm_spawn.tail) {
|
||||
while (janet_vm.spawn.head != janet_vm.spawn.tail) {
|
||||
JanetTask task = {NULL, janet_wrap_nil(), JANET_SIGNAL_OK};
|
||||
janet_q_pop(&janet_vm_spawn, &task, sizeof(task));
|
||||
janet_q_pop(&janet_vm.spawn, &task, sizeof(task));
|
||||
run_one(task.fiber, task.value, task.sig);
|
||||
}
|
||||
|
||||
/* Poll for events */
|
||||
if (janet_vm_listener_count || janet_vm_tq_count || janet_vm_extra_listeners) {
|
||||
if (janet_vm.listener_count || janet_vm.tq_count || janet_vm.extra_listeners) {
|
||||
JanetTimeout to;
|
||||
memset(&to, 0, sizeof(to));
|
||||
int has_timeout;
|
||||
@ -919,14 +891,14 @@ void janet_loop1(void) {
|
||||
pop_timeout(0);
|
||||
}
|
||||
/* Run polling implementation only if pending timeouts or pending events */
|
||||
if (janet_vm_tq_count || janet_vm_listener_count || janet_vm_extra_listeners) {
|
||||
if (janet_vm.tq_count || janet_vm.listener_count || janet_vm.extra_listeners) {
|
||||
janet_loop1_impl(has_timeout, to.when);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void janet_loop(void) {
|
||||
while (janet_vm_listener_count || (janet_vm_spawn.head != janet_vm_spawn.tail) || janet_vm_tq_count || janet_vm_extra_listeners) {
|
||||
while (janet_vm.listener_count || (janet_vm.spawn.head != janet_vm.spawn.tail) || janet_vm.tq_count || janet_vm.extra_listeners) {
|
||||
janet_loop1();
|
||||
}
|
||||
}
|
||||
@ -958,10 +930,8 @@ typedef struct {
|
||||
|
||||
#else
|
||||
|
||||
static JANET_THREAD_LOCAL JanetHandle janet_vm_selfpipe[2];
|
||||
|
||||
static void janet_ev_setup_selfpipe(void) {
|
||||
if (janet_make_pipe(janet_vm_selfpipe, 0)) {
|
||||
if (janet_make_pipe(janet_vm.selfpipe, 0)) {
|
||||
JANET_EXIT("failed to initialize self pipe in event loop");
|
||||
}
|
||||
}
|
||||
@ -969,43 +939,41 @@ static void janet_ev_setup_selfpipe(void) {
|
||||
/* Handle events from the self pipe inside the event loop */
|
||||
static void janet_ev_handle_selfpipe(void) {
|
||||
JanetSelfPipeEvent response;
|
||||
while (read(janet_vm_selfpipe[0], &response, sizeof(response)) > 0) {
|
||||
while (read(janet_vm.selfpipe[0], &response, sizeof(response)) > 0) {
|
||||
response.cb(response.msg);
|
||||
janet_ev_dec_refcount();
|
||||
}
|
||||
}
|
||||
|
||||
static void janet_ev_cleanup_selfpipe(void) {
|
||||
close(janet_vm_selfpipe[0]);
|
||||
close(janet_vm_selfpipe[1]);
|
||||
close(janet_vm.selfpipe[0]);
|
||||
close(janet_vm.selfpipe[1]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
|
||||
JANET_THREAD_LOCAL HANDLE janet_vm_iocp = NULL;
|
||||
|
||||
static JanetTimestamp ts_now(void) {
|
||||
return (JanetTimestamp) GetTickCount64();
|
||||
}
|
||||
|
||||
void janet_ev_init(void) {
|
||||
janet_ev_init_common();
|
||||
janet_vm_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
if (NULL == janet_vm_iocp) janet_panic("could not create io completion port");
|
||||
janet_vm.iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
if (NULL == janet_vm.iocp) janet_panic("could not create io completion port");
|
||||
}
|
||||
|
||||
void janet_ev_deinit(void) {
|
||||
janet_ev_deinit_common();
|
||||
CloseHandle(janet_vm_iocp);
|
||||
CloseHandle(janet_vm.iocp);
|
||||
}
|
||||
|
||||
JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) {
|
||||
/* Add the handle to the io completion port if not already added */
|
||||
JanetListenerState *state = janet_listen_impl(stream, behavior, mask, size, user);
|
||||
if (!(stream->flags & JANET_STREAM_IOCP)) {
|
||||
if (NULL == CreateIoCompletionPort(stream->handle, janet_vm_iocp, (ULONG_PTR) stream, 0)) {
|
||||
if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) {
|
||||
janet_panicf("failed to listen for events: %V", janet_ev_lasterr());
|
||||
}
|
||||
stream->flags |= JANET_STREAM_IOCP;
|
||||
@ -1035,7 +1003,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
|
||||
} else {
|
||||
waittime = INFINITE;
|
||||
}
|
||||
BOOL result = GetQueuedCompletionStatus(janet_vm_iocp, &num_bytes_transfered, &completionKey, &overlapped, (DWORD) waittime);
|
||||
BOOL result = GetQueuedCompletionStatus(janet_vm.iocp, &num_bytes_transfered, &completionKey, &overlapped, (DWORD) waittime);
|
||||
|
||||
if (result || overlapped) {
|
||||
if (0 == completionKey) {
|
||||
@ -1067,10 +1035,6 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
|
||||
|
||||
#elif defined(JANET_EV_EPOLL)
|
||||
|
||||
JANET_THREAD_LOCAL int janet_vm_epoll = 0;
|
||||
JANET_THREAD_LOCAL int janet_vm_timerfd = 0;
|
||||
JANET_THREAD_LOCAL int janet_vm_timer_enabled = 0;
|
||||
|
||||
static JanetTimestamp ts_now(void) {
|
||||
struct timespec now;
|
||||
janet_assert(-1 != clock_gettime(CLOCK_MONOTONIC, &now), "failed to get time");
|
||||
@ -1098,7 +1062,7 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in
|
||||
ev.data.ptr = stream;
|
||||
int status;
|
||||
do {
|
||||
status = epoll_ctl(janet_vm_epoll, op, stream->handle, &ev);
|
||||
status = epoll_ctl(janet_vm.epoll, op, stream->handle, &ev);
|
||||
} while (status == -1 && errno == EINTR);
|
||||
if (status == -1) {
|
||||
janet_unlisten_impl(state);
|
||||
@ -1118,7 +1082,7 @@ static void janet_unlisten(JanetListenerState *state) {
|
||||
ev.data.ptr = stream;
|
||||
int status;
|
||||
do {
|
||||
status = epoll_ctl(janet_vm_epoll, op, stream->handle, &ev);
|
||||
status = epoll_ctl(janet_vm.epoll, op, stream->handle, &ev);
|
||||
} while (status == -1 && errno == EINTR);
|
||||
if (status == -1) {
|
||||
janet_panicv(janet_ev_lasterr());
|
||||
@ -1131,21 +1095,21 @@ static void janet_unlisten(JanetListenerState *state) {
|
||||
#define JANET_EPOLL_MAX_EVENTS 64
|
||||
void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
struct itimerspec its;
|
||||
if (janet_vm_timer_enabled || has_timeout) {
|
||||
if (janet_vm.timer_enabled || has_timeout) {
|
||||
memset(&its, 0, sizeof(its));
|
||||
if (has_timeout) {
|
||||
its.it_value.tv_sec = timeout / 1000;
|
||||
its.it_value.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
timerfd_settime(janet_vm_timerfd, TFD_TIMER_ABSTIME, &its, NULL);
|
||||
timerfd_settime(janet_vm.timerfd, TFD_TIMER_ABSTIME, &its, NULL);
|
||||
}
|
||||
janet_vm_timer_enabled = has_timeout;
|
||||
janet_vm.timer_enabled = has_timeout;
|
||||
|
||||
/* Poll for events */
|
||||
struct epoll_event events[JANET_EPOLL_MAX_EVENTS];
|
||||
int ready;
|
||||
do {
|
||||
ready = epoll_wait(janet_vm_epoll, events, JANET_EPOLL_MAX_EVENTS, -1);
|
||||
ready = epoll_wait(janet_vm.epoll, events, JANET_EPOLL_MAX_EVENTS, -1);
|
||||
} while (ready == -1 && errno == EINTR);
|
||||
if (ready == -1) {
|
||||
JANET_EXIT("failed to poll events");
|
||||
@ -1154,9 +1118,9 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
/* Step state machines */
|
||||
for (int i = 0; i < ready; i++) {
|
||||
void *p = events[i].data.ptr;
|
||||
if (&janet_vm_timerfd == p) {
|
||||
if (&janet_vm.timerfd == p) {
|
||||
/* Timer expired, ignore */;
|
||||
} else if (janet_vm_selfpipe == p) {
|
||||
} else if (janet_vm.selfpipe == p) {
|
||||
/* Self-pipe handling */
|
||||
janet_ev_handle_selfpipe();
|
||||
} else {
|
||||
@ -1192,17 +1156,17 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
void janet_ev_init(void) {
|
||||
janet_ev_init_common();
|
||||
janet_ev_setup_selfpipe();
|
||||
janet_vm_epoll = epoll_create1(EPOLL_CLOEXEC);
|
||||
janet_vm_timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
janet_vm_timer_enabled = 0;
|
||||
if (janet_vm_epoll == -1 || janet_vm_timerfd == -1) goto error;
|
||||
janet_vm.epoll = epoll_create1(EPOLL_CLOEXEC);
|
||||
janet_vm.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
janet_vm.timer_enabled = 0;
|
||||
if (janet_vm.epoll == -1 || janet_vm.timerfd == -1) goto error;
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLET;
|
||||
ev.data.ptr = &janet_vm_timerfd;
|
||||
if (-1 == epoll_ctl(janet_vm_epoll, EPOLL_CTL_ADD, janet_vm_timerfd, &ev)) goto error;
|
||||
ev.data.ptr = &janet_vm.timerfd;
|
||||
if (-1 == epoll_ctl(janet_vm.epoll, EPOLL_CTL_ADD, janet_vm.timerfd, &ev)) goto error;
|
||||
ev.events = EPOLLIN | EPOLLET;
|
||||
ev.data.ptr = janet_vm_selfpipe;
|
||||
if (-1 == epoll_ctl(janet_vm_epoll, EPOLL_CTL_ADD, janet_vm_selfpipe[0], &ev)) goto error;
|
||||
ev.data.ptr = janet_vm.selfpipe;
|
||||
if (-1 == epoll_ctl(janet_vm.epoll, EPOLL_CTL_ADD, janet_vm.selfpipe[0], &ev)) goto error;
|
||||
return;
|
||||
error:
|
||||
JANET_EXIT("failed to initialize event loop");
|
||||
@ -1210,10 +1174,10 @@ error:
|
||||
|
||||
void janet_ev_deinit(void) {
|
||||
janet_ev_deinit_common();
|
||||
close(janet_vm_epoll);
|
||||
close(janet_vm_timerfd);
|
||||
close(janet_vm.epoll);
|
||||
close(janet_vm.timerfd);
|
||||
janet_ev_cleanup_selfpipe();
|
||||
janet_vm_epoll = 0;
|
||||
janet_vm.epoll = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1224,8 +1188,6 @@ void janet_ev_deinit(void) {
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
JANET_THREAD_LOCAL struct pollfd *janet_vm_fds = NULL;
|
||||
|
||||
static JanetTimestamp ts_now(void) {
|
||||
struct timespec now;
|
||||
janet_assert(-1 != clock_gettime(CLOCK_REALTIME, &now), "failed to get time");
|
||||
@ -1245,12 +1207,12 @@ static int make_poll_events(int mask) {
|
||||
|
||||
/* Wait for the next event */
|
||||
JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) {
|
||||
size_t oldsize = janet_vm_listener_cap;
|
||||
size_t oldsize = janet_vm.listener_cap;
|
||||
JanetListenerState *state = janet_listen_impl(stream, behavior, mask, size, user);
|
||||
size_t newsize = janet_vm_listener_cap;
|
||||
size_t newsize = janet_vm.listener_cap;
|
||||
if (newsize > oldsize) {
|
||||
janet_vm_fds = janet_realloc(janet_vm_fds, (newsize + 1) * sizeof(struct pollfd));
|
||||
if (NULL == janet_vm_fds) {
|
||||
janet_vm.fds = janet_realloc(janet_vm.fds, (newsize + 1) * sizeof(struct pollfd));
|
||||
if (NULL == janet_vm.fds) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
@ -1258,12 +1220,12 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in
|
||||
ev.fd = stream->handle;
|
||||
ev.events = make_poll_events(state->stream->_mask);
|
||||
ev.revents = 0;
|
||||
janet_vm_fds[state->_index + 1] = ev;
|
||||
janet_vm.fds[state->_index + 1] = ev;
|
||||
return state;
|
||||
}
|
||||
|
||||
static void janet_unlisten(JanetListenerState *state) {
|
||||
janet_vm_fds[state->_index + 1] = janet_vm_fds[janet_vm_listener_count];
|
||||
janet_vm.fds[state->_index + 1] = janet_vm.fds[janet_vm.listener_count];
|
||||
janet_unlisten_impl(state);
|
||||
}
|
||||
|
||||
@ -1276,23 +1238,23 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
JanetTimestamp now = ts_now();
|
||||
to = now > timeout ? 0 : (int)(timeout - now);
|
||||
}
|
||||
ready = poll(janet_vm_fds, janet_vm_listener_count + 1, to);
|
||||
ready = poll(janet_vm.fds, janet_vm.listener_count + 1, to);
|
||||
} while (ready == -1 && errno == EINTR);
|
||||
if (ready == -1) {
|
||||
JANET_EXIT("failed to poll events");
|
||||
}
|
||||
|
||||
/* Check selfpipe */
|
||||
if (janet_vm_fds[0].revents & POLLIN) {
|
||||
janet_vm_fds[0].revents = 0;
|
||||
if (janet_vm.fds[0].revents & POLLIN) {
|
||||
janet_vm.fds[0].revents = 0;
|
||||
janet_ev_handle_selfpipe();
|
||||
}
|
||||
|
||||
/* Step state machines */
|
||||
for (size_t i = 0; i < janet_vm_listener_count; i++) {
|
||||
struct pollfd *pfd = janet_vm_fds + i + 1;
|
||||
for (size_t i = 0; i < janet_vm.listener_count; i++) {
|
||||
struct pollfd *pfd = janet_vm.fds + i + 1;
|
||||
/* Skip fds where nothing interesting happened */
|
||||
JanetListenerState *state = janet_vm_listeners[i];
|
||||
JanetListenerState *state = janet_vm.listeners[i];
|
||||
/* Normal event */
|
||||
int mask = pfd->revents;
|
||||
JanetAsyncStatus status1 = JANET_ASYNC_STATUS_NOT_DONE;
|
||||
@ -1318,23 +1280,23 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
|
||||
|
||||
void janet_ev_init(void) {
|
||||
janet_ev_init_common();
|
||||
janet_vm_fds = NULL;
|
||||
janet_vm.fds = NULL;
|
||||
janet_ev_setup_selfpipe();
|
||||
janet_vm_fds = janet_malloc(sizeof(struct pollfd));
|
||||
if (NULL == janet_vm_fds) {
|
||||
janet_vm.fds = janet_malloc(sizeof(struct pollfd));
|
||||
if (NULL == janet_vm.fds) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_fds[0].fd = janet_vm_selfpipe[0];
|
||||
janet_vm_fds[0].events = POLLIN;
|
||||
janet_vm_fds[0].revents = 0;
|
||||
janet_vm.fds[0].fd = janet_vm.selfpipe[0];
|
||||
janet_vm.fds[0].events = POLLIN;
|
||||
janet_vm.fds[0].revents = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void janet_ev_deinit(void) {
|
||||
janet_ev_deinit_common();
|
||||
janet_ev_cleanup_selfpipe();
|
||||
janet_free(janet_vm_fds);
|
||||
janet_vm_fds = NULL;
|
||||
janet_free(janet_vm.fds);
|
||||
janet_vm.fds = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1400,7 +1362,7 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar
|
||||
init->cb = cb;
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
init->write_pipe = janet_vm_iocp;
|
||||
init->write_pipe = janet_vm.iocp;
|
||||
HANDLE thread_handle = CreateThread(NULL, 0, janet_thread_body, init, 0, NULL);
|
||||
if (NULL == thread_handle) {
|
||||
janet_free(init);
|
||||
@ -1408,7 +1370,7 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar
|
||||
}
|
||||
CloseHandle(thread_handle); /* detach from thread */
|
||||
#else
|
||||
init->write_pipe = janet_vm_selfpipe[1];
|
||||
init->write_pipe = janet_vm.selfpipe[1];
|
||||
pthread_t waiter_thread;
|
||||
int err = pthread_create(&waiter_thread, NULL, janet_thread_body, init);
|
||||
if (err) {
|
||||
@ -2040,7 +2002,7 @@ static Janet cfun_ev_go(int32_t argc, Janet *argv) {
|
||||
JanetFiber *fiber = janet_getfiber(argv, 0);
|
||||
Janet value = argc >= 2 ? argv[1] : janet_wrap_nil();
|
||||
JanetChannel *supervisor_channel = janet_optabstract(argv, argc, 2, &ChannelAT,
|
||||
janet_vm_root_fiber->supervisor_channel);
|
||||
janet_vm.root_fiber->supervisor_channel);
|
||||
fiber->supervisor_channel = supervisor_channel;
|
||||
janet_schedule(fiber, value);
|
||||
return argv[0];
|
||||
@ -2058,11 +2020,11 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
||||
Janet aregv = janet_unmarshal(nextbytes, endbytes - nextbytes,
|
||||
JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
|
||||
if (!janet_checktype(aregv, JANET_TABLE)) janet_panic("expected table for abstract registry");
|
||||
janet_vm_abstract_registry = janet_unwrap_table(aregv);
|
||||
janet_vm.abstract_registry = janet_unwrap_table(aregv);
|
||||
Janet regv = janet_unmarshal(nextbytes, endbytes - nextbytes,
|
||||
JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
|
||||
if (!janet_checktype(regv, JANET_TABLE)) janet_panic("expected table for cfunction registry");
|
||||
janet_vm_registry = janet_unwrap_table(regv);
|
||||
janet_vm.registry = janet_unwrap_table(regv);
|
||||
Janet fiberv = janet_unmarshal(nextbytes, endbytes - nextbytes,
|
||||
JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
|
||||
Janet value = janet_unmarshal(nextbytes, endbytes - nextbytes,
|
||||
@ -2097,8 +2059,8 @@ static Janet cfun_ev_thread(int32_t argc, Janet *argv) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_buffer_init(buffer, 0);
|
||||
janet_marshal(buffer, janet_wrap_table(janet_vm_abstract_registry), NULL, JANET_MARSHAL_UNSAFE);
|
||||
janet_marshal(buffer, janet_wrap_table(janet_vm_registry), NULL, JANET_MARSHAL_UNSAFE);
|
||||
janet_marshal(buffer, janet_wrap_table(janet_vm.abstract_registry), NULL, JANET_MARSHAL_UNSAFE);
|
||||
janet_marshal(buffer, janet_wrap_table(janet_vm.registry), NULL, JANET_MARSHAL_UNSAFE);
|
||||
janet_marshal(buffer, argv[0], NULL, JANET_MARSHAL_UNSAFE);
|
||||
janet_marshal(buffer, value, NULL, JANET_MARSHAL_UNSAFE);
|
||||
janet_ev_threaded_await(janet_go_thread_subr, 0, argc, buffer);
|
||||
@ -2106,7 +2068,7 @@ static Janet cfun_ev_thread(int32_t argc, Janet *argv) {
|
||||
|
||||
static Janet cfun_ev_give_supervisor(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, -1);
|
||||
JanetChannel *chan = janet_vm_root_fiber->supervisor_channel;
|
||||
JanetChannel *chan = janet_vm.root_fiber->supervisor_channel;
|
||||
if (NULL != chan) {
|
||||
if (janet_channel_push(chan, janet_wrap_tuple(janet_tuple_n(argv, argc)), 0)) {
|
||||
janet_await();
|
||||
@ -2118,7 +2080,7 @@ static Janet cfun_ev_give_supervisor(int32_t argc, Janet *argv) {
|
||||
JANET_NO_RETURN void janet_sleep_await(double sec) {
|
||||
JanetTimeout to;
|
||||
to.when = ts_delta(ts_now(), sec);
|
||||
to.fiber = janet_vm_root_fiber;
|
||||
to.fiber = janet_vm.root_fiber;
|
||||
to.is_error = 0;
|
||||
to.sched_id = to.fiber->sched_id;
|
||||
to.curr_fiber = NULL;
|
||||
@ -2135,8 +2097,8 @@ static Janet cfun_ev_sleep(int32_t argc, Janet *argv) {
|
||||
static Janet cfun_ev_deadline(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 3);
|
||||
double sec = janet_getnumber(argv, 0);
|
||||
JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm_root_fiber);
|
||||
JanetFiber *tocheck = janet_optfiber(argv, argc, 2, janet_vm_fiber);
|
||||
JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber);
|
||||
JanetFiber *tocheck = janet_optfiber(argv, argc, 2, janet_vm.fiber);
|
||||
JanetTimeout to;
|
||||
to.when = ts_delta(ts_now(), sec);
|
||||
to.fiber = tocancel;
|
||||
|
@ -57,7 +57,7 @@ static JanetFiber *fiber_alloc(int32_t capacity) {
|
||||
if (NULL == data) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_next_collection += sizeof(Janet) * capacity;
|
||||
janet_vm.next_collection += sizeof(Janet) * capacity;
|
||||
fiber->data = data;
|
||||
return fiber;
|
||||
}
|
||||
@ -121,7 +121,7 @@ void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
|
||||
}
|
||||
fiber->data = newData;
|
||||
fiber->capacity = n;
|
||||
janet_vm_next_collection += sizeof(Janet) * diff;
|
||||
janet_vm.next_collection += sizeof(Janet) * diff;
|
||||
}
|
||||
|
||||
/* Grow fiber if needed */
|
||||
@ -255,7 +255,7 @@ static void janet_env_detach(JanetFuncEnv *env) {
|
||||
int32_t len = env->length;
|
||||
size_t s = sizeof(Janet) * (size_t) len;
|
||||
Janet *vmem = janet_malloc(s);
|
||||
janet_vm_next_collection += (uint32_t) s;
|
||||
janet_vm.next_collection += (uint32_t) s;
|
||||
if (NULL == vmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -442,11 +442,11 @@ JanetFiberStatus janet_fiber_status(JanetFiber *f) {
|
||||
}
|
||||
|
||||
JanetFiber *janet_current_fiber(void) {
|
||||
return janet_vm_fiber;
|
||||
return janet_vm.fiber;
|
||||
}
|
||||
|
||||
JanetFiber *janet_root_fiber(void) {
|
||||
return janet_vm_root_fiber;
|
||||
return janet_vm.root_fiber;
|
||||
}
|
||||
|
||||
/* CFuns */
|
||||
@ -520,17 +520,17 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
|
||||
fiber->flags |= JANET_FIBER_MASK_YIELD;
|
||||
break;
|
||||
case 'i':
|
||||
if (!janet_vm_fiber->env) {
|
||||
janet_vm_fiber->env = janet_table(0);
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(0);
|
||||
}
|
||||
fiber->env = janet_vm_fiber->env;
|
||||
fiber->env = janet_vm.fiber->env;
|
||||
break;
|
||||
case 'p':
|
||||
if (!janet_vm_fiber->env) {
|
||||
janet_vm_fiber->env = janet_table(0);
|
||||
if (!janet_vm.fiber->env) {
|
||||
janet_vm.fiber->env = janet_table(0);
|
||||
}
|
||||
fiber->env = janet_table(0);
|
||||
fiber->env->proto = janet_vm_fiber->env;
|
||||
fiber->env->proto = janet_vm.fiber->env;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -549,13 +549,13 @@ static Janet cfun_fiber_status(int32_t argc, Janet *argv) {
|
||||
static Janet cfun_fiber_current(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_fiber(janet_vm_fiber);
|
||||
return janet_wrap_fiber(janet_vm.fiber);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_root(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_fiber(janet_vm_root_fiber);
|
||||
return janet_wrap_fiber(janet_vm.root_fiber);
|
||||
}
|
||||
|
||||
static Janet cfun_fiber_maxstack(int32_t argc, Janet *argv) {
|
||||
|
@ -57,8 +57,6 @@
|
||||
#define JANET_FIBER_DID_LONGJUMP 0x8000000
|
||||
#define JANET_FIBER_FLAG_MASK 0xF000000
|
||||
|
||||
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
|
||||
|
||||
#define janet_fiber_set_status(f, s) do {\
|
||||
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\
|
||||
(f)->flags |= (s) << JANET_FIBER_STATUS_OFFSET;\
|
||||
|
130
src/core/gc.c
130
src/core/gc.c
@ -31,28 +31,6 @@
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
struct JanetScratch {
|
||||
JanetScratchFinalizer finalize;
|
||||
long long mem[]; /* for proper alignment */
|
||||
};
|
||||
|
||||
/* GC State */
|
||||
JANET_THREAD_LOCAL void *janet_vm_blocks;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_gc_interval;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_next_collection;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_block_count;
|
||||
JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0;
|
||||
|
||||
/* Roots */
|
||||
JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_root_count;
|
||||
JANET_THREAD_LOCAL size_t janet_vm_root_capacity;
|
||||
|
||||
/* Scratch Memory */
|
||||
JANET_THREAD_LOCAL JanetScratch **janet_scratch_mem;
|
||||
JANET_THREAD_LOCAL size_t janet_scratch_cap;
|
||||
JANET_THREAD_LOCAL size_t janet_scratch_len;
|
||||
|
||||
/* Helpers for marking the various gc types */
|
||||
static void janet_mark_funcenv(JanetFuncEnv *env);
|
||||
static void janet_mark_funcdef(JanetFuncDef *def);
|
||||
@ -72,7 +50,7 @@ static JANET_THREAD_LOCAL size_t orig_rootcount;
|
||||
|
||||
/* Hint to the GC that we may need to collect */
|
||||
void janet_gcpressure(size_t s) {
|
||||
janet_vm_next_collection += s;
|
||||
janet_vm.next_collection += s;
|
||||
}
|
||||
|
||||
/* Mark a value */
|
||||
@ -332,7 +310,7 @@ static void janet_deinit_block(JanetGCObject *mem) {
|
||||
* marked as reachable. Flip the gc color flag for next sweep. */
|
||||
void janet_sweep() {
|
||||
JanetGCObject *previous = NULL;
|
||||
JanetGCObject *current = janet_vm_blocks;
|
||||
JanetGCObject *current = janet_vm.blocks;
|
||||
JanetGCObject *next;
|
||||
while (NULL != current) {
|
||||
next = current->next;
|
||||
@ -340,12 +318,12 @@ void janet_sweep() {
|
||||
previous = current;
|
||||
current->flags &= ~JANET_MEM_REACHABLE;
|
||||
} else {
|
||||
janet_vm_block_count--;
|
||||
janet_vm.block_count--;
|
||||
janet_deinit_block(current);
|
||||
if (NULL != previous) {
|
||||
previous->next = next;
|
||||
} else {
|
||||
janet_vm_blocks = next;
|
||||
janet_vm.blocks = next;
|
||||
}
|
||||
janet_free(current);
|
||||
}
|
||||
@ -358,7 +336,7 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
|
||||
JanetGCObject *mem;
|
||||
|
||||
/* Make sure everything is inited */
|
||||
janet_assert(NULL != janet_vm_cache, "please initialize janet before use");
|
||||
janet_assert(NULL != janet_vm.cache, "please initialize janet before use");
|
||||
mem = janet_malloc(size);
|
||||
|
||||
/* Check for bad malloc */
|
||||
@ -370,10 +348,10 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
|
||||
mem->flags = type;
|
||||
|
||||
/* Prepend block to heap list */
|
||||
janet_vm_next_collection += size;
|
||||
mem->next = janet_vm_blocks;
|
||||
janet_vm_blocks = mem;
|
||||
janet_vm_block_count++;
|
||||
janet_vm.next_collection += size;
|
||||
mem->next = janet_vm.blocks;
|
||||
janet_vm.blocks = mem;
|
||||
janet_vm.block_count++;
|
||||
|
||||
return (void *)mem;
|
||||
}
|
||||
@ -387,10 +365,10 @@ static void free_one_scratch(JanetScratch *s) {
|
||||
|
||||
/* Free all allocated scratch memory */
|
||||
static void janet_free_all_scratch(void) {
|
||||
for (size_t i = 0; i < janet_scratch_len; i++) {
|
||||
free_one_scratch(janet_scratch_mem[i]);
|
||||
for (size_t i = 0; i < janet_vm.scratch_len; i++) {
|
||||
free_one_scratch(janet_vm.scratch_mem[i]);
|
||||
}
|
||||
janet_scratch_len = 0;
|
||||
janet_vm.scratch_len = 0;
|
||||
}
|
||||
|
||||
static JanetScratch *janet_mem2scratch(void *mem) {
|
||||
@ -401,29 +379,29 @@ static JanetScratch *janet_mem2scratch(void *mem) {
|
||||
/* Run garbage collection */
|
||||
void janet_collect(void) {
|
||||
uint32_t i;
|
||||
if (janet_vm_gc_suspend) return;
|
||||
if (janet_vm.gc_suspend) return;
|
||||
depth = JANET_RECURSION_GUARD;
|
||||
/* Try and prevent many major collections back to back.
|
||||
* A full collection will take O(janet_vm_block_count) time.
|
||||
* A full collection will take O(janet_vm.block_count) time.
|
||||
* If we have a large heap, make sure our interval is not too
|
||||
* small so we won't make many collections over it. This is just a
|
||||
* heuristic for automatically changing the gc interval */
|
||||
if (janet_vm_block_count * 8 > janet_vm_gc_interval) {
|
||||
janet_vm_gc_interval = janet_vm_block_count * sizeof(JanetGCObject);
|
||||
if (janet_vm.block_count * 8 > janet_vm.gc_interval) {
|
||||
janet_vm.gc_interval = janet_vm.block_count * sizeof(JanetGCObject);
|
||||
}
|
||||
orig_rootcount = janet_vm_root_count;
|
||||
orig_rootcount = janet_vm.root_count;
|
||||
#ifdef JANET_EV
|
||||
janet_ev_mark();
|
||||
#endif
|
||||
janet_mark_fiber(janet_vm_root_fiber);
|
||||
janet_mark_fiber(janet_vm.root_fiber);
|
||||
for (i = 0; i < orig_rootcount; i++)
|
||||
janet_mark(janet_vm_roots[i]);
|
||||
while (orig_rootcount < janet_vm_root_count) {
|
||||
Janet x = janet_vm_roots[--janet_vm_root_count];
|
||||
janet_mark(janet_vm.roots[i]);
|
||||
while (orig_rootcount < janet_vm.root_count) {
|
||||
Janet x = janet_vm.roots[--janet_vm.root_count];
|
||||
janet_mark(x);
|
||||
}
|
||||
janet_sweep();
|
||||
janet_vm_next_collection = 0;
|
||||
janet_vm.next_collection = 0;
|
||||
janet_free_all_scratch();
|
||||
}
|
||||
|
||||
@ -431,17 +409,17 @@ void janet_collect(void) {
|
||||
* and all of its children. If gcroot is called on a value n times, unroot
|
||||
* must also be called n times to remove it as a gc root. */
|
||||
void janet_gcroot(Janet root) {
|
||||
size_t newcount = janet_vm_root_count + 1;
|
||||
if (newcount > janet_vm_root_capacity) {
|
||||
size_t newcount = janet_vm.root_count + 1;
|
||||
if (newcount > janet_vm.root_capacity) {
|
||||
size_t newcap = 2 * newcount;
|
||||
janet_vm_roots = janet_realloc(janet_vm_roots, sizeof(Janet) * newcap);
|
||||
if (NULL == janet_vm_roots) {
|
||||
janet_vm.roots = janet_realloc(janet_vm.roots, sizeof(Janet) * newcap);
|
||||
if (NULL == janet_vm.roots) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_root_capacity = newcap;
|
||||
janet_vm.root_capacity = newcap;
|
||||
}
|
||||
janet_vm_roots[janet_vm_root_count] = root;
|
||||
janet_vm_root_count = newcount;
|
||||
janet_vm.roots[janet_vm.root_count] = root;
|
||||
janet_vm.root_count = newcount;
|
||||
}
|
||||
|
||||
/* Identity equality for GC purposes */
|
||||
@ -462,11 +440,11 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) {
|
||||
/* Remove a root value from the GC. This allows the gc to potentially reclaim
|
||||
* a value and all its children. */
|
||||
int janet_gcunroot(Janet root) {
|
||||
Janet *vtop = janet_vm_roots + janet_vm_root_count;
|
||||
Janet *vtop = janet_vm.roots + janet_vm.root_count;
|
||||
/* Search from top to bottom as access is most likely LIFO */
|
||||
for (Janet *v = janet_vm_roots; v < vtop; v++) {
|
||||
for (Janet *v = janet_vm.roots; v < vtop; v++) {
|
||||
if (janet_gc_idequals(root, *v)) {
|
||||
*v = janet_vm_roots[--janet_vm_root_count];
|
||||
*v = janet_vm.roots[--janet_vm.root_count];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -475,12 +453,12 @@ int janet_gcunroot(Janet root) {
|
||||
|
||||
/* Remove a root value from the GC. This sets the effective reference count to 0. */
|
||||
int janet_gcunrootall(Janet root) {
|
||||
Janet *vtop = janet_vm_roots + janet_vm_root_count;
|
||||
Janet *vtop = janet_vm.roots + janet_vm.root_count;
|
||||
int ret = 0;
|
||||
/* Search from top to bottom as access is most likely LIFO */
|
||||
for (Janet *v = janet_vm_roots; v < vtop; v++) {
|
||||
for (Janet *v = janet_vm.roots; v < vtop; v++) {
|
||||
if (janet_gc_idequals(root, *v)) {
|
||||
*v = janet_vm_roots[--janet_vm_root_count];
|
||||
*v = janet_vm.roots[--janet_vm.root_count];
|
||||
vtop--;
|
||||
ret = 1;
|
||||
}
|
||||
@ -490,24 +468,24 @@ int janet_gcunrootall(Janet root) {
|
||||
|
||||
/* Free all allocated memory */
|
||||
void janet_clear_memory(void) {
|
||||
JanetGCObject *current = janet_vm_blocks;
|
||||
JanetGCObject *current = janet_vm.blocks;
|
||||
while (NULL != current) {
|
||||
janet_deinit_block(current);
|
||||
JanetGCObject *next = current->next;
|
||||
janet_free(current);
|
||||
current = next;
|
||||
}
|
||||
janet_vm_blocks = NULL;
|
||||
janet_vm.blocks = NULL;
|
||||
janet_free_all_scratch();
|
||||
janet_free(janet_scratch_mem);
|
||||
janet_free(janet_vm.scratch_mem);
|
||||
}
|
||||
|
||||
/* Primitives for suspending GC. */
|
||||
int janet_gclock(void) {
|
||||
return janet_vm_gc_suspend++;
|
||||
return janet_vm.gc_suspend++;
|
||||
}
|
||||
void janet_gcunlock(int handle) {
|
||||
janet_vm_gc_suspend = handle;
|
||||
janet_vm.gc_suspend = handle;
|
||||
}
|
||||
|
||||
/* Scratch memory API */
|
||||
@ -518,16 +496,16 @@ void *janet_smalloc(size_t size) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
s->finalize = NULL;
|
||||
if (janet_scratch_len == janet_scratch_cap) {
|
||||
size_t newcap = 2 * janet_scratch_cap + 2;
|
||||
JanetScratch **newmem = (JanetScratch **) janet_realloc(janet_scratch_mem, newcap * sizeof(JanetScratch));
|
||||
if (janet_vm.scratch_len == janet_vm.scratch_cap) {
|
||||
size_t newcap = 2 * janet_vm.scratch_cap + 2;
|
||||
JanetScratch **newmem = (JanetScratch **) janet_realloc(janet_vm.scratch_mem, newcap * sizeof(JanetScratch));
|
||||
if (NULL == newmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_scratch_cap = newcap;
|
||||
janet_scratch_mem = newmem;
|
||||
janet_vm.scratch_cap = newcap;
|
||||
janet_vm.scratch_mem = newmem;
|
||||
}
|
||||
janet_scratch_mem[janet_scratch_len++] = s;
|
||||
janet_vm.scratch_mem[janet_vm.scratch_len++] = s;
|
||||
return (char *)(s->mem);
|
||||
}
|
||||
|
||||
@ -544,14 +522,14 @@ void *janet_scalloc(size_t nmemb, size_t size) {
|
||||
void *janet_srealloc(void *mem, size_t size) {
|
||||
if (NULL == mem) return janet_smalloc(size);
|
||||
JanetScratch *s = janet_mem2scratch(mem);
|
||||
if (janet_scratch_len) {
|
||||
for (size_t i = janet_scratch_len - 1; ; i--) {
|
||||
if (janet_scratch_mem[i] == s) {
|
||||
if (janet_vm.scratch_len) {
|
||||
for (size_t i = janet_vm.scratch_len - 1; ; i--) {
|
||||
if (janet_vm.scratch_mem[i] == s) {
|
||||
JanetScratch *news = janet_realloc(s, size + sizeof(JanetScratch));
|
||||
if (NULL == news) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_scratch_mem[i] = news;
|
||||
janet_vm.scratch_mem[i] = news;
|
||||
return (char *)(news->mem);
|
||||
}
|
||||
if (i == 0) break;
|
||||
@ -568,10 +546,10 @@ void janet_sfinalizer(void *mem, JanetScratchFinalizer finalizer) {
|
||||
void janet_sfree(void *mem) {
|
||||
if (NULL == mem) return;
|
||||
JanetScratch *s = janet_mem2scratch(mem);
|
||||
if (janet_scratch_len) {
|
||||
for (size_t i = janet_scratch_len - 1; ; i--) {
|
||||
if (janet_scratch_mem[i] == s) {
|
||||
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len];
|
||||
if (janet_vm.scratch_len) {
|
||||
for (size_t i = janet_vm.scratch_len - 1; ; i--) {
|
||||
if (janet_vm.scratch_mem[i] == s) {
|
||||
janet_vm.scratch_mem[i] = janet_vm.scratch_mem[--janet_vm.scratch_len];
|
||||
free_one_scratch(s);
|
||||
return;
|
||||
}
|
||||
|
@ -23,13 +23,12 @@
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static JANET_THREAD_LOCAL JanetRNG janet_vm_rng = {0, 0, 0, 0, 0};
|
||||
|
||||
static int janet_rng_get(void *p, Janet key, Janet *out);
|
||||
static Janet janet_rng_next(void *p, Janet key);
|
||||
|
||||
@ -69,7 +68,7 @@ const JanetAbstractType janet_rng_type = {
|
||||
};
|
||||
|
||||
JanetRNG *janet_default_rng(void) {
|
||||
return &janet_vm_rng;
|
||||
return &janet_vm.rng;
|
||||
}
|
||||
|
||||
void janet_rng_seed(JanetRNG *rng, uint32_t seed) {
|
||||
@ -217,7 +216,7 @@ static Janet janet_rng_next(void *p, Janet key) {
|
||||
static Janet janet_rand(int32_t argc, Janet *argv) {
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
return janet_wrap_number(janet_rng_double(&janet_vm_rng));
|
||||
return janet_wrap_number(janet_rng_double(&janet_vm.rng));
|
||||
}
|
||||
|
||||
/* Seed the random number generator */
|
||||
@ -225,10 +224,10 @@ static Janet janet_srand(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
if (janet_checkint(argv[0])) {
|
||||
uint32_t seed = (uint32_t)(janet_getinteger(argv, 0));
|
||||
janet_rng_seed(&janet_vm_rng, seed);
|
||||
janet_rng_seed(&janet_vm.rng, seed);
|
||||
} else {
|
||||
JanetByteView bytes = janet_getbytes(argv, 0);
|
||||
janet_rng_longseed(&janet_vm_rng, bytes.bytes, bytes.len);
|
||||
janet_rng_longseed(&janet_vm.rng, bytes.bytes, bytes.len);
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ void janet_to_string_b(JanetBuffer *buffer, Janet x) {
|
||||
}
|
||||
return;
|
||||
case JANET_CFUNCTION: {
|
||||
Janet check = janet_table_get(janet_vm_registry, x);
|
||||
Janet check = janet_table_get(janet_vm.registry, x);
|
||||
if (janet_checktype(check, JANET_SYMBOL)) {
|
||||
janet_buffer_push_cstring(buffer, "<cfunction ");
|
||||
janet_buffer_push_bytes(buffer,
|
||||
|
49
src/core/state.c
Normal file
49
src/core/state.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JANET_AMALG
|
||||
#include "features.h"
|
||||
#include <janet.h>
|
||||
#include "state.h"
|
||||
#endif
|
||||
|
||||
JANET_THREAD_LOCAL JanetVM janet_vm;
|
||||
|
||||
JanetVM *janet_vm_alloc(void) {
|
||||
JanetVM *mem = janet_malloc(sizeof(JanetVM));
|
||||
if (NULL == mem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void janet_vm_free(JanetVM *vm) {
|
||||
janet_free(vm);
|
||||
}
|
||||
|
||||
void janet_vm_save(JanetVM *into) {
|
||||
*into = janet_vm;
|
||||
}
|
||||
|
||||
void janet_vm_load(JanetVM *from) {
|
||||
janet_vm = *from;
|
||||
}
|
182
src/core/state.h
182
src/core/state.h
@ -25,75 +25,135 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* The VM state. Rather than a struct that is passed
|
||||
* around, the vm state is global for simplicity. If
|
||||
* at some point a global state object, or context,
|
||||
* is required to be passed around, this is what would
|
||||
* be in it. However, thread local global variables for interpreter
|
||||
* state should allow easy multi-threading. */
|
||||
typedef int64_t JanetTimestamp;
|
||||
|
||||
typedef struct JanetScratch JanetScratch;
|
||||
typedef struct JanetScratch {
|
||||
JanetScratchFinalizer finalize;
|
||||
long long mem[]; /* for proper alignment */
|
||||
} JanetScratch;
|
||||
|
||||
/* Top level dynamic bindings */
|
||||
extern JANET_THREAD_LOCAL JanetTable *janet_vm_top_dyns;
|
||||
|
||||
/* Cache the core environment */
|
||||
extern JANET_THREAD_LOCAL JanetTable *janet_vm_core_env;
|
||||
|
||||
/* How many VM stacks have been entered */
|
||||
extern JANET_THREAD_LOCAL int janet_vm_stackn;
|
||||
|
||||
/* The current running fiber on the current thread.
|
||||
* Set and unset by janet_run. */
|
||||
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
|
||||
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_root_fiber;
|
||||
|
||||
/* The current pointer to the inner most jmp_buf. The current
|
||||
* return point for panics. */
|
||||
extern JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf;
|
||||
extern JANET_THREAD_LOCAL Janet *janet_vm_return_reg;
|
||||
|
||||
/* The global registry for c functions. Used to store meta-data
|
||||
* along with otherwise bare c function pointers. */
|
||||
extern JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
||||
|
||||
/* Registry for abstract abstract types that can be marshalled.
|
||||
* We need this to look up the constructors when unmarshalling. */
|
||||
extern JANET_THREAD_LOCAL JanetTable *janet_vm_abstract_registry;
|
||||
|
||||
/* Immutable value cache */
|
||||
extern JANET_THREAD_LOCAL const uint8_t **janet_vm_cache;
|
||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_capacity;
|
||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_count;
|
||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_deleted;
|
||||
|
||||
/* Garbage collection */
|
||||
extern JANET_THREAD_LOCAL void *janet_vm_blocks;
|
||||
extern JANET_THREAD_LOCAL size_t janet_vm_gc_interval;
|
||||
extern JANET_THREAD_LOCAL size_t janet_vm_next_collection;
|
||||
extern JANET_THREAD_LOCAL size_t janet_vm_block_count;
|
||||
extern JANET_THREAD_LOCAL int janet_vm_gc_suspend;
|
||||
|
||||
/* GC roots */
|
||||
extern JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
||||
extern JANET_THREAD_LOCAL size_t janet_vm_root_count;
|
||||
extern JANET_THREAD_LOCAL size_t janet_vm_root_capacity;
|
||||
|
||||
/* Scratch memory */
|
||||
extern JANET_THREAD_LOCAL JanetScratch **janet_scratch_mem;
|
||||
extern JANET_THREAD_LOCAL size_t janet_scratch_cap;
|
||||
extern JANET_THREAD_LOCAL size_t janet_scratch_len;
|
||||
|
||||
/* Recursionless traversal of data structures */
|
||||
typedef struct {
|
||||
JanetGCObject *self;
|
||||
JanetGCObject *other;
|
||||
int32_t index;
|
||||
int32_t index2;
|
||||
} JanetTraversalNode;
|
||||
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal;
|
||||
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_top;
|
||||
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_base;
|
||||
|
||||
typedef struct {
|
||||
int32_t capacity;
|
||||
int32_t head;
|
||||
int32_t tail;
|
||||
void *data;
|
||||
} JanetQueue;
|
||||
|
||||
typedef struct {
|
||||
JanetTimestamp when;
|
||||
JanetFiber *fiber;
|
||||
JanetFiber *curr_fiber;
|
||||
uint32_t sched_id;
|
||||
int is_error;
|
||||
} JanetTimeout;
|
||||
|
||||
typedef struct {
|
||||
JanetMailbox *original;
|
||||
JanetMailbox *newbox;
|
||||
uint64_t flags;
|
||||
} JanetMailboxPair;
|
||||
|
||||
struct JanetVM {
|
||||
/* Top level dynamic bindings */
|
||||
JanetTable *top_dyns;
|
||||
|
||||
/* Cache the core environment */
|
||||
JanetTable *core_env;
|
||||
|
||||
/* How many VM stacks have been entered */
|
||||
int stackn;
|
||||
|
||||
/* The current running fiber on the current thread.
|
||||
* Set and unset by janet_run. */
|
||||
JanetFiber *fiber;
|
||||
JanetFiber *root_fiber;
|
||||
|
||||
/* The current pointer to the inner most jmp_buf. The current
|
||||
* return point for panics. */
|
||||
jmp_buf *signal_buf;
|
||||
Janet *return_reg;
|
||||
|
||||
/* The global registry for c functions. Used to store meta-data
|
||||
* along with otherwise bare c function pointers. */
|
||||
JanetTable *registry;
|
||||
|
||||
/* Registry for abstract abstract types that can be marshalled.
|
||||
* We need this to look up the constructors when unmarshalling. */
|
||||
JanetTable *abstract_registry;
|
||||
|
||||
/* Immutable value cache */
|
||||
const uint8_t **cache;
|
||||
uint32_t cache_capacity;
|
||||
uint32_t cache_count;
|
||||
uint32_t cache_deleted;
|
||||
uint8_t gensym_counter[8];
|
||||
|
||||
/* Garbage collection */
|
||||
void *blocks;
|
||||
size_t gc_interval;
|
||||
size_t next_collection;
|
||||
size_t block_count;
|
||||
int gc_suspend;
|
||||
|
||||
/* GC roots */
|
||||
Janet *roots;
|
||||
size_t root_count;
|
||||
size_t root_capacity;
|
||||
|
||||
/* Scratch memory */
|
||||
JanetScratch **scratch_mem;
|
||||
size_t scratch_cap;
|
||||
size_t scratch_len;
|
||||
|
||||
/* Random number generator */
|
||||
JanetRNG rng;
|
||||
|
||||
/* Traversal pointers */
|
||||
JanetTraversalNode *traversal;
|
||||
JanetTraversalNode *traversal_top;
|
||||
JanetTraversalNode *traversal_base;
|
||||
|
||||
/* Threading */
|
||||
#ifndef JANET_SINGLE_THREADED
|
||||
JanetMailbox *mailbox;
|
||||
JanetThread *thread_current;
|
||||
JanetTable *thread_decode;
|
||||
#endif
|
||||
|
||||
/* Event loop and scheduler globals */
|
||||
#ifdef JANET_EV
|
||||
size_t tq_count;
|
||||
size_t tq_capacity;
|
||||
JanetQueue spawn;
|
||||
JanetTimeout *tq;
|
||||
JanetRNG ev_rng;
|
||||
JanetListenerState **listeners;
|
||||
size_t listener_count;
|
||||
size_t listener_cap;
|
||||
size_t extra_listeners;
|
||||
#ifdef JANET_WINDOWS
|
||||
HANDLE iocp;
|
||||
#elif defined(JANET_EV_EPOLL)
|
||||
JanetHandle selfpipe[2];
|
||||
int epoll;
|
||||
int timerfd;
|
||||
int timer_enabled;
|
||||
#else
|
||||
JanetHandle selfpipe[2];
|
||||
struct pollfd *fds;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern JANET_THREAD_LOCAL JanetVM janet_vm;
|
||||
|
||||
/* Setup / teardown */
|
||||
#ifdef JANET_THREADS
|
||||
|
@ -36,30 +36,25 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Cache state */
|
||||
JANET_THREAD_LOCAL const uint8_t **janet_vm_cache = NULL;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_cache_capacity = 0;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_cache_count = 0;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_cache_deleted = 0;
|
||||
|
||||
/* Initialize the cache (allocate cache memory) */
|
||||
void janet_symcache_init() {
|
||||
janet_vm_cache_capacity = 1024;
|
||||
janet_vm_cache = janet_calloc(1, (size_t) janet_vm_cache_capacity * sizeof(const uint8_t *));
|
||||
if (NULL == janet_vm_cache) {
|
||||
janet_vm.cache_capacity = 1024;
|
||||
janet_vm.cache = janet_calloc(1, (size_t) janet_vm.cache_capacity * sizeof(const uint8_t *));
|
||||
if (NULL == janet_vm.cache) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_cache_count = 0;
|
||||
janet_vm_cache_deleted = 0;
|
||||
memset(&janet_vm.gensym_counter, 0, sizeof(janet_vm.gensym_counter));
|
||||
janet_vm.cache_count = 0;
|
||||
janet_vm.cache_deleted = 0;
|
||||
}
|
||||
|
||||
/* Deinitialize the cache (free the cache memory) */
|
||||
void janet_symcache_deinit() {
|
||||
janet_free((void *)janet_vm_cache);
|
||||
janet_vm_cache = NULL;
|
||||
janet_vm_cache_capacity = 0;
|
||||
janet_vm_cache_count = 0;
|
||||
janet_vm_cache_deleted = 0;
|
||||
janet_free((void *)janet_vm.cache);
|
||||
janet_vm.cache = NULL;
|
||||
janet_vm.cache_capacity = 0;
|
||||
janet_vm.cache_count = 0;
|
||||
janet_vm.cache_deleted = 0;
|
||||
}
|
||||
|
||||
/* Mark an entry in the table as deleted. */
|
||||
@ -79,24 +74,24 @@ static const uint8_t **janet_symcache_findmem(
|
||||
|
||||
/* We will search two ranges - index to the end,
|
||||
* and 0 to the index. */
|
||||
index = (uint32_t)hash & (janet_vm_cache_capacity - 1);
|
||||
index = (uint32_t)hash & (janet_vm.cache_capacity - 1);
|
||||
bounds[0] = index;
|
||||
bounds[1] = janet_vm_cache_capacity;
|
||||
bounds[1] = janet_vm.cache_capacity;
|
||||
bounds[2] = 0;
|
||||
bounds[3] = index;
|
||||
for (j = 0; j < 4; j += 2)
|
||||
for (i = bounds[j]; i < bounds[j + 1]; ++i) {
|
||||
const uint8_t *test = janet_vm_cache[i];
|
||||
const uint8_t *test = janet_vm.cache[i];
|
||||
/* Check empty spots */
|
||||
if (NULL == test) {
|
||||
if (NULL == firstEmpty)
|
||||
firstEmpty = janet_vm_cache + i;
|
||||
firstEmpty = janet_vm.cache + i;
|
||||
goto notfound;
|
||||
}
|
||||
/* Check for marked deleted */
|
||||
if (JANET_SYMCACHE_DELETED == test) {
|
||||
if (firstEmpty == NULL)
|
||||
firstEmpty = janet_vm_cache + i;
|
||||
firstEmpty = janet_vm.cache + i;
|
||||
continue;
|
||||
}
|
||||
if (janet_string_equalconst(test, str, len, hash)) {
|
||||
@ -104,10 +99,10 @@ static const uint8_t **janet_symcache_findmem(
|
||||
*success = 1;
|
||||
if (firstEmpty != NULL) {
|
||||
*firstEmpty = test;
|
||||
janet_vm_cache[i] = JANET_SYMCACHE_DELETED;
|
||||
janet_vm.cache[i] = JANET_SYMCACHE_DELETED;
|
||||
return firstEmpty;
|
||||
}
|
||||
return janet_vm_cache + i;
|
||||
return janet_vm.cache + i;
|
||||
}
|
||||
}
|
||||
notfound:
|
||||
@ -121,15 +116,15 @@ notfound:
|
||||
/* Resize the cache. */
|
||||
static void janet_cache_resize(uint32_t newCapacity) {
|
||||
uint32_t i, oldCapacity;
|
||||
const uint8_t **oldCache = janet_vm_cache;
|
||||
const uint8_t **oldCache = janet_vm.cache;
|
||||
const uint8_t **newCache = janet_calloc(1, (size_t) newCapacity * sizeof(const uint8_t *));
|
||||
if (newCache == NULL) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
oldCapacity = janet_vm_cache_capacity;
|
||||
janet_vm_cache = newCache;
|
||||
janet_vm_cache_capacity = newCapacity;
|
||||
janet_vm_cache_deleted = 0;
|
||||
oldCapacity = janet_vm.cache_capacity;
|
||||
janet_vm.cache = newCache;
|
||||
janet_vm.cache_capacity = newCapacity;
|
||||
janet_vm.cache_deleted = 0;
|
||||
/* Add all of the old cache entries back */
|
||||
for (i = 0; i < oldCapacity; ++i) {
|
||||
int status;
|
||||
@ -150,13 +145,13 @@ static void janet_cache_resize(uint32_t newCapacity) {
|
||||
|
||||
/* Add an item to the cache */
|
||||
static void janet_symcache_put(const uint8_t *x, const uint8_t **bucket) {
|
||||
if ((janet_vm_cache_count + janet_vm_cache_deleted) * 2 > janet_vm_cache_capacity) {
|
||||
if ((janet_vm.cache_count + janet_vm.cache_deleted) * 2 > janet_vm.cache_capacity) {
|
||||
int status;
|
||||
janet_cache_resize(janet_tablen((2 * janet_vm_cache_count + 1)));
|
||||
janet_cache_resize(janet_tablen((2 * janet_vm.cache_count + 1)));
|
||||
bucket = janet_symcache_find(x, &status);
|
||||
}
|
||||
/* Add x to the cache */
|
||||
janet_vm_cache_count++;
|
||||
janet_vm.cache_count++;
|
||||
*bucket = x;
|
||||
}
|
||||
|
||||
@ -165,8 +160,8 @@ void janet_symbol_deinit(const uint8_t *sym) {
|
||||
int status = 0;
|
||||
const uint8_t **bucket = janet_symcache_find(sym, &status);
|
||||
if (status) {
|
||||
janet_vm_cache_count--;
|
||||
janet_vm_cache_deleted++;
|
||||
janet_vm.cache_count--;
|
||||
janet_vm.cache_deleted++;
|
||||
*bucket = JANET_SYMCACHE_DELETED;
|
||||
}
|
||||
}
|
||||
@ -194,22 +189,19 @@ const uint8_t *janet_csymbol(const char *cstr) {
|
||||
return janet_symbol((const uint8_t *)cstr, (int32_t) strlen(cstr));
|
||||
}
|
||||
|
||||
/* Store counter for genysm to avoid quadratic behavior */
|
||||
JANET_THREAD_LOCAL uint8_t gensym_counter[8] = {'_', '0', '0', '0', '0', '0', '0', 0};
|
||||
|
||||
/* Increment the gensym buffer */
|
||||
static void inc_gensym(void) {
|
||||
for (int i = sizeof(gensym_counter) - 2; i; i--) {
|
||||
if (gensym_counter[i] == '9') {
|
||||
gensym_counter[i] = 'a';
|
||||
for (int i = sizeof(janet_vm.gensym_counter) - 2; i; i--) {
|
||||
if (janet_vm.gensym_counter[i] == '9') {
|
||||
janet_vm.gensym_counter[i] = 'a';
|
||||
break;
|
||||
} else if (gensym_counter[i] == 'z') {
|
||||
gensym_counter[i] = 'A';
|
||||
} else if (janet_vm.gensym_counter[i] == 'z') {
|
||||
janet_vm.gensym_counter[i] = 'A';
|
||||
break;
|
||||
} else if (gensym_counter[i] == 'Z') {
|
||||
gensym_counter[i] = '0';
|
||||
} else if (janet_vm.gensym_counter[i] == 'Z') {
|
||||
janet_vm.gensym_counter[i] = '0';
|
||||
} else {
|
||||
gensym_counter[i]++;
|
||||
janet_vm.gensym_counter[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -227,19 +219,19 @@ const uint8_t *janet_symbol_gen(void) {
|
||||
* is enough for resolving collisions. */
|
||||
do {
|
||||
hash = janet_string_calchash(
|
||||
gensym_counter,
|
||||
sizeof(gensym_counter) - 1);
|
||||
janet_vm.gensym_counter,
|
||||
sizeof(janet_vm.gensym_counter) - 1);
|
||||
bucket = janet_symcache_findmem(
|
||||
gensym_counter,
|
||||
sizeof(gensym_counter) - 1,
|
||||
janet_vm.gensym_counter,
|
||||
sizeof(janet_vm.gensym_counter) - 1,
|
||||
hash,
|
||||
&status);
|
||||
} while (status && (inc_gensym(), 1));
|
||||
JanetStringHead *head = janet_gcalloc(JANET_MEMORY_SYMBOL, sizeof(JanetStringHead) + sizeof(gensym_counter));
|
||||
head->length = sizeof(gensym_counter) - 1;
|
||||
JanetStringHead *head = janet_gcalloc(JANET_MEMORY_SYMBOL, sizeof(JanetStringHead) + sizeof(janet_vm.gensym_counter));
|
||||
head->length = sizeof(janet_vm.gensym_counter) - 1;
|
||||
head->hash = hash;
|
||||
sym = (uint8_t *)(head->data);
|
||||
memcpy(sym, gensym_counter, sizeof(gensym_counter));
|
||||
memcpy(sym, janet_vm.gensym_counter, sizeof(janet_vm.gensym_counter));
|
||||
janet_symcache_put((const uint8_t *)sym, bucket);
|
||||
return (const uint8_t *)sym;
|
||||
}
|
||||
|
@ -71,25 +71,15 @@ struct JanetMailbox {
|
||||
#define JANET_THREAD_CFUNCTIONS 0x4
|
||||
static const char janet_thread_flags[] = "hac";
|
||||
|
||||
typedef struct {
|
||||
JanetMailbox *original;
|
||||
JanetMailbox *newbox;
|
||||
uint64_t flags;
|
||||
} JanetMailboxPair;
|
||||
|
||||
static JANET_THREAD_LOCAL JanetMailbox *janet_vm_mailbox = NULL;
|
||||
static JANET_THREAD_LOCAL JanetThread *janet_vm_thread_current = NULL;
|
||||
static JANET_THREAD_LOCAL JanetTable *janet_vm_thread_decode = NULL;
|
||||
|
||||
static JanetTable *janet_thread_get_decode(void) {
|
||||
if (janet_vm_thread_decode == NULL) {
|
||||
janet_vm_thread_decode = janet_get_core_table("load-image-dict");
|
||||
if (NULL == janet_vm_thread_decode) {
|
||||
janet_vm_thread_decode = janet_table(0);
|
||||
if (janet_vm.thread_decode == NULL) {
|
||||
janet_vm.thread_decode = janet_get_core_table("load-image-dict");
|
||||
if (NULL == janet_vm.thread_decode) {
|
||||
janet_vm.thread_decode = janet_table(0);
|
||||
}
|
||||
janet_gcroot(janet_wrap_table(janet_vm_thread_decode));
|
||||
janet_gcroot(janet_wrap_table(janet_vm.thread_decode));
|
||||
}
|
||||
return janet_vm_thread_decode;
|
||||
return janet_vm.thread_decode;
|
||||
}
|
||||
|
||||
static JanetMailbox *janet_mailbox_create(int refCount, uint16_t capacity) {
|
||||
@ -326,8 +316,8 @@ int janet_thread_send(JanetThread *thread, Janet msg, double timeout) {
|
||||
/* Hack to capture all panics from marshalling. This works because
|
||||
* we know janet_marshal won't mess with other essential global state. */
|
||||
jmp_buf buf;
|
||||
jmp_buf *old_buf = janet_vm_jmp_buf;
|
||||
janet_vm_jmp_buf = &buf;
|
||||
jmp_buf *old_buf = janet_vm.signal_buf;
|
||||
janet_vm.signal_buf = &buf;
|
||||
int32_t oldmcount = mailbox->messageCount;
|
||||
|
||||
int ret = 0;
|
||||
@ -347,7 +337,7 @@ int janet_thread_send(JanetThread *thread, Janet msg, double timeout) {
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
janet_vm_jmp_buf = old_buf;
|
||||
janet_vm.signal_buf = old_buf;
|
||||
janet_mailbox_unlock(mailbox);
|
||||
|
||||
/* Potentially wake up a blocked thread */
|
||||
@ -358,7 +348,7 @@ int janet_thread_send(JanetThread *thread, Janet msg, double timeout) {
|
||||
|
||||
/* Returns 0 on successful message. Returns 1 if timedout */
|
||||
int janet_thread_receive(Janet *msg_out, double timeout) {
|
||||
JanetMailbox *mailbox = janet_vm_mailbox;
|
||||
JanetMailbox *mailbox = janet_vm.mailbox;
|
||||
janet_mailbox_lock(mailbox);
|
||||
|
||||
/* For timeouts */
|
||||
@ -373,15 +363,15 @@ int janet_thread_receive(Janet *msg_out, double timeout) {
|
||||
/* Hack to capture all panics from marshalling. This works because
|
||||
* we know janet_marshal won't mess with other essential global state. */
|
||||
jmp_buf buf;
|
||||
jmp_buf *old_buf = janet_vm_jmp_buf;
|
||||
janet_vm_jmp_buf = &buf;
|
||||
jmp_buf *old_buf = janet_vm.signal_buf;
|
||||
janet_vm.signal_buf = &buf;
|
||||
|
||||
/* Handle errors */
|
||||
if (setjmp(buf)) {
|
||||
/* Cleanup jmp_buf, return error.
|
||||
* Do not ignore bad messages as before. */
|
||||
janet_vm_jmp_buf = old_buf;
|
||||
*msg_out = *janet_vm_return_reg;
|
||||
janet_vm.signal_buf = old_buf;
|
||||
*msg_out = *janet_vm.return_reg;
|
||||
janet_mailbox_unlock(mailbox);
|
||||
return 2;
|
||||
} else {
|
||||
@ -397,7 +387,7 @@ int janet_thread_receive(Janet *msg_out, double timeout) {
|
||||
*msg_out = item;
|
||||
|
||||
/* Cleanup */
|
||||
janet_vm_jmp_buf = old_buf;
|
||||
janet_vm.signal_buf = old_buf;
|
||||
janet_mailbox_unlock(mailbox);
|
||||
|
||||
/* Potentially wake up pending threads */
|
||||
@ -455,21 +445,21 @@ static int thread_worker(JanetMailboxPair *pair) {
|
||||
JanetFiber *fiber = NULL;
|
||||
Janet out;
|
||||
|
||||
/* Use the mailbox we were given */
|
||||
janet_vm_mailbox = pair->newbox;
|
||||
janet_mailbox_ref(pair->newbox, 1);
|
||||
|
||||
/* Init VM */
|
||||
janet_init();
|
||||
|
||||
/* Use the mailbox we were given */
|
||||
janet_vm.mailbox = pair->newbox;
|
||||
janet_mailbox_ref(pair->newbox, 1);
|
||||
|
||||
/* Get dictionaries for default encode/decode */
|
||||
JanetTable *encode;
|
||||
if (pair->flags & JANET_THREAD_HEAVYWEIGHT) {
|
||||
encode = janet_get_core_table("make-image-dict");
|
||||
} else {
|
||||
encode = NULL;
|
||||
janet_vm_thread_decode = janet_table(0);
|
||||
janet_gcroot(janet_wrap_table(janet_vm_thread_decode));
|
||||
janet_vm.thread_decode = janet_table(0);
|
||||
janet_gcroot(janet_wrap_table(janet_vm.thread_decode));
|
||||
}
|
||||
|
||||
/* Create parent thread */
|
||||
@ -482,9 +472,9 @@ static int thread_worker(JanetMailboxPair *pair) {
|
||||
int status = janet_thread_receive(®, INFINITY);
|
||||
if (status) goto error;
|
||||
if (!janet_checktype(reg, JANET_TABLE)) goto error;
|
||||
janet_gcunroot(janet_wrap_table(janet_vm_abstract_registry));
|
||||
janet_vm_abstract_registry = janet_unwrap_table(reg);
|
||||
janet_gcroot(janet_wrap_table(janet_vm_abstract_registry));
|
||||
janet_gcunroot(janet_wrap_table(janet_vm.abstract_registry));
|
||||
janet_vm.abstract_registry = janet_unwrap_table(reg);
|
||||
janet_gcroot(janet_wrap_table(janet_vm.abstract_registry));
|
||||
}
|
||||
|
||||
/* Unmarshal the normal registry */
|
||||
@ -493,9 +483,9 @@ static int thread_worker(JanetMailboxPair *pair) {
|
||||
int status = janet_thread_receive(®, INFINITY);
|
||||
if (status) goto error;
|
||||
if (!janet_checktype(reg, JANET_TABLE)) goto error;
|
||||
janet_gcunroot(janet_wrap_table(janet_vm_registry));
|
||||
janet_vm_registry = janet_unwrap_table(reg);
|
||||
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
||||
janet_gcunroot(janet_wrap_table(janet_vm.registry));
|
||||
janet_vm.registry = janet_unwrap_table(reg);
|
||||
janet_gcroot(janet_wrap_table(janet_vm.registry));
|
||||
}
|
||||
|
||||
/* Unmarshal the function */
|
||||
@ -580,28 +570,26 @@ static int janet_thread_start_child(JanetMailboxPair *pair) {
|
||||
*/
|
||||
|
||||
void janet_threads_init(void) {
|
||||
if (NULL == janet_vm_mailbox) {
|
||||
janet_vm_mailbox = janet_mailbox_create(1, 10);
|
||||
}
|
||||
janet_vm_thread_decode = NULL;
|
||||
janet_vm_thread_current = NULL;
|
||||
janet_vm.mailbox = janet_mailbox_create(1, 10);
|
||||
janet_vm.thread_decode = NULL;
|
||||
janet_vm.thread_current = NULL;
|
||||
}
|
||||
|
||||
void janet_threads_deinit(void) {
|
||||
janet_mailbox_lock(janet_vm_mailbox);
|
||||
janet_vm_mailbox->closed = 1;
|
||||
janet_mailbox_ref_with_lock(janet_vm_mailbox, -1);
|
||||
janet_vm_mailbox = NULL;
|
||||
janet_vm_thread_current = NULL;
|
||||
janet_vm_thread_decode = NULL;
|
||||
janet_mailbox_lock(janet_vm.mailbox);
|
||||
janet_vm.mailbox->closed = 1;
|
||||
janet_mailbox_ref_with_lock(janet_vm.mailbox, -1);
|
||||
janet_vm.mailbox = NULL;
|
||||
janet_vm.thread_current = NULL;
|
||||
janet_vm.thread_decode = NULL;
|
||||
}
|
||||
|
||||
JanetThread *janet_thread_current(void) {
|
||||
if (NULL == janet_vm_thread_current) {
|
||||
janet_vm_thread_current = janet_make_thread(janet_vm_mailbox, janet_get_core_table("make-image-dict"));
|
||||
janet_gcroot(janet_wrap_abstract(janet_vm_thread_current));
|
||||
if (NULL == janet_vm.thread_current) {
|
||||
janet_vm.thread_current = janet_make_thread(janet_vm.mailbox, janet_get_core_table("make-image-dict"));
|
||||
janet_gcroot(janet_wrap_abstract(janet_vm.thread_current));
|
||||
}
|
||||
return janet_vm_thread_current;
|
||||
return janet_vm.thread_current;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -630,7 +618,7 @@ static Janet cfun_thread_new(int32_t argc, Janet *argv) {
|
||||
encode = NULL;
|
||||
}
|
||||
|
||||
JanetMailboxPair *pair = make_mailbox_pair(janet_vm_mailbox, flags);
|
||||
JanetMailboxPair *pair = make_mailbox_pair(janet_vm.mailbox, flags);
|
||||
JanetThread *thread = janet_make_thread(pair->newbox, encode);
|
||||
if (janet_thread_start_child(pair)) {
|
||||
destroy_mailbox_pair(pair);
|
||||
@ -638,13 +626,13 @@ static Janet cfun_thread_new(int32_t argc, Janet *argv) {
|
||||
}
|
||||
|
||||
if (flags & JANET_THREAD_ABSTRACTS) {
|
||||
if (janet_thread_send(thread, janet_wrap_table(janet_vm_abstract_registry), INFINITY)) {
|
||||
if (janet_thread_send(thread, janet_wrap_table(janet_vm.abstract_registry), INFINITY)) {
|
||||
janet_panic("could not send abstract registry to thread");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & JANET_THREAD_CFUNCTIONS) {
|
||||
if (janet_thread_send(thread, janet_wrap_table(janet_vm_registry), INFINITY)) {
|
||||
if (janet_thread_send(thread, janet_wrap_table(janet_vm.registry), INFINITY)) {
|
||||
janet_panic("could not send registry to thread");
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ const void *janet_strbinsearch(
|
||||
void janet_register(const char *name, JanetCFunction cfun) {
|
||||
Janet key = janet_wrap_cfunction(cfun);
|
||||
Janet value = janet_csymbolv(name);
|
||||
janet_table_put(janet_vm_registry, key, value);
|
||||
janet_table_put(janet_vm.registry, key, value);
|
||||
}
|
||||
|
||||
/* Add a def to an environment */
|
||||
@ -433,7 +433,7 @@ static void _janet_cfuns_prefix(JanetTable *env, const char *regprefix, const Ja
|
||||
} else {
|
||||
janet_def(env, cfuns->name, fun, cfuns->documentation);
|
||||
}
|
||||
janet_table_put(janet_vm_registry, fun, name);
|
||||
janet_table_put(janet_vm.registry, fun, name);
|
||||
cfuns++;
|
||||
}
|
||||
(janet_free)(longname_buffer);
|
||||
@ -451,16 +451,16 @@ void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns)
|
||||
|
||||
void janet_register_abstract_type(const JanetAbstractType *at) {
|
||||
Janet sym = janet_csymbolv(at->name);
|
||||
Janet check = janet_table_get(janet_vm_abstract_registry, sym);
|
||||
Janet check = janet_table_get(janet_vm.abstract_registry, sym);
|
||||
if (!janet_checktype(check, JANET_NIL) && at != janet_unwrap_pointer(check)) {
|
||||
janet_panicf("cannot register abstract type %s, "
|
||||
"a type with the same name exists", at->name);
|
||||
}
|
||||
janet_table_put(janet_vm_abstract_registry, sym, janet_wrap_pointer((void *) at));
|
||||
janet_table_put(janet_vm.abstract_registry, sym, janet_wrap_pointer((void *) at));
|
||||
}
|
||||
|
||||
const JanetAbstractType *janet_get_abstract_type(Janet key) {
|
||||
Janet wrapped = janet_table_get(janet_vm_abstract_registry, key);
|
||||
Janet wrapped = janet_table_get(janet_vm.abstract_registry, key);
|
||||
if (janet_checktype(wrapped, JANET_NIL)) {
|
||||
return NULL;
|
||||
}
|
||||
@ -473,7 +473,7 @@ void janet_core_def(JanetTable *env, const char *name, Janet x, const void *p) {
|
||||
Janet key = janet_csymbolv(name);
|
||||
janet_table_put(env, key, x);
|
||||
if (janet_checktype(x, JANET_CFUNCTION)) {
|
||||
janet_table_put(janet_vm_registry, x, key);
|
||||
janet_table_put(janet_vm.registry, x, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,31 +31,27 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal = NULL;
|
||||
JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_top = NULL;
|
||||
JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_base = NULL;
|
||||
|
||||
static void push_traversal_node(void *lhs, void *rhs, int32_t index2) {
|
||||
JanetTraversalNode node;
|
||||
node.self = (JanetGCObject *) lhs;
|
||||
node.other = (JanetGCObject *) rhs;
|
||||
node.index = 0;
|
||||
node.index2 = index2;
|
||||
if (janet_vm_traversal + 1 >= janet_vm_traversal_top) {
|
||||
size_t oldsize = janet_vm_traversal - janet_vm_traversal_base;
|
||||
if (janet_vm.traversal + 1 >= janet_vm.traversal_top) {
|
||||
size_t oldsize = janet_vm.traversal - janet_vm.traversal_base;
|
||||
size_t newsize = 2 * oldsize + 1;
|
||||
if (newsize < 128) {
|
||||
newsize = 128;
|
||||
}
|
||||
JanetTraversalNode *tn = janet_realloc(janet_vm_traversal_base, newsize * sizeof(JanetTraversalNode));
|
||||
JanetTraversalNode *tn = janet_realloc(janet_vm.traversal_base, newsize * sizeof(JanetTraversalNode));
|
||||
if (tn == NULL) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_vm_traversal_base = tn;
|
||||
janet_vm_traversal_top = janet_vm_traversal_base + newsize;
|
||||
janet_vm_traversal = janet_vm_traversal_base + oldsize;
|
||||
janet_vm.traversal_base = tn;
|
||||
janet_vm.traversal_top = janet_vm.traversal_base + newsize;
|
||||
janet_vm.traversal = janet_vm.traversal_base + oldsize;
|
||||
}
|
||||
*(++janet_vm_traversal) = node;
|
||||
*(++janet_vm.traversal) = node;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -67,8 +63,8 @@ static void push_traversal_node(void *lhs, void *rhs, int32_t index2) {
|
||||
* 3 - early stop - lhs > rhs
|
||||
*/
|
||||
static int traversal_next(Janet *x, Janet *y) {
|
||||
JanetTraversalNode *t = janet_vm_traversal;
|
||||
while (t && t > janet_vm_traversal_base) {
|
||||
JanetTraversalNode *t = janet_vm.traversal;
|
||||
while (t && t > janet_vm.traversal_base) {
|
||||
JanetGCObject *self = t->self;
|
||||
JanetTupleHead *tself = (JanetTupleHead *)self;
|
||||
JanetStructHead *sself = (JanetStructHead *)self;
|
||||
@ -81,7 +77,7 @@ static int traversal_next(Janet *x, Janet *y) {
|
||||
int32_t index = t->index++;
|
||||
*x = tself->data[index];
|
||||
*y = tother->data[index];
|
||||
janet_vm_traversal = t;
|
||||
janet_vm.traversal = t;
|
||||
return 0;
|
||||
}
|
||||
if (t->index2 && tself->length != tother->length) {
|
||||
@ -94,20 +90,20 @@ static int traversal_next(Janet *x, Janet *y) {
|
||||
int32_t index = t->index++;
|
||||
*x = sself->data[index].value;
|
||||
*y = sother->data[index].value;
|
||||
janet_vm_traversal = t;
|
||||
janet_vm.traversal = t;
|
||||
return 0;
|
||||
}
|
||||
for (int32_t i = t->index; i < sself->capacity; i++) {
|
||||
t->index2 = 1;
|
||||
*x = sself->data[t->index].key;
|
||||
*y = sother->data[t->index].key;
|
||||
janet_vm_traversal = t;
|
||||
janet_vm.traversal = t;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
t--;
|
||||
}
|
||||
janet_vm_traversal = t;
|
||||
janet_vm.traversal = t;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -196,17 +192,17 @@ Janet janet_next_impl(Janet ds, Janet key, int is_interpreter) {
|
||||
status == JANET_STATUS_USER4) {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
janet_vm_fiber->child = child;
|
||||
janet_vm.fiber->child = child;
|
||||
JanetSignal sig = janet_continue(child, janet_wrap_nil(), &retreg);
|
||||
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
|
||||
if (is_interpreter) {
|
||||
janet_signalv(sig, retreg);
|
||||
} else {
|
||||
janet_vm_fiber->child = NULL;
|
||||
janet_vm.fiber->child = NULL;
|
||||
janet_panicv(retreg);
|
||||
}
|
||||
}
|
||||
janet_vm_fiber->child = NULL;
|
||||
janet_vm.fiber->child = NULL;
|
||||
if (sig == JANET_SIGNAL_OK ||
|
||||
sig == JANET_SIGNAL_ERROR ||
|
||||
sig == JANET_SIGNAL_USER0 ||
|
||||
@ -239,7 +235,7 @@ static int janet_compare_abstract(JanetAbstract xx, JanetAbstract yy) {
|
||||
}
|
||||
|
||||
int janet_equals(Janet x, Janet y) {
|
||||
janet_vm_traversal = janet_vm_traversal_base;
|
||||
janet_vm.traversal = janet_vm.traversal_base;
|
||||
do {
|
||||
if (janet_type(x) != janet_type(y)) return 0;
|
||||
switch (janet_type(x)) {
|
||||
@ -347,7 +343,7 @@ int32_t janet_hash(Janet x) {
|
||||
* If y is less, returns 1. All types are comparable
|
||||
* and should have strict ordering, excepts NaNs. */
|
||||
int janet_compare(Janet x, Janet y) {
|
||||
janet_vm_traversal = janet_vm_traversal_base;
|
||||
janet_vm.traversal = janet_vm.traversal_base;
|
||||
int status;
|
||||
do {
|
||||
JanetType tx = janet_type(x);
|
||||
|
158
src/core/vm.c
158
src/core/vm.c
@ -32,17 +32,6 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* VM state */
|
||||
JANET_THREAD_LOCAL JanetTable *janet_vm_top_dyns;
|
||||
JANET_THREAD_LOCAL JanetTable *janet_vm_core_env;
|
||||
JANET_THREAD_LOCAL JanetTable *janet_vm_registry;
|
||||
JANET_THREAD_LOCAL JanetTable *janet_vm_abstract_registry;
|
||||
JANET_THREAD_LOCAL int janet_vm_stackn = 0;
|
||||
JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber = NULL;
|
||||
JANET_THREAD_LOCAL JanetFiber *janet_vm_root_fiber = NULL;
|
||||
JANET_THREAD_LOCAL Janet *janet_vm_return_reg = NULL;
|
||||
JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
||||
|
||||
/* Virtual registers
|
||||
*
|
||||
* One instruction word
|
||||
@ -91,18 +80,18 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
||||
func = janet_stack_frame(stack)->func; \
|
||||
} while (0)
|
||||
#define vm_return(sig, val) do { \
|
||||
janet_vm_return_reg[0] = (val); \
|
||||
janet_vm.return_reg[0] = (val); \
|
||||
vm_commit(); \
|
||||
return (sig); \
|
||||
} while (0)
|
||||
#define vm_return_no_restore(sig, val) do { \
|
||||
janet_vm_return_reg[0] = (val); \
|
||||
janet_vm.return_reg[0] = (val); \
|
||||
return (sig); \
|
||||
} while (0)
|
||||
|
||||
/* Next instruction variations */
|
||||
#define maybe_collect() do {\
|
||||
if (janet_vm_next_collection >= janet_vm_gc_interval) janet_collect(); } while (0)
|
||||
if (janet_vm.next_collection >= janet_vm.gc_interval) janet_collect(); } while (0)
|
||||
#define vm_checkgc_next() maybe_collect(); vm_next()
|
||||
#define vm_pcnext() pc++; vm_next()
|
||||
#define vm_checkgc_pcnext() maybe_collect(); vm_pcnext()
|
||||
@ -591,7 +580,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||
JanetSignal sig = (fiber->gc.flags & JANET_FIBER_STATUS_MASK) >> JANET_FIBER_STATUS_OFFSET;
|
||||
fiber->gc.flags &= ~JANET_FIBER_STATUS_MASK;
|
||||
fiber->flags &= ~(JANET_FIBER_RESUME_SIGNAL | JANET_FIBER_FLAG_MASK);
|
||||
janet_vm_return_reg[0] = in;
|
||||
janet_vm.return_reg[0] = in;
|
||||
return sig;
|
||||
}
|
||||
|
||||
@ -1279,9 +1268,9 @@ JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out) {
|
||||
|
||||
Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
||||
/* Check entry conditions */
|
||||
if (!janet_vm_fiber)
|
||||
if (!janet_vm.fiber)
|
||||
janet_panic("janet_call failed because there is no current fiber");
|
||||
if (janet_vm_stackn >= JANET_RECURSION_GUARD)
|
||||
if (janet_vm.stackn >= JANET_RECURSION_GUARD)
|
||||
janet_panic("C stack recursed too deeply");
|
||||
|
||||
/* Tracing */
|
||||
@ -1290,8 +1279,8 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
||||
}
|
||||
|
||||
/* Push frame */
|
||||
janet_fiber_pushn(janet_vm_fiber, argv, argc);
|
||||
if (janet_fiber_funcframe(janet_vm_fiber, fun)) {
|
||||
janet_fiber_pushn(janet_vm.fiber, argv, argc);
|
||||
if (janet_fiber_funcframe(janet_vm.fiber, fun)) {
|
||||
int32_t min = fun->def->min_arity;
|
||||
int32_t max = fun->def->max_arity;
|
||||
Janet funv = janet_wrap_function(fun);
|
||||
@ -1301,31 +1290,31 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
||||
janet_panicf("arity mismatch in %v, expected at least %d, got %d", funv, min, argc);
|
||||
janet_panicf("arity mismatch in %v, expected at most %d, got %d", funv, max, argc);
|
||||
}
|
||||
janet_fiber_frame(janet_vm_fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
|
||||
janet_fiber_frame(janet_vm.fiber)->flags |= JANET_STACKFRAME_ENTRANCE;
|
||||
|
||||
/* Set up */
|
||||
int32_t oldn = janet_vm_stackn++;
|
||||
int32_t oldn = janet_vm.stackn++;
|
||||
int handle = janet_gclock();
|
||||
|
||||
/* Run vm */
|
||||
janet_vm_fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
||||
JanetSignal signal = run_vm(janet_vm_fiber, janet_wrap_nil());
|
||||
janet_vm.fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
|
||||
JanetSignal signal = run_vm(janet_vm.fiber, janet_wrap_nil());
|
||||
|
||||
/* Teardown */
|
||||
janet_vm_stackn = oldn;
|
||||
janet_vm.stackn = oldn;
|
||||
janet_gcunlock(handle);
|
||||
|
||||
if (signal != JANET_SIGNAL_OK) {
|
||||
janet_panicv(*janet_vm_return_reg);
|
||||
janet_panicv(*janet_vm.return_reg);
|
||||
}
|
||||
|
||||
return *janet_vm_return_reg;
|
||||
return *janet_vm.return_reg;
|
||||
}
|
||||
|
||||
static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
|
||||
/* Check conditions */
|
||||
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
||||
if (janet_vm_stackn >= JANET_RECURSION_GUARD) {
|
||||
if (janet_vm.stackn >= JANET_RECURSION_GUARD) {
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_ERROR);
|
||||
*out = janet_cstringv("C stack recursed too deeply");
|
||||
return JANET_SIGNAL_ERROR;
|
||||
@ -1343,21 +1332,21 @@ static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
|
||||
}
|
||||
|
||||
void janet_try_init(JanetTryState *state) {
|
||||
state->stackn = janet_vm_stackn++;
|
||||
state->gc_handle = janet_vm_gc_suspend;
|
||||
state->vm_fiber = janet_vm_fiber;
|
||||
state->vm_jmp_buf = janet_vm_jmp_buf;
|
||||
state->vm_return_reg = janet_vm_return_reg;
|
||||
janet_vm_return_reg = &(state->payload);
|
||||
janet_vm_jmp_buf = &(state->buf);
|
||||
state->stackn = janet_vm.stackn++;
|
||||
state->gc_handle = janet_vm.gc_suspend;
|
||||
state->vm_fiber = janet_vm.fiber;
|
||||
state->vm_jmp_buf = janet_vm.signal_buf;
|
||||
state->vm_return_reg = janet_vm.return_reg;
|
||||
janet_vm.return_reg = &(state->payload);
|
||||
janet_vm.signal_buf = &(state->buf);
|
||||
}
|
||||
|
||||
void janet_restore(JanetTryState *state) {
|
||||
janet_vm_stackn = state->stackn;
|
||||
janet_vm_gc_suspend = state->gc_handle;
|
||||
janet_vm_fiber = state->vm_fiber;
|
||||
janet_vm_jmp_buf = state->vm_jmp_buf;
|
||||
janet_vm_return_reg = state->vm_return_reg;
|
||||
janet_vm.stackn = state->stackn;
|
||||
janet_vm.gc_suspend = state->gc_handle;
|
||||
janet_vm.fiber = state->vm_fiber;
|
||||
janet_vm.signal_buf = state->vm_jmp_buf;
|
||||
janet_vm.return_reg = state->vm_return_reg;
|
||||
}
|
||||
|
||||
static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out) {
|
||||
@ -1373,13 +1362,13 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
||||
|
||||
/* Continue child fiber if it exists */
|
||||
if (fiber->child) {
|
||||
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
|
||||
if (janet_vm.root_fiber == NULL) janet_vm.root_fiber = fiber;
|
||||
JanetFiber *child = fiber->child;
|
||||
uint32_t instr = (janet_stack_frame(fiber->data + fiber->frame)->pc)[0];
|
||||
janet_vm_stackn++;
|
||||
janet_vm.stackn++;
|
||||
JanetSignal sig = janet_continue(child, in, &in);
|
||||
janet_vm_stackn--;
|
||||
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
|
||||
janet_vm.stackn--;
|
||||
if (janet_vm.root_fiber == fiber) janet_vm.root_fiber = NULL;
|
||||
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
|
||||
*out = in;
|
||||
janet_fiber_set_status(fiber, sig);
|
||||
@ -1425,14 +1414,14 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
||||
JanetSignal sig = janet_try(&tstate);
|
||||
if (!sig) {
|
||||
/* Normal setup */
|
||||
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
|
||||
janet_vm_fiber = fiber;
|
||||
if (janet_vm.root_fiber == NULL) janet_vm.root_fiber = fiber;
|
||||
janet_vm.fiber = fiber;
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_ALIVE);
|
||||
sig = run_vm(fiber, in);
|
||||
}
|
||||
|
||||
/* Restore */
|
||||
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
|
||||
if (janet_vm.root_fiber == fiber) janet_vm.root_fiber = NULL;
|
||||
janet_fiber_set_status(fiber, sig);
|
||||
janet_restore(&tstate);
|
||||
fiber->last_value = tstate.payload;
|
||||
@ -1497,39 +1486,50 @@ Janet janet_mcall(const char *name, int32_t argc, Janet *argv) {
|
||||
|
||||
/* Setup VM */
|
||||
int janet_init(void) {
|
||||
|
||||
/* Garbage collection */
|
||||
janet_vm_blocks = NULL;
|
||||
janet_vm_next_collection = 0;
|
||||
janet_vm_gc_interval = 0x400000;
|
||||
janet_vm_block_count = 0;
|
||||
janet_vm.blocks = NULL;
|
||||
janet_vm.next_collection = 0;
|
||||
janet_vm.gc_interval = 0x400000;
|
||||
janet_vm.block_count = 0;
|
||||
|
||||
janet_symcache_init();
|
||||
|
||||
/* Initialize gc roots */
|
||||
janet_vm_roots = NULL;
|
||||
janet_vm_root_count = 0;
|
||||
janet_vm_root_capacity = 0;
|
||||
janet_vm.roots = NULL;
|
||||
janet_vm.root_count = 0;
|
||||
janet_vm.root_capacity = 0;
|
||||
|
||||
/* Scratch memory */
|
||||
janet_scratch_mem = NULL;
|
||||
janet_scratch_len = 0;
|
||||
janet_scratch_cap = 0;
|
||||
janet_vm.scratch_mem = NULL;
|
||||
janet_vm.scratch_len = 0;
|
||||
janet_vm.scratch_cap = 0;
|
||||
|
||||
/* Initialize registry */
|
||||
janet_vm_registry = janet_table(0);
|
||||
janet_vm_abstract_registry = janet_table(0);
|
||||
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
||||
janet_gcroot(janet_wrap_table(janet_vm_abstract_registry));
|
||||
janet_vm.registry = janet_table(0);
|
||||
janet_vm.abstract_registry = janet_table(0);
|
||||
janet_gcroot(janet_wrap_table(janet_vm.registry));
|
||||
janet_gcroot(janet_wrap_table(janet_vm.abstract_registry));
|
||||
|
||||
/* Traversal */
|
||||
janet_vm_traversal = NULL;
|
||||
janet_vm_traversal_base = NULL;
|
||||
janet_vm_traversal_top = NULL;
|
||||
janet_vm.traversal = NULL;
|
||||
janet_vm.traversal_base = NULL;
|
||||
janet_vm.traversal_top = NULL;
|
||||
|
||||
/* Core env */
|
||||
janet_vm_core_env = NULL;
|
||||
janet_vm.core_env = NULL;
|
||||
|
||||
/* Dynamic bindings */
|
||||
janet_vm_top_dyns = NULL;
|
||||
janet_vm.top_dyns = NULL;
|
||||
|
||||
/* Seed RNG */
|
||||
janet_rng_seed(janet_default_rng(), 0);
|
||||
|
||||
/* Fibers */
|
||||
janet_vm_fiber = NULL;
|
||||
janet_vm_root_fiber = NULL;
|
||||
janet_vm_stackn = 0;
|
||||
janet_vm.fiber = NULL;
|
||||
janet_vm.root_fiber = NULL;
|
||||
janet_vm.stackn = 0;
|
||||
|
||||
#ifdef JANET_THREADS
|
||||
janet_threads_init();
|
||||
#endif
|
||||
@ -1546,17 +1546,17 @@ int janet_init(void) {
|
||||
void janet_deinit(void) {
|
||||
janet_clear_memory();
|
||||
janet_symcache_deinit();
|
||||
janet_free(janet_vm_roots);
|
||||
janet_vm_roots = NULL;
|
||||
janet_vm_root_count = 0;
|
||||
janet_vm_root_capacity = 0;
|
||||
janet_vm_registry = NULL;
|
||||
janet_vm_abstract_registry = NULL;
|
||||
janet_vm_core_env = NULL;
|
||||
janet_vm_top_dyns = NULL;
|
||||
janet_free(janet_vm_traversal_base);
|
||||
janet_vm_fiber = NULL;
|
||||
janet_vm_root_fiber = NULL;
|
||||
janet_free(janet_vm.roots);
|
||||
janet_vm.roots = NULL;
|
||||
janet_vm.root_count = 0;
|
||||
janet_vm.root_capacity = 0;
|
||||
janet_vm.registry = NULL;
|
||||
janet_vm.abstract_registry = NULL;
|
||||
janet_vm.core_env = NULL;
|
||||
janet_vm.top_dyns = NULL;
|
||||
janet_free(janet_vm.traversal_base);
|
||||
janet_vm.fiber = NULL;
|
||||
janet_vm.root_fiber = NULL;
|
||||
#ifdef JANET_THREADS
|
||||
janet_threads_deinit();
|
||||
#endif
|
||||
|
@ -163,7 +163,7 @@ Janet(janet_wrap_number)(double x) {
|
||||
void *janet_memalloc_empty(int32_t count) {
|
||||
int32_t i;
|
||||
void *mem = janet_malloc((size_t) count * sizeof(JanetKV));
|
||||
janet_vm_next_collection += (size_t) count * sizeof(JanetKV);
|
||||
janet_vm.next_collection += (size_t) count * sizeof(JanetKV);
|
||||
if (NULL == mem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -365,6 +365,9 @@ typedef enum {
|
||||
JANET_STATUS_ALIVE
|
||||
} JanetFiberStatus;
|
||||
|
||||
/* For encapsulating all thread-local Janet state (except natives) */
|
||||
typedef struct JanetVM JanetVM;
|
||||
|
||||
/* Use type punning for GC objects */
|
||||
typedef struct JanetGCObject JanetGCObject;
|
||||
|
||||
@ -1641,6 +1644,10 @@ JANET_API int32_t janet_sorted_keys(const JanetKV *dict, int32_t cap, int32_t *i
|
||||
/* VM functions */
|
||||
JANET_API int janet_init(void);
|
||||
JANET_API void janet_deinit(void);
|
||||
JANET_API JanetVM *janet_vm_alloc(void);
|
||||
JANET_API void janet_vm_free(JanetVM *vm);
|
||||
JANET_API void janet_vm_save(JanetVM *into);
|
||||
JANET_API void janet_vm_load(JanetVM *from);
|
||||
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
|
||||
JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig);
|
||||
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
|
||||
|
Loading…
Reference in New Issue
Block a user