1
0
mirror of https://github.com/janet-lang/janet synced 2025-07-23 04:12:54 +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:
Calvin Rose 2021-07-16 20:59:03 -05:00
parent 230b734663
commit 1ef6db16ed
23 changed files with 609 additions and 577 deletions

View File

@ -113,6 +113,7 @@ JANET_CORE_SOURCES=src/core/abstract.c \
src/core/regalloc.c \ src/core/regalloc.c \
src/core/run.c \ src/core/run.c \
src/core/specials.c \ src/core/specials.c \
src/core/state.c \
src/core/string.c \ src/core/string.c \
src/core/strtod.c \ src/core/strtod.c \
src/core/struct.c \ src/core/struct.c \

View File

@ -127,6 +127,7 @@ core_src = [
'src/core/regalloc.c', 'src/core/regalloc.c',
'src/core/run.c', 'src/core/run.c',
'src/core/specials.c', 'src/core/specials.c',
'src/core/state.c',
'src/core/string.c', 'src/core/string.c',
'src/core/strtod.c', 'src/core/strtod.c',
'src/core/struct.c', 'src/core/struct.c',

View File

@ -3681,6 +3681,7 @@
"src/core/regalloc.c" "src/core/regalloc.c"
"src/core/run.c" "src/core/run.c"
"src/core/specials.c" "src/core/specials.c"
"src/core/state.c"
"src/core/string.c" "src/core/string.c"
"src/core/strtod.c" "src/core/strtod.c"
"src/core/struct.c" "src/core/struct.c"

View File

@ -35,7 +35,7 @@ JanetArray *janet_array(int32_t capacity) {
JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray)); JanetArray *array = janet_gcalloc(JANET_MEMORY_ARRAY, sizeof(JanetArray));
Janet *data = NULL; Janet *data = NULL;
if (capacity > 0) { 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); data = (Janet *) janet_malloc(sizeof(Janet) * (size_t) capacity);
if (NULL == data) { if (NULL == data) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
@ -72,7 +72,7 @@ void janet_array_ensure(JanetArray *array, int32_t capacity, int32_t growth) {
if (NULL == newData) { if (NULL == newData) {
JANET_OUT_OF_MEMORY; 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->data = newData;
array->capacity = capacity; array->capacity = capacity;
} }

View File

@ -51,15 +51,15 @@ JANET_NO_RETURN static void janet_top_level_signal(const char *msg) {
} }
void janet_signalv(JanetSignal sig, Janet message) { void janet_signalv(JanetSignal sig, Janet message) {
if (janet_vm_return_reg != NULL) { if (janet_vm.return_reg != NULL) {
*janet_vm_return_reg = message; *janet_vm.return_reg = message;
if (NULL != janet_vm_fiber) { if (NULL != janet_vm.fiber) {
janet_vm_fiber->flags |= JANET_FIBER_DID_LONGJUMP; janet_vm.fiber->flags |= JANET_FIBER_DID_LONGJUMP;
} }
#if defined(JANET_BSD) || defined(JANET_APPLE) #if defined(JANET_BSD) || defined(JANET_APPLE)
_longjmp(*janet_vm_jmp_buf, sig); _longjmp(*janet_vm.signal_buf, sig);
#else #else
longjmp(*janet_vm_jmp_buf, sig); longjmp(*janet_vm.signal_buf, sig);
#endif #endif
} else { } else {
const char *str = (const char *)janet_formatc("janet top level signal - %v\n", message); 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) { Janet janet_dyn(const char *name) {
if (!janet_vm_fiber) { if (!janet_vm.fiber) {
if (!janet_vm_top_dyns) return janet_wrap_nil(); if (!janet_vm.top_dyns) return janet_wrap_nil();
return janet_table_get(janet_vm_top_dyns, janet_ckeywordv(name)); return janet_table_get(janet_vm.top_dyns, janet_ckeywordv(name));
} }
if (janet_vm_fiber->env) { if (janet_vm.fiber->env) {
return janet_table_get(janet_vm_fiber->env, janet_ckeywordv(name)); return janet_table_get(janet_vm.fiber->env, janet_ckeywordv(name));
} else { } else {
return janet_wrap_nil(); return janet_wrap_nil();
} }
} }
void janet_setdyn(const char *name, Janet value) { void janet_setdyn(const char *name, Janet value) {
if (!janet_vm_fiber) { if (!janet_vm.fiber) {
if (!janet_vm_top_dyns) janet_vm_top_dyns = janet_table(10); if (!janet_vm.top_dyns) janet_vm.top_dyns = janet_table(10);
janet_table_put(janet_vm_top_dyns, janet_ckeywordv(name), value); janet_table_put(janet_vm.top_dyns, janet_ckeywordv(name), value);
} else { } else {
if (!janet_vm_fiber->env) { if (!janet_vm.fiber->env) {
janet_vm_fiber->env = janet_table(1); 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);
} }
} }

View File

@ -944,10 +944,10 @@ JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *w
/* C Function for compiling */ /* C Function for compiling */
static Janet cfun(int32_t argc, Janet *argv) { static Janet cfun(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 4); 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) { if (NULL == env) {
env = janet_table(0); env = janet_table(0);
janet_vm_fiber->env = env; janet_vm.fiber->env = env;
} }
const uint8_t *source = NULL; const uint8_t *source = NULL;
if (argc >= 3) { if (argc >= 3) {

View File

@ -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) { static Janet janet_core_dyn(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2); janet_arity(argc, 1, 2);
Janet value; Janet value;
if (janet_vm_fiber->env) { if (janet_vm.fiber->env) {
value = janet_table_get(janet_vm_fiber->env, argv[0]); value = janet_table_get(janet_vm.fiber->env, argv[0]);
} else { } else {
value = janet_wrap_nil(); 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) { static Janet janet_core_setdyn(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2); janet_fixarity(argc, 2);
if (!janet_vm_fiber->env) { if (!janet_vm.fiber->env) {
janet_vm_fiber->env = janet_table(2); 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]; return argv[1];
} }
@ -428,14 +428,14 @@ static Janet janet_core_gcsetinterval(int32_t argc, Janet *argv) {
janet_panic("interval too large"); janet_panic("interval too large");
} }
#endif #endif
janet_vm_gc_interval = s; janet_vm.gc_interval = s;
return janet_wrap_nil(); return janet_wrap_nil();
} }
static Janet janet_core_gcinterval(int32_t argc, Janet *argv) { static Janet janet_core_gcinterval(int32_t argc, Janet *argv) {
(void) argv; (void) argv;
janet_fixarity(argc, 0); 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) { 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) { JanetTable *janet_core_env(JanetTable *replacements) {
/* Memoize core env, ignoring replacements the second time around. */ /* Memoize core env, ignoring replacements the second time around. */
if (NULL != janet_vm_core_env) { if (NULL != janet_vm.core_env) {
return janet_vm_core_env; return janet_vm.core_env;
} }
JanetTable *dict = janet_core_lookup_table(replacements); JanetTable *dict = janet_core_lookup_table(replacements);
@ -1232,7 +1232,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
/* Memoize */ /* Memoize */
janet_gcroot(marsh_out); janet_gcroot(marsh_out);
JanetTable *env = janet_unwrap_table(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 /* Invert image dict manually here. We can't do this in boot.janet as it
* breaks deterministic builds */ * breaks deterministic builds */
@ -1265,7 +1265,7 @@ JanetTable *janet_core_lookup_table(JanetTable *replacements) {
if (!janet_checktype(kv.key, JANET_NIL)) { if (!janet_checktype(kv.key, JANET_NIL)) {
janet_table_put(dict, kv.key, kv.value); janet_table_put(dict, kv.key, kv.value);
if (janet_checktype(kv.value, JANET_CFUNCTION)) { 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);
} }
} }
} }

View File

@ -55,7 +55,7 @@ void janet_debug_find(
JanetFuncDef **def_out, int32_t *pc_out, JanetFuncDef **def_out, int32_t *pc_out,
const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) { const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) {
/* Scan the heap for right func def */ /* 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 */ /* Keep track of the best source mapping we have seen so far */
int32_t besti = -1; int32_t besti = -1;
int32_t best_line = -1; int32_t best_line = -1;
@ -144,7 +144,7 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
} else { } else {
JanetCFunction cfun = (JanetCFunction)(frame->pc); JanetCFunction cfun = (JanetCFunction)(frame->pc);
if (cfun) { 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)) if (!janet_checktype(name, JANET_NIL))
janet_eprintf(" %s", (const char *)janet_to_string(name)); janet_eprintf(" %s", (const char *)janet_to_string(name));
else else
@ -252,7 +252,7 @@ static Janet doframe(JanetStackFrame *frame) {
} else { } else {
JanetCFunction cfun = (JanetCFunction)(frame->pc); JanetCFunction cfun = (JanetCFunction)(frame->pc);
if (cfun) { 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)) { if (!janet_checktype(name, JANET_NIL)) {
janet_table_put(t, janet_ckeywordv("name"), name); janet_table_put(t, janet_ckeywordv("name"), name);
} }

View File

@ -56,12 +56,6 @@
#endif #endif
/* Ring buffer for storing a list of fibers */ /* Ring buffer for storing a list of fibers */
typedef struct {
int32_t capacity;
int32_t head;
int32_t tail;
void *data;
} JanetQueue;
typedef struct { typedef struct {
JanetFiber *fiber; JanetFiber *fiber;
@ -143,31 +137,9 @@ struct JanetTask {
JanetSignal sig; 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 */ /* Forward declaration */
static void janet_unlisten(JanetListenerState *state); 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) */ /* Get current timestamp (millisecond precision) */
static JanetTimestamp ts_now(void); static JanetTimestamp ts_now(void);
@ -180,58 +152,58 @@ static JanetTimestamp ts_delta(JanetTimestamp ts, double delta) {
/* Look at the next timeout value without /* Look at the next timeout value without
* removing it. */ * removing it. */
static int peek_timeout(JanetTimeout *out) { static int peek_timeout(JanetTimeout *out) {
if (janet_vm_tq_count == 0) return 0; if (janet_vm.tq_count == 0) return 0;
*out = janet_vm_tq[0]; *out = janet_vm.tq[0];
return 1; return 1;
} }
/* Remove the next timeout from the priority queue */ /* Remove the next timeout from the priority queue */
static void pop_timeout(size_t index) { static void pop_timeout(size_t index) {
if (janet_vm_tq_count <= index) return; if (janet_vm.tq_count <= index) return;
janet_vm_tq[index] = janet_vm_tq[--janet_vm_tq_count]; janet_vm.tq[index] = janet_vm.tq[--janet_vm.tq_count];
for (;;) { for (;;) {
size_t left = (index << 1) + 1; size_t left = (index << 1) + 1;
size_t right = left + 1; size_t right = left + 1;
size_t smallest = index; size_t smallest = index;
if (left < janet_vm_tq_count && if (left < janet_vm.tq_count &&
(janet_vm_tq[left].when < janet_vm_tq[smallest].when)) (janet_vm.tq[left].when < janet_vm.tq[smallest].when))
smallest = left; smallest = left;
if (right < janet_vm_tq_count && if (right < janet_vm.tq_count &&
(janet_vm_tq[right].when < janet_vm_tq[smallest].when)) (janet_vm.tq[right].when < janet_vm.tq[smallest].when))
smallest = right; smallest = right;
if (smallest == index) return; if (smallest == index) return;
JanetTimeout temp = janet_vm_tq[index]; JanetTimeout temp = janet_vm.tq[index];
janet_vm_tq[index] = janet_vm_tq[smallest]; janet_vm.tq[index] = janet_vm.tq[smallest];
janet_vm_tq[smallest] = temp; janet_vm.tq[smallest] = temp;
index = smallest; index = smallest;
} }
} }
/* Add a timeout to the timeout min heap */ /* Add a timeout to the timeout min heap */
static void add_timeout(JanetTimeout to) { 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; size_t newcount = oldcount + 1;
if (newcount > janet_vm_tq_capacity) { if (newcount > janet_vm.tq_capacity) {
size_t newcap = 2 * newcount; 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) { if (NULL == tq) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_tq = tq; janet_vm.tq = tq;
janet_vm_tq_capacity = newcap; janet_vm.tq_capacity = newcap;
} }
/* Append */ /* Append */
janet_vm_tq_count = (int32_t) newcount; janet_vm.tq_count = (int32_t) newcount;
janet_vm_tq[oldcount] = to; janet_vm.tq[oldcount] = to;
/* Heapify */ /* Heapify */
size_t index = oldcount; size_t index = oldcount;
while (index > 0) { while (index > 0) {
size_t parent = (index - 1) >> 1; 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 */ /* Swap */
JanetTimeout tmp = janet_vm_tq[index]; JanetTimeout tmp = janet_vm.tq[index];
janet_vm_tq[index] = janet_vm_tq[parent]; janet_vm.tq[index] = janet_vm.tq[parent];
janet_vm_tq[parent] = tmp; janet_vm.tq[parent] = tmp;
/* Next */ /* Next */
index = parent; index = parent;
} }
@ -242,7 +214,7 @@ static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener
if (stream->_mask & mask) { if (stream->_mask & mask) {
janet_panic("cannot listen for duplicate event on stream"); 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"); janet_panic("current fiber is already waiting for event");
} }
if (size < sizeof(JanetListenerState)) if (size < sizeof(JanetListenerState))
@ -252,8 +224,8 @@ static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
state->machine = behavior; state->machine = behavior;
state->fiber = janet_vm_root_fiber; state->fiber = janet_vm.root_fiber;
janet_vm_root_fiber->waiting = state; janet_vm.root_fiber->waiting = state;
state->stream = stream; state->stream = stream;
state->_mask = mask; state->_mask = mask;
stream->_mask |= mask; stream->_mask |= mask;
@ -261,17 +233,17 @@ static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener
stream->state = state; stream->state = state;
/* Keep track of a listener for GC purposes */ /* 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) { if (resize) {
size_t newcap = janet_vm_listener_count ? janet_vm_listener_cap * 2 : 16; size_t newcap = janet_vm.listener_count ? janet_vm.listener_cap * 2 : 16;
janet_vm_listeners = janet_realloc(janet_vm_listeners, newcap * sizeof(JanetListenerState *)); janet_vm.listeners = janet_realloc(janet_vm.listeners, newcap * sizeof(JanetListenerState *));
if (NULL == janet_vm_listeners) { if (NULL == janet_vm.listeners) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_listener_cap = newcap; janet_vm.listener_cap = newcap;
} }
size_t index = janet_vm_listener_count++; size_t index = janet_vm.listener_count++;
janet_vm_listeners[index] = state; janet_vm.listeners[index] = state;
state->_index = index; state->_index = index;
/* Emit INIT event for convenience */ /* Emit INIT event for convenience */
@ -299,8 +271,8 @@ static void janet_unlisten_impl(JanetListenerState *state) {
} }
/* Untrack a listener for gc purposes */ /* Untrack a listener for gc purposes */
size_t index = state->_index; size_t index = state->_index;
janet_vm_listeners[index] = janet_vm_listeners[--janet_vm_listener_count]; janet_vm.listeners[index] = janet_vm.listeners[--janet_vm.listener_count];
janet_vm_listeners[index]->_index = index; janet_vm.listeners[index]->_index = index;
janet_free(state); janet_free(state);
} }
@ -459,7 +431,7 @@ void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig) {
fiber->flags |= JANET_FIBER_FLAG_SCHEDULED; fiber->flags |= JANET_FIBER_FLAG_SCHEDULED;
fiber->sched_id++; fiber->sched_id++;
JanetTask t = { fiber, value, sig }; 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) { void janet_cancel(JanetFiber *fiber, Janet value) {
@ -482,34 +454,34 @@ void janet_fiber_did_resume(JanetFiber *fiber) {
void janet_ev_mark(void) { void janet_ev_mark(void) {
/* Pending tasks */ /* Pending tasks */
JanetTask *tasks = janet_vm_spawn.data; JanetTask *tasks = janet_vm.spawn.data;
if (janet_vm_spawn.head <= janet_vm_spawn.tail) { if (janet_vm.spawn.head <= janet_vm.spawn.tail) {
for (int32_t i = janet_vm_spawn.head; i < janet_vm_spawn.tail; i++) { for (int32_t i = janet_vm.spawn.head; i < janet_vm.spawn.tail; i++) {
janet_mark(janet_wrap_fiber(tasks[i].fiber)); janet_mark(janet_wrap_fiber(tasks[i].fiber));
janet_mark(tasks[i].value); janet_mark(tasks[i].value);
} }
} else { } 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(janet_wrap_fiber(tasks[i].fiber));
janet_mark(tasks[i].value); 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(janet_wrap_fiber(tasks[i].fiber));
janet_mark(tasks[i].value); janet_mark(tasks[i].value);
} }
} }
/* Pending timeouts */ /* Pending timeouts */
for (size_t i = 0; i < janet_vm_tq_count; i++) { for (size_t i = 0; i < janet_vm.tq_count; i++) {
janet_mark(janet_wrap_fiber(janet_vm_tq[i].fiber)); janet_mark(janet_wrap_fiber(janet_vm.tq[i].fiber));
if (janet_vm_tq[i].curr_fiber != NULL) { if (janet_vm.tq[i].curr_fiber != NULL) {
janet_mark(janet_wrap_fiber(janet_vm_tq[i].curr_fiber)); janet_mark(janet_wrap_fiber(janet_vm.tq[i].curr_fiber));
} }
} }
/* Pending listeners */ /* Pending listeners */
for (size_t i = 0; i < janet_vm_listener_count; i++) { for (size_t i = 0; i < janet_vm.listener_count; i++) {
JanetListenerState *state = janet_vm_listeners[i]; JanetListenerState *state = janet_vm.listeners[i];
if (NULL != state->fiber) { if (NULL != state->fiber) {
janet_mark(janet_wrap_fiber(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 */ /* Common init code */
void janet_ev_init_common(void) { void janet_ev_init_common(void) {
janet_q_init(&janet_vm_spawn); janet_q_init(&janet_vm.spawn);
janet_vm_listener_count = 0; janet_vm.listener_count = 0;
janet_vm_listener_cap = 0; janet_vm.listener_cap = 0;
janet_vm_listeners = NULL; janet_vm.listeners = NULL;
janet_vm_tq = NULL; janet_vm.tq = NULL;
janet_vm_tq_count = 0; janet_vm.tq_count = 0;
janet_vm_tq_capacity = 0; janet_vm.tq_capacity = 0;
janet_rng_seed(&janet_vm_ev_rng, 0); janet_rng_seed(&janet_vm.ev_rng, 0);
} }
/* Common deinit code */ /* Common deinit code */
void janet_ev_deinit_common(void) { void janet_ev_deinit_common(void) {
janet_q_deinit(&janet_vm_spawn); janet_q_deinit(&janet_vm.spawn);
janet_free(janet_vm_tq); janet_free(janet_vm.tq);
janet_free(janet_vm_listeners); janet_free(janet_vm.listeners);
janet_vm_listeners = NULL; janet_vm.listeners = NULL;
} }
/* Short hand to yield to event loop */ /* Short hand to yield to event loop */
@ -569,7 +541,7 @@ void janet_await(void) {
/* Set timeout for the current root fiber */ /* Set timeout for the current root fiber */
void janet_addtimeout(double sec) { void janet_addtimeout(double sec) {
JanetFiber *fiber = janet_vm_root_fiber; JanetFiber *fiber = janet_vm.root_fiber;
JanetTimeout to; JanetTimeout to;
to.when = ts_delta(ts_now(), sec); to.when = ts_delta(ts_now(), sec);
to.fiber = fiber; to.fiber = fiber;
@ -580,11 +552,11 @@ void janet_addtimeout(double sec) {
} }
void janet_ev_inc_refcount(void) { void janet_ev_inc_refcount(void) {
janet_vm_extra_listeners++; janet_vm.extra_listeners++;
} }
void janet_ev_dec_refcount(void) { void janet_ev_dec_refcount(void) {
janet_vm_extra_listeners--; janet_vm.extra_listeners--;
} }
/* Channels */ /* Channels */
@ -699,8 +671,8 @@ static int janet_channel_push(JanetChannel *channel, Janet x, int mode) {
if (mode == 2) return 0; if (mode == 2) return 0;
/* Pushed successfully, but should block. */ /* Pushed successfully, but should block. */
JanetChannelPending pending; JanetChannelPending pending;
pending.fiber = janet_vm_root_fiber, pending.fiber = janet_vm.root_fiber,
pending.sched_id = janet_vm_root_fiber->sched_id, pending.sched_id = janet_vm.root_fiber->sched_id,
pending.mode = mode ? JANET_CP_MODE_CHOICE_WRITE : JANET_CP_MODE_ITEM; pending.mode = mode ? JANET_CP_MODE_CHOICE_WRITE : JANET_CP_MODE_ITEM;
janet_q_push(&channel->write_pending, &pending, sizeof(pending)); janet_q_push(&channel->write_pending, &pending, sizeof(pending));
return 1; 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))) { if (janet_q_pop(&channel->items, item, sizeof(Janet))) {
/* Queue empty */ /* Queue empty */
JanetChannelPending pending; JanetChannelPending pending;
pending.fiber = janet_vm_root_fiber, pending.fiber = janet_vm.root_fiber,
pending.sched_id = janet_vm_root_fiber->sched_id; pending.sched_id = janet_vm.root_fiber->sched_id;
pending.mode = is_choice ? JANET_CP_MODE_CHOICE_READ : JANET_CP_MODE_ITEM; pending.mode = is_choice ? JANET_CP_MODE_CHOICE_READ : JANET_CP_MODE_ITEM;
janet_q_push(&channel->read_pending, &pending, sizeof(pending)); janet_q_push(&channel->read_pending, &pending, sizeof(pending));
return 0; return 0;
@ -757,7 +729,7 @@ static Janet cfun_channel_pop(int32_t argc, Janet *argv) {
JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT); JanetChannel *channel = janet_getabstract(argv, 0, &ChannelAT);
Janet item; Janet item;
if (janet_channel_pop(channel, &item, 0)) { if (janet_channel_pop(channel, &item, 0)) {
janet_schedule(janet_vm_root_fiber, item); janet_schedule(janet_vm.root_fiber, item);
} }
janet_await(); janet_await();
} }
@ -825,7 +797,7 @@ static Janet cfun_channel_count(int32_t argc, Janet *argv) {
/* Fisher yates shuffle of arguments to get fairness */ /* Fisher yates shuffle of arguments to get fairness */
static void fisher_yates_args(int32_t argc, Janet *argv) { static void fisher_yates_args(int32_t argc, Janet *argv) {
for (int32_t i = argc; i > 1; i--) { 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]; Janet temp = argv[swap_index];
argv[swap_index] = argv[i - 1]; argv[swap_index] = argv[i - 1];
argv[i - 1] = temp; argv[i - 1] = temp;
@ -903,14 +875,14 @@ void janet_loop1(void) {
} }
/* Run scheduled fibers */ /* 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}; 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); run_one(task.fiber, task.value, task.sig);
} }
/* Poll for events */ /* 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; JanetTimeout to;
memset(&to, 0, sizeof(to)); memset(&to, 0, sizeof(to));
int has_timeout; int has_timeout;
@ -919,14 +891,14 @@ void janet_loop1(void) {
pop_timeout(0); pop_timeout(0);
} }
/* Run polling implementation only if pending timeouts or pending events */ /* 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); janet_loop1_impl(has_timeout, to.when);
} }
} }
} }
void janet_loop(void) { 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(); janet_loop1();
} }
} }
@ -958,10 +930,8 @@ typedef struct {
#else #else
static JANET_THREAD_LOCAL JanetHandle janet_vm_selfpipe[2];
static void janet_ev_setup_selfpipe(void) { 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"); 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 */ /* Handle events from the self pipe inside the event loop */
static void janet_ev_handle_selfpipe(void) { static void janet_ev_handle_selfpipe(void) {
JanetSelfPipeEvent response; 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); response.cb(response.msg);
janet_ev_dec_refcount(); janet_ev_dec_refcount();
} }
} }
static void janet_ev_cleanup_selfpipe(void) { static void janet_ev_cleanup_selfpipe(void) {
close(janet_vm_selfpipe[0]); close(janet_vm.selfpipe[0]);
close(janet_vm_selfpipe[1]); close(janet_vm.selfpipe[1]);
} }
#endif #endif
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
JANET_THREAD_LOCAL HANDLE janet_vm_iocp = NULL;
static JanetTimestamp ts_now(void) { static JanetTimestamp ts_now(void) {
return (JanetTimestamp) GetTickCount64(); return (JanetTimestamp) GetTickCount64();
} }
void janet_ev_init(void) { void janet_ev_init(void) {
janet_ev_init_common(); janet_ev_init_common();
janet_vm_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); janet_vm.iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (NULL == janet_vm_iocp) janet_panic("could not create io completion port"); if (NULL == janet_vm.iocp) janet_panic("could not create io completion port");
} }
void janet_ev_deinit(void) { void janet_ev_deinit(void) {
janet_ev_deinit_common(); 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) { 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 */ /* Add the handle to the io completion port if not already added */
JanetListenerState *state = janet_listen_impl(stream, behavior, mask, size, user); JanetListenerState *state = janet_listen_impl(stream, behavior, mask, size, user);
if (!(stream->flags & JANET_STREAM_IOCP)) { 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()); janet_panicf("failed to listen for events: %V", janet_ev_lasterr());
} }
stream->flags |= JANET_STREAM_IOCP; stream->flags |= JANET_STREAM_IOCP;
@ -1035,7 +1003,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
} else { } else {
waittime = INFINITE; 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 (result || overlapped) {
if (0 == completionKey) { if (0 == completionKey) {
@ -1067,10 +1035,6 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
#elif defined(JANET_EV_EPOLL) #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) { static JanetTimestamp ts_now(void) {
struct timespec now; struct timespec now;
janet_assert(-1 != clock_gettime(CLOCK_MONOTONIC, &now), "failed to get time"); 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; ev.data.ptr = stream;
int status; int status;
do { 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); } while (status == -1 && errno == EINTR);
if (status == -1) { if (status == -1) {
janet_unlisten_impl(state); janet_unlisten_impl(state);
@ -1118,7 +1082,7 @@ static void janet_unlisten(JanetListenerState *state) {
ev.data.ptr = stream; ev.data.ptr = stream;
int status; int status;
do { 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); } while (status == -1 && errno == EINTR);
if (status == -1) { if (status == -1) {
janet_panicv(janet_ev_lasterr()); janet_panicv(janet_ev_lasterr());
@ -1131,21 +1095,21 @@ static void janet_unlisten(JanetListenerState *state) {
#define JANET_EPOLL_MAX_EVENTS 64 #define JANET_EPOLL_MAX_EVENTS 64
void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) { void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
struct itimerspec its; struct itimerspec its;
if (janet_vm_timer_enabled || has_timeout) { if (janet_vm.timer_enabled || has_timeout) {
memset(&its, 0, sizeof(its)); memset(&its, 0, sizeof(its));
if (has_timeout) { if (has_timeout) {
its.it_value.tv_sec = timeout / 1000; its.it_value.tv_sec = timeout / 1000;
its.it_value.tv_nsec = (timeout % 1000) * 1000000; 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 */ /* Poll for events */
struct epoll_event events[JANET_EPOLL_MAX_EVENTS]; struct epoll_event events[JANET_EPOLL_MAX_EVENTS];
int ready; int ready;
do { 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); } while (ready == -1 && errno == EINTR);
if (ready == -1) { if (ready == -1) {
JANET_EXIT("failed to poll events"); JANET_EXIT("failed to poll events");
@ -1154,9 +1118,9 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
/* Step state machines */ /* Step state machines */
for (int i = 0; i < ready; i++) { for (int i = 0; i < ready; i++) {
void *p = events[i].data.ptr; void *p = events[i].data.ptr;
if (&janet_vm_timerfd == p) { if (&janet_vm.timerfd == p) {
/* Timer expired, ignore */; /* Timer expired, ignore */;
} else if (janet_vm_selfpipe == p) { } else if (janet_vm.selfpipe == p) {
/* Self-pipe handling */ /* Self-pipe handling */
janet_ev_handle_selfpipe(); janet_ev_handle_selfpipe();
} else { } else {
@ -1192,17 +1156,17 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
void janet_ev_init(void) { void janet_ev_init(void) {
janet_ev_init_common(); janet_ev_init_common();
janet_ev_setup_selfpipe(); janet_ev_setup_selfpipe();
janet_vm_epoll = epoll_create1(EPOLL_CLOEXEC); janet_vm.epoll = epoll_create1(EPOLL_CLOEXEC);
janet_vm_timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); janet_vm.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
janet_vm_timer_enabled = 0; janet_vm.timer_enabled = 0;
if (janet_vm_epoll == -1 || janet_vm_timerfd == -1) goto error; if (janet_vm.epoll == -1 || janet_vm.timerfd == -1) goto error;
struct epoll_event ev; struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET; ev.events = EPOLLIN | EPOLLET;
ev.data.ptr = &janet_vm_timerfd; ev.data.ptr = &janet_vm.timerfd;
if (-1 == epoll_ctl(janet_vm_epoll, EPOLL_CTL_ADD, janet_vm_timerfd, &ev)) goto error; if (-1 == epoll_ctl(janet_vm.epoll, EPOLL_CTL_ADD, janet_vm.timerfd, &ev)) goto error;
ev.events = EPOLLIN | EPOLLET; ev.events = EPOLLIN | EPOLLET;
ev.data.ptr = janet_vm_selfpipe; ev.data.ptr = janet_vm.selfpipe;
if (-1 == epoll_ctl(janet_vm_epoll, EPOLL_CTL_ADD, janet_vm_selfpipe[0], &ev)) goto error; if (-1 == epoll_ctl(janet_vm.epoll, EPOLL_CTL_ADD, janet_vm.selfpipe[0], &ev)) goto error;
return; return;
error: error:
JANET_EXIT("failed to initialize event loop"); JANET_EXIT("failed to initialize event loop");
@ -1210,10 +1174,10 @@ error:
void janet_ev_deinit(void) { void janet_ev_deinit(void) {
janet_ev_deinit_common(); janet_ev_deinit_common();
close(janet_vm_epoll); close(janet_vm.epoll);
close(janet_vm_timerfd); close(janet_vm.timerfd);
janet_ev_cleanup_selfpipe(); janet_ev_cleanup_selfpipe();
janet_vm_epoll = 0; janet_vm.epoll = 0;
} }
/* /*
@ -1224,8 +1188,6 @@ void janet_ev_deinit(void) {
#include <poll.h> #include <poll.h>
JANET_THREAD_LOCAL struct pollfd *janet_vm_fds = NULL;
static JanetTimestamp ts_now(void) { static JanetTimestamp ts_now(void) {
struct timespec now; struct timespec now;
janet_assert(-1 != clock_gettime(CLOCK_REALTIME, &now), "failed to get time"); 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 */ /* Wait for the next event */
JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) { 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); 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) { if (newsize > oldsize) {
janet_vm_fds = janet_realloc(janet_vm_fds, (newsize + 1) * sizeof(struct pollfd)); janet_vm.fds = janet_realloc(janet_vm.fds, (newsize + 1) * sizeof(struct pollfd));
if (NULL == janet_vm_fds) { if (NULL == janet_vm.fds) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
} }
@ -1258,12 +1220,12 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in
ev.fd = stream->handle; ev.fd = stream->handle;
ev.events = make_poll_events(state->stream->_mask); ev.events = make_poll_events(state->stream->_mask);
ev.revents = 0; ev.revents = 0;
janet_vm_fds[state->_index + 1] = ev; janet_vm.fds[state->_index + 1] = ev;
return state; return state;
} }
static void janet_unlisten(JanetListenerState *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); janet_unlisten_impl(state);
} }
@ -1276,23 +1238,23 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp timeout) {
JanetTimestamp now = ts_now(); JanetTimestamp now = ts_now();
to = now > timeout ? 0 : (int)(timeout - 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); } while (ready == -1 && errno == EINTR);
if (ready == -1) { if (ready == -1) {
JANET_EXIT("failed to poll events"); JANET_EXIT("failed to poll events");
} }
/* Check selfpipe */ /* Check selfpipe */
if (janet_vm_fds[0].revents & POLLIN) { if (janet_vm.fds[0].revents & POLLIN) {
janet_vm_fds[0].revents = 0; janet_vm.fds[0].revents = 0;
janet_ev_handle_selfpipe(); janet_ev_handle_selfpipe();
} }
/* Step state machines */ /* Step state machines */
for (size_t i = 0; i < janet_vm_listener_count; i++) { for (size_t i = 0; i < janet_vm.listener_count; i++) {
struct pollfd *pfd = janet_vm_fds + i + 1; struct pollfd *pfd = janet_vm.fds + i + 1;
/* Skip fds where nothing interesting happened */ /* Skip fds where nothing interesting happened */
JanetListenerState *state = janet_vm_listeners[i]; JanetListenerState *state = janet_vm.listeners[i];
/* Normal event */ /* Normal event */
int mask = pfd->revents; int mask = pfd->revents;
JanetAsyncStatus status1 = JANET_ASYNC_STATUS_NOT_DONE; 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) { void janet_ev_init(void) {
janet_ev_init_common(); janet_ev_init_common();
janet_vm_fds = NULL; janet_vm.fds = NULL;
janet_ev_setup_selfpipe(); janet_ev_setup_selfpipe();
janet_vm_fds = janet_malloc(sizeof(struct pollfd)); janet_vm.fds = janet_malloc(sizeof(struct pollfd));
if (NULL == janet_vm_fds) { if (NULL == janet_vm.fds) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_fds[0].fd = janet_vm_selfpipe[0]; janet_vm.fds[0].fd = janet_vm.selfpipe[0];
janet_vm_fds[0].events = POLLIN; janet_vm.fds[0].events = POLLIN;
janet_vm_fds[0].revents = 0; janet_vm.fds[0].revents = 0;
return; return;
} }
void janet_ev_deinit(void) { void janet_ev_deinit(void) {
janet_ev_deinit_common(); janet_ev_deinit_common();
janet_ev_cleanup_selfpipe(); janet_ev_cleanup_selfpipe();
janet_free(janet_vm_fds); janet_free(janet_vm.fds);
janet_vm_fds = NULL; janet_vm.fds = NULL;
} }
#endif #endif
@ -1400,7 +1362,7 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar
init->cb = cb; init->cb = cb;
#ifdef JANET_WINDOWS #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); HANDLE thread_handle = CreateThread(NULL, 0, janet_thread_body, init, 0, NULL);
if (NULL == thread_handle) { if (NULL == thread_handle) {
janet_free(init); janet_free(init);
@ -1408,7 +1370,7 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar
} }
CloseHandle(thread_handle); /* detach from thread */ CloseHandle(thread_handle); /* detach from thread */
#else #else
init->write_pipe = janet_vm_selfpipe[1]; init->write_pipe = janet_vm.selfpipe[1];
pthread_t waiter_thread; pthread_t waiter_thread;
int err = pthread_create(&waiter_thread, NULL, janet_thread_body, init); int err = pthread_create(&waiter_thread, NULL, janet_thread_body, init);
if (err) { if (err) {
@ -2040,7 +2002,7 @@ static Janet cfun_ev_go(int32_t argc, Janet *argv) {
JanetFiber *fiber = janet_getfiber(argv, 0); JanetFiber *fiber = janet_getfiber(argv, 0);
Janet value = argc >= 2 ? argv[1] : janet_wrap_nil(); Janet value = argc >= 2 ? argv[1] : janet_wrap_nil();
JanetChannel *supervisor_channel = janet_optabstract(argv, argc, 2, &ChannelAT, 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; fiber->supervisor_channel = supervisor_channel;
janet_schedule(fiber, value); janet_schedule(fiber, value);
return argv[0]; return argv[0];
@ -2058,11 +2020,11 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
Janet aregv = janet_unmarshal(nextbytes, endbytes - nextbytes, Janet aregv = janet_unmarshal(nextbytes, endbytes - nextbytes,
JANET_MARSHAL_UNSAFE, NULL, &nextbytes); JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
if (!janet_checktype(aregv, JANET_TABLE)) janet_panic("expected table for abstract registry"); 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 regv = janet_unmarshal(nextbytes, endbytes - nextbytes,
JANET_MARSHAL_UNSAFE, NULL, &nextbytes); JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
if (!janet_checktype(regv, JANET_TABLE)) janet_panic("expected table for cfunction registry"); 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 fiberv = janet_unmarshal(nextbytes, endbytes - nextbytes,
JANET_MARSHAL_UNSAFE, NULL, &nextbytes); JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
Janet value = janet_unmarshal(nextbytes, endbytes - 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_OUT_OF_MEMORY;
} }
janet_buffer_init(buffer, 0); 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.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.registry), NULL, JANET_MARSHAL_UNSAFE);
janet_marshal(buffer, argv[0], NULL, JANET_MARSHAL_UNSAFE); janet_marshal(buffer, argv[0], NULL, JANET_MARSHAL_UNSAFE);
janet_marshal(buffer, value, NULL, JANET_MARSHAL_UNSAFE); janet_marshal(buffer, value, NULL, JANET_MARSHAL_UNSAFE);
janet_ev_threaded_await(janet_go_thread_subr, 0, argc, buffer); 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) { static Janet cfun_ev_give_supervisor(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1); 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 (NULL != chan) {
if (janet_channel_push(chan, janet_wrap_tuple(janet_tuple_n(argv, argc)), 0)) { if (janet_channel_push(chan, janet_wrap_tuple(janet_tuple_n(argv, argc)), 0)) {
janet_await(); 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) { JANET_NO_RETURN void janet_sleep_await(double sec) {
JanetTimeout to; JanetTimeout to;
to.when = ts_delta(ts_now(), sec); to.when = ts_delta(ts_now(), sec);
to.fiber = janet_vm_root_fiber; to.fiber = janet_vm.root_fiber;
to.is_error = 0; to.is_error = 0;
to.sched_id = to.fiber->sched_id; to.sched_id = to.fiber->sched_id;
to.curr_fiber = NULL; 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) { static Janet cfun_ev_deadline(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 3); janet_arity(argc, 1, 3);
double sec = janet_getnumber(argv, 0); double sec = janet_getnumber(argv, 0);
JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm_root_fiber); JanetFiber *tocancel = janet_optfiber(argv, argc, 1, janet_vm.root_fiber);
JanetFiber *tocheck = janet_optfiber(argv, argc, 2, janet_vm_fiber); JanetFiber *tocheck = janet_optfiber(argv, argc, 2, janet_vm.fiber);
JanetTimeout to; JanetTimeout to;
to.when = ts_delta(ts_now(), sec); to.when = ts_delta(ts_now(), sec);
to.fiber = tocancel; to.fiber = tocancel;

View File

@ -57,7 +57,7 @@ static JanetFiber *fiber_alloc(int32_t capacity) {
if (NULL == data) { if (NULL == data) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_next_collection += sizeof(Janet) * capacity; janet_vm.next_collection += sizeof(Janet) * capacity;
fiber->data = data; fiber->data = data;
return fiber; return fiber;
} }
@ -121,7 +121,7 @@ void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
} }
fiber->data = newData; fiber->data = newData;
fiber->capacity = n; fiber->capacity = n;
janet_vm_next_collection += sizeof(Janet) * diff; janet_vm.next_collection += sizeof(Janet) * diff;
} }
/* Grow fiber if needed */ /* Grow fiber if needed */
@ -255,7 +255,7 @@ static void janet_env_detach(JanetFuncEnv *env) {
int32_t len = env->length; int32_t len = env->length;
size_t s = sizeof(Janet) * (size_t) len; size_t s = sizeof(Janet) * (size_t) len;
Janet *vmem = janet_malloc(s); Janet *vmem = janet_malloc(s);
janet_vm_next_collection += (uint32_t) s; janet_vm.next_collection += (uint32_t) s;
if (NULL == vmem) { if (NULL == vmem) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
@ -442,11 +442,11 @@ JanetFiberStatus janet_fiber_status(JanetFiber *f) {
} }
JanetFiber *janet_current_fiber(void) { JanetFiber *janet_current_fiber(void) {
return janet_vm_fiber; return janet_vm.fiber;
} }
JanetFiber *janet_root_fiber(void) { JanetFiber *janet_root_fiber(void) {
return janet_vm_root_fiber; return janet_vm.root_fiber;
} }
/* CFuns */ /* CFuns */
@ -520,17 +520,17 @@ static Janet cfun_fiber_new(int32_t argc, Janet *argv) {
fiber->flags |= JANET_FIBER_MASK_YIELD; fiber->flags |= JANET_FIBER_MASK_YIELD;
break; break;
case 'i': case 'i':
if (!janet_vm_fiber->env) { if (!janet_vm.fiber->env) {
janet_vm_fiber->env = janet_table(0); janet_vm.fiber->env = janet_table(0);
} }
fiber->env = janet_vm_fiber->env; fiber->env = janet_vm.fiber->env;
break; break;
case 'p': case 'p':
if (!janet_vm_fiber->env) { if (!janet_vm.fiber->env) {
janet_vm_fiber->env = janet_table(0); janet_vm.fiber->env = janet_table(0);
} }
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; 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) { static Janet cfun_fiber_current(int32_t argc, Janet *argv) {
(void) argv; (void) argv;
janet_fixarity(argc, 0); 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) { static Janet cfun_fiber_root(int32_t argc, Janet *argv) {
(void) argv; (void) argv;
janet_fixarity(argc, 0); 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) { static Janet cfun_fiber_maxstack(int32_t argc, Janet *argv) {

View File

@ -57,8 +57,6 @@
#define JANET_FIBER_DID_LONGJUMP 0x8000000 #define JANET_FIBER_DID_LONGJUMP 0x8000000
#define JANET_FIBER_FLAG_MASK 0xF000000 #define JANET_FIBER_FLAG_MASK 0xF000000
extern JANET_THREAD_LOCAL JanetFiber *janet_vm_fiber;
#define janet_fiber_set_status(f, s) do {\ #define janet_fiber_set_status(f, s) do {\
(f)->flags &= ~JANET_FIBER_STATUS_MASK;\ (f)->flags &= ~JANET_FIBER_STATUS_MASK;\
(f)->flags |= (s) << JANET_FIBER_STATUS_OFFSET;\ (f)->flags |= (s) << JANET_FIBER_STATUS_OFFSET;\

View File

@ -31,28 +31,6 @@
#include "vector.h" #include "vector.h"
#endif #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 */ /* Helpers for marking the various gc types */
static void janet_mark_funcenv(JanetFuncEnv *env); static void janet_mark_funcenv(JanetFuncEnv *env);
static void janet_mark_funcdef(JanetFuncDef *def); 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 */ /* Hint to the GC that we may need to collect */
void janet_gcpressure(size_t s) { void janet_gcpressure(size_t s) {
janet_vm_next_collection += s; janet_vm.next_collection += s;
} }
/* Mark a value */ /* 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. */ * marked as reachable. Flip the gc color flag for next sweep. */
void janet_sweep() { void janet_sweep() {
JanetGCObject *previous = NULL; JanetGCObject *previous = NULL;
JanetGCObject *current = janet_vm_blocks; JanetGCObject *current = janet_vm.blocks;
JanetGCObject *next; JanetGCObject *next;
while (NULL != current) { while (NULL != current) {
next = current->next; next = current->next;
@ -340,12 +318,12 @@ void janet_sweep() {
previous = current; previous = current;
current->flags &= ~JANET_MEM_REACHABLE; current->flags &= ~JANET_MEM_REACHABLE;
} else { } else {
janet_vm_block_count--; janet_vm.block_count--;
janet_deinit_block(current); janet_deinit_block(current);
if (NULL != previous) { if (NULL != previous) {
previous->next = next; previous->next = next;
} else { } else {
janet_vm_blocks = next; janet_vm.blocks = next;
} }
janet_free(current); janet_free(current);
} }
@ -358,7 +336,7 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
JanetGCObject *mem; JanetGCObject *mem;
/* Make sure everything is inited */ /* 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); mem = janet_malloc(size);
/* Check for bad malloc */ /* Check for bad malloc */
@ -370,10 +348,10 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
mem->flags = type; mem->flags = type;
/* Prepend block to heap list */ /* Prepend block to heap list */
janet_vm_next_collection += size; janet_vm.next_collection += size;
mem->next = janet_vm_blocks; mem->next = janet_vm.blocks;
janet_vm_blocks = mem; janet_vm.blocks = mem;
janet_vm_block_count++; janet_vm.block_count++;
return (void *)mem; return (void *)mem;
} }
@ -387,10 +365,10 @@ static void free_one_scratch(JanetScratch *s) {
/* Free all allocated scratch memory */ /* Free all allocated scratch memory */
static void janet_free_all_scratch(void) { static void janet_free_all_scratch(void) {
for (size_t i = 0; i < janet_scratch_len; i++) { for (size_t i = 0; i < janet_vm.scratch_len; i++) {
free_one_scratch(janet_scratch_mem[i]); free_one_scratch(janet_vm.scratch_mem[i]);
} }
janet_scratch_len = 0; janet_vm.scratch_len = 0;
} }
static JanetScratch *janet_mem2scratch(void *mem) { static JanetScratch *janet_mem2scratch(void *mem) {
@ -401,29 +379,29 @@ static JanetScratch *janet_mem2scratch(void *mem) {
/* Run garbage collection */ /* Run garbage collection */
void janet_collect(void) { void janet_collect(void) {
uint32_t i; uint32_t i;
if (janet_vm_gc_suspend) return; if (janet_vm.gc_suspend) return;
depth = JANET_RECURSION_GUARD; depth = JANET_RECURSION_GUARD;
/* Try and prevent many major collections back to back. /* 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 * 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 * small so we won't make many collections over it. This is just a
* heuristic for automatically changing the gc interval */ * heuristic for automatically changing the gc interval */
if (janet_vm_block_count * 8 > janet_vm_gc_interval) { if (janet_vm.block_count * 8 > janet_vm.gc_interval) {
janet_vm_gc_interval = janet_vm_block_count * sizeof(JanetGCObject); 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 #ifdef JANET_EV
janet_ev_mark(); janet_ev_mark();
#endif #endif
janet_mark_fiber(janet_vm_root_fiber); janet_mark_fiber(janet_vm.root_fiber);
for (i = 0; i < orig_rootcount; i++) for (i = 0; i < orig_rootcount; i++)
janet_mark(janet_vm_roots[i]); janet_mark(janet_vm.roots[i]);
while (orig_rootcount < janet_vm_root_count) { while (orig_rootcount < janet_vm.root_count) {
Janet x = janet_vm_roots[--janet_vm_root_count]; Janet x = janet_vm.roots[--janet_vm.root_count];
janet_mark(x); janet_mark(x);
} }
janet_sweep(); janet_sweep();
janet_vm_next_collection = 0; janet_vm.next_collection = 0;
janet_free_all_scratch(); 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 * 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. */ * must also be called n times to remove it as a gc root. */
void janet_gcroot(Janet root) { void janet_gcroot(Janet root) {
size_t newcount = janet_vm_root_count + 1; size_t newcount = janet_vm.root_count + 1;
if (newcount > janet_vm_root_capacity) { if (newcount > janet_vm.root_capacity) {
size_t newcap = 2 * newcount; size_t newcap = 2 * newcount;
janet_vm_roots = janet_realloc(janet_vm_roots, sizeof(Janet) * newcap); janet_vm.roots = janet_realloc(janet_vm.roots, sizeof(Janet) * newcap);
if (NULL == janet_vm_roots) { if (NULL == janet_vm.roots) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_root_capacity = newcap; janet_vm.root_capacity = newcap;
} }
janet_vm_roots[janet_vm_root_count] = root; janet_vm.roots[janet_vm.root_count] = root;
janet_vm_root_count = newcount; janet_vm.root_count = newcount;
} }
/* Identity equality for GC purposes */ /* 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 /* Remove a root value from the GC. This allows the gc to potentially reclaim
* a value and all its children. */ * a value and all its children. */
int janet_gcunroot(Janet root) { 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 */ /* 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)) { if (janet_gc_idequals(root, *v)) {
*v = janet_vm_roots[--janet_vm_root_count]; *v = janet_vm.roots[--janet_vm.root_count];
return 1; 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. */ /* Remove a root value from the GC. This sets the effective reference count to 0. */
int janet_gcunrootall(Janet root) { 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; int ret = 0;
/* Search from top to bottom as access is most likely LIFO */ /* 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)) { if (janet_gc_idequals(root, *v)) {
*v = janet_vm_roots[--janet_vm_root_count]; *v = janet_vm.roots[--janet_vm.root_count];
vtop--; vtop--;
ret = 1; ret = 1;
} }
@ -490,24 +468,24 @@ int janet_gcunrootall(Janet root) {
/* Free all allocated memory */ /* Free all allocated memory */
void janet_clear_memory(void) { void janet_clear_memory(void) {
JanetGCObject *current = janet_vm_blocks; JanetGCObject *current = janet_vm.blocks;
while (NULL != current) { while (NULL != current) {
janet_deinit_block(current); janet_deinit_block(current);
JanetGCObject *next = current->next; JanetGCObject *next = current->next;
janet_free(current); janet_free(current);
current = next; current = next;
} }
janet_vm_blocks = NULL; janet_vm.blocks = NULL;
janet_free_all_scratch(); janet_free_all_scratch();
janet_free(janet_scratch_mem); janet_free(janet_vm.scratch_mem);
} }
/* Primitives for suspending GC. */ /* Primitives for suspending GC. */
int janet_gclock(void) { int janet_gclock(void) {
return janet_vm_gc_suspend++; return janet_vm.gc_suspend++;
} }
void janet_gcunlock(int handle) { void janet_gcunlock(int handle) {
janet_vm_gc_suspend = handle; janet_vm.gc_suspend = handle;
} }
/* Scratch memory API */ /* Scratch memory API */
@ -518,16 +496,16 @@ void *janet_smalloc(size_t size) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
s->finalize = NULL; s->finalize = NULL;
if (janet_scratch_len == janet_scratch_cap) { if (janet_vm.scratch_len == janet_vm.scratch_cap) {
size_t newcap = 2 * janet_scratch_cap + 2; size_t newcap = 2 * janet_vm.scratch_cap + 2;
JanetScratch **newmem = (JanetScratch **) janet_realloc(janet_scratch_mem, newcap * sizeof(JanetScratch)); JanetScratch **newmem = (JanetScratch **) janet_realloc(janet_vm.scratch_mem, newcap * sizeof(JanetScratch));
if (NULL == newmem) { if (NULL == newmem) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_scratch_cap = newcap; janet_vm.scratch_cap = newcap;
janet_scratch_mem = newmem; 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); 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) { void *janet_srealloc(void *mem, size_t size) {
if (NULL == mem) return janet_smalloc(size); if (NULL == mem) return janet_smalloc(size);
JanetScratch *s = janet_mem2scratch(mem); JanetScratch *s = janet_mem2scratch(mem);
if (janet_scratch_len) { if (janet_vm.scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) { for (size_t i = janet_vm.scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == s) { if (janet_vm.scratch_mem[i] == s) {
JanetScratch *news = janet_realloc(s, size + sizeof(JanetScratch)); JanetScratch *news = janet_realloc(s, size + sizeof(JanetScratch));
if (NULL == news) { if (NULL == news) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_scratch_mem[i] = news; janet_vm.scratch_mem[i] = news;
return (char *)(news->mem); return (char *)(news->mem);
} }
if (i == 0) break; if (i == 0) break;
@ -568,10 +546,10 @@ void janet_sfinalizer(void *mem, JanetScratchFinalizer finalizer) {
void janet_sfree(void *mem) { void janet_sfree(void *mem) {
if (NULL == mem) return; if (NULL == mem) return;
JanetScratch *s = janet_mem2scratch(mem); JanetScratch *s = janet_mem2scratch(mem);
if (janet_scratch_len) { if (janet_vm.scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) { for (size_t i = janet_vm.scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == s) { if (janet_vm.scratch_mem[i] == s) {
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len]; janet_vm.scratch_mem[i] = janet_vm.scratch_mem[--janet_vm.scratch_len];
free_one_scratch(s); free_one_scratch(s);
return; return;
} }

View File

@ -23,13 +23,12 @@
#ifndef JANET_AMALG #ifndef JANET_AMALG
#include "features.h" #include "features.h"
#include <janet.h> #include <janet.h>
#include "state.h"
#include "util.h" #include "util.h"
#endif #endif
#include <math.h> #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 int janet_rng_get(void *p, Janet key, Janet *out);
static Janet janet_rng_next(void *p, Janet key); static Janet janet_rng_next(void *p, Janet key);
@ -69,7 +68,7 @@ const JanetAbstractType janet_rng_type = {
}; };
JanetRNG *janet_default_rng(void) { JanetRNG *janet_default_rng(void) {
return &janet_vm_rng; return &janet_vm.rng;
} }
void janet_rng_seed(JanetRNG *rng, uint32_t seed) { 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) { static Janet janet_rand(int32_t argc, Janet *argv) {
(void) argv; (void) argv;
janet_fixarity(argc, 0); 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 */ /* Seed the random number generator */
@ -225,10 +224,10 @@ static Janet janet_srand(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1); janet_fixarity(argc, 1);
if (janet_checkint(argv[0])) { if (janet_checkint(argv[0])) {
uint32_t seed = (uint32_t)(janet_getinteger(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 { } else {
JanetByteView bytes = janet_getbytes(argv, 0); 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(); return janet_wrap_nil();
} }

View File

@ -227,7 +227,7 @@ void janet_to_string_b(JanetBuffer *buffer, Janet x) {
} }
return; return;
case JANET_CFUNCTION: { 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)) { if (janet_checktype(check, JANET_SYMBOL)) {
janet_buffer_push_cstring(buffer, "<cfunction "); janet_buffer_push_cstring(buffer, "<cfunction ");
janet_buffer_push_bytes(buffer, janet_buffer_push_bytes(buffer,

49
src/core/state.c Normal file
View 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;
}

View File

@ -25,75 +25,135 @@
#include <stdint.h> #include <stdint.h>
/* The VM state. Rather than a struct that is passed typedef int64_t JanetTimestamp;
* 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 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 { typedef struct {
JanetGCObject *self; JanetGCObject *self;
JanetGCObject *other; JanetGCObject *other;
int32_t index; int32_t index;
int32_t index2; int32_t index2;
} JanetTraversalNode; } JanetTraversalNode;
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal;
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_top; typedef struct {
extern JANET_THREAD_LOCAL JanetTraversalNode *janet_vm_traversal_base; 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 */ /* Setup / teardown */
#ifdef JANET_THREADS #ifdef JANET_THREADS

View File

@ -36,30 +36,25 @@
#include <string.h> #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) */ /* Initialize the cache (allocate cache memory) */
void janet_symcache_init() { void janet_symcache_init() {
janet_vm_cache_capacity = 1024; janet_vm.cache_capacity = 1024;
janet_vm_cache = janet_calloc(1, (size_t) janet_vm_cache_capacity * sizeof(const uint8_t *)); janet_vm.cache = janet_calloc(1, (size_t) janet_vm.cache_capacity * sizeof(const uint8_t *));
if (NULL == janet_vm_cache) { if (NULL == janet_vm.cache) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_cache_count = 0; memset(&janet_vm.gensym_counter, 0, sizeof(janet_vm.gensym_counter));
janet_vm_cache_deleted = 0; janet_vm.cache_count = 0;
janet_vm.cache_deleted = 0;
} }
/* Deinitialize the cache (free the cache memory) */ /* Deinitialize the cache (free the cache memory) */
void janet_symcache_deinit() { void janet_symcache_deinit() {
janet_free((void *)janet_vm_cache); janet_free((void *)janet_vm.cache);
janet_vm_cache = NULL; janet_vm.cache = NULL;
janet_vm_cache_capacity = 0; janet_vm.cache_capacity = 0;
janet_vm_cache_count = 0; janet_vm.cache_count = 0;
janet_vm_cache_deleted = 0; janet_vm.cache_deleted = 0;
} }
/* Mark an entry in the table as deleted. */ /* 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, /* We will search two ranges - index to the end,
* and 0 to the index. */ * 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[0] = index;
bounds[1] = janet_vm_cache_capacity; bounds[1] = janet_vm.cache_capacity;
bounds[2] = 0; bounds[2] = 0;
bounds[3] = index; bounds[3] = index;
for (j = 0; j < 4; j += 2) for (j = 0; j < 4; j += 2)
for (i = bounds[j]; i < bounds[j + 1]; ++i) { 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 */ /* Check empty spots */
if (NULL == test) { if (NULL == test) {
if (NULL == firstEmpty) if (NULL == firstEmpty)
firstEmpty = janet_vm_cache + i; firstEmpty = janet_vm.cache + i;
goto notfound; goto notfound;
} }
/* Check for marked deleted */ /* Check for marked deleted */
if (JANET_SYMCACHE_DELETED == test) { if (JANET_SYMCACHE_DELETED == test) {
if (firstEmpty == NULL) if (firstEmpty == NULL)
firstEmpty = janet_vm_cache + i; firstEmpty = janet_vm.cache + i;
continue; continue;
} }
if (janet_string_equalconst(test, str, len, hash)) { if (janet_string_equalconst(test, str, len, hash)) {
@ -104,10 +99,10 @@ static const uint8_t **janet_symcache_findmem(
*success = 1; *success = 1;
if (firstEmpty != NULL) { if (firstEmpty != NULL) {
*firstEmpty = test; *firstEmpty = test;
janet_vm_cache[i] = JANET_SYMCACHE_DELETED; janet_vm.cache[i] = JANET_SYMCACHE_DELETED;
return firstEmpty; return firstEmpty;
} }
return janet_vm_cache + i; return janet_vm.cache + i;
} }
} }
notfound: notfound:
@ -121,15 +116,15 @@ notfound:
/* Resize the cache. */ /* Resize the cache. */
static void janet_cache_resize(uint32_t newCapacity) { static void janet_cache_resize(uint32_t newCapacity) {
uint32_t i, oldCapacity; 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 *)); const uint8_t **newCache = janet_calloc(1, (size_t) newCapacity * sizeof(const uint8_t *));
if (newCache == NULL) { if (newCache == NULL) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
oldCapacity = janet_vm_cache_capacity; oldCapacity = janet_vm.cache_capacity;
janet_vm_cache = newCache; janet_vm.cache = newCache;
janet_vm_cache_capacity = newCapacity; janet_vm.cache_capacity = newCapacity;
janet_vm_cache_deleted = 0; janet_vm.cache_deleted = 0;
/* Add all of the old cache entries back */ /* Add all of the old cache entries back */
for (i = 0; i < oldCapacity; ++i) { for (i = 0; i < oldCapacity; ++i) {
int status; int status;
@ -150,13 +145,13 @@ static void janet_cache_resize(uint32_t newCapacity) {
/* Add an item to the cache */ /* Add an item to the cache */
static void janet_symcache_put(const uint8_t *x, const uint8_t **bucket) { 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; 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); bucket = janet_symcache_find(x, &status);
} }
/* Add x to the cache */ /* Add x to the cache */
janet_vm_cache_count++; janet_vm.cache_count++;
*bucket = x; *bucket = x;
} }
@ -165,8 +160,8 @@ void janet_symbol_deinit(const uint8_t *sym) {
int status = 0; int status = 0;
const uint8_t **bucket = janet_symcache_find(sym, &status); const uint8_t **bucket = janet_symcache_find(sym, &status);
if (status) { if (status) {
janet_vm_cache_count--; janet_vm.cache_count--;
janet_vm_cache_deleted++; janet_vm.cache_deleted++;
*bucket = JANET_SYMCACHE_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)); 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 */ /* Increment the gensym buffer */
static void inc_gensym(void) { static void inc_gensym(void) {
for (int i = sizeof(gensym_counter) - 2; i; i--) { for (int i = sizeof(janet_vm.gensym_counter) - 2; i; i--) {
if (gensym_counter[i] == '9') { if (janet_vm.gensym_counter[i] == '9') {
gensym_counter[i] = 'a'; janet_vm.gensym_counter[i] = 'a';
break; break;
} else if (gensym_counter[i] == 'z') { } else if (janet_vm.gensym_counter[i] == 'z') {
gensym_counter[i] = 'A'; janet_vm.gensym_counter[i] = 'A';
break; break;
} else if (gensym_counter[i] == 'Z') { } else if (janet_vm.gensym_counter[i] == 'Z') {
gensym_counter[i] = '0'; janet_vm.gensym_counter[i] = '0';
} else { } else {
gensym_counter[i]++; janet_vm.gensym_counter[i]++;
break; break;
} }
} }
@ -227,19 +219,19 @@ const uint8_t *janet_symbol_gen(void) {
* is enough for resolving collisions. */ * is enough for resolving collisions. */
do { do {
hash = janet_string_calchash( hash = janet_string_calchash(
gensym_counter, janet_vm.gensym_counter,
sizeof(gensym_counter) - 1); sizeof(janet_vm.gensym_counter) - 1);
bucket = janet_symcache_findmem( bucket = janet_symcache_findmem(
gensym_counter, janet_vm.gensym_counter,
sizeof(gensym_counter) - 1, sizeof(janet_vm.gensym_counter) - 1,
hash, hash,
&status); &status);
} while (status && (inc_gensym(), 1)); } while (status && (inc_gensym(), 1));
JanetStringHead *head = janet_gcalloc(JANET_MEMORY_SYMBOL, sizeof(JanetStringHead) + sizeof(gensym_counter)); JanetStringHead *head = janet_gcalloc(JANET_MEMORY_SYMBOL, sizeof(JanetStringHead) + sizeof(janet_vm.gensym_counter));
head->length = sizeof(gensym_counter) - 1; head->length = sizeof(janet_vm.gensym_counter) - 1;
head->hash = hash; head->hash = hash;
sym = (uint8_t *)(head->data); 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); janet_symcache_put((const uint8_t *)sym, bucket);
return (const uint8_t *)sym; return (const uint8_t *)sym;
} }

View File

@ -71,25 +71,15 @@ struct JanetMailbox {
#define JANET_THREAD_CFUNCTIONS 0x4 #define JANET_THREAD_CFUNCTIONS 0x4
static const char janet_thread_flags[] = "hac"; 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) { static JanetTable *janet_thread_get_decode(void) {
if (janet_vm_thread_decode == NULL) { if (janet_vm.thread_decode == NULL) {
janet_vm_thread_decode = janet_get_core_table("load-image-dict"); janet_vm.thread_decode = janet_get_core_table("load-image-dict");
if (NULL == janet_vm_thread_decode) { if (NULL == janet_vm.thread_decode) {
janet_vm_thread_decode = janet_table(0); 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) { 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 /* Hack to capture all panics from marshalling. This works because
* we know janet_marshal won't mess with other essential global state. */ * we know janet_marshal won't mess with other essential global state. */
jmp_buf buf; jmp_buf buf;
jmp_buf *old_buf = janet_vm_jmp_buf; jmp_buf *old_buf = janet_vm.signal_buf;
janet_vm_jmp_buf = &buf; janet_vm.signal_buf = &buf;
int32_t oldmcount = mailbox->messageCount; int32_t oldmcount = mailbox->messageCount;
int ret = 0; int ret = 0;
@ -347,7 +337,7 @@ int janet_thread_send(JanetThread *thread, Janet msg, double timeout) {
} }
/* Cleanup */ /* Cleanup */
janet_vm_jmp_buf = old_buf; janet_vm.signal_buf = old_buf;
janet_mailbox_unlock(mailbox); janet_mailbox_unlock(mailbox);
/* Potentially wake up a blocked thread */ /* 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 */ /* Returns 0 on successful message. Returns 1 if timedout */
int janet_thread_receive(Janet *msg_out, double timeout) { int janet_thread_receive(Janet *msg_out, double timeout) {
JanetMailbox *mailbox = janet_vm_mailbox; JanetMailbox *mailbox = janet_vm.mailbox;
janet_mailbox_lock(mailbox); janet_mailbox_lock(mailbox);
/* For timeouts */ /* 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 /* Hack to capture all panics from marshalling. This works because
* we know janet_marshal won't mess with other essential global state. */ * we know janet_marshal won't mess with other essential global state. */
jmp_buf buf; jmp_buf buf;
jmp_buf *old_buf = janet_vm_jmp_buf; jmp_buf *old_buf = janet_vm.signal_buf;
janet_vm_jmp_buf = &buf; janet_vm.signal_buf = &buf;
/* Handle errors */ /* Handle errors */
if (setjmp(buf)) { if (setjmp(buf)) {
/* Cleanup jmp_buf, return error. /* Cleanup jmp_buf, return error.
* Do not ignore bad messages as before. */ * Do not ignore bad messages as before. */
janet_vm_jmp_buf = old_buf; janet_vm.signal_buf = old_buf;
*msg_out = *janet_vm_return_reg; *msg_out = *janet_vm.return_reg;
janet_mailbox_unlock(mailbox); janet_mailbox_unlock(mailbox);
return 2; return 2;
} else { } else {
@ -397,7 +387,7 @@ int janet_thread_receive(Janet *msg_out, double timeout) {
*msg_out = item; *msg_out = item;
/* Cleanup */ /* Cleanup */
janet_vm_jmp_buf = old_buf; janet_vm.signal_buf = old_buf;
janet_mailbox_unlock(mailbox); janet_mailbox_unlock(mailbox);
/* Potentially wake up pending threads */ /* Potentially wake up pending threads */
@ -455,21 +445,21 @@ static int thread_worker(JanetMailboxPair *pair) {
JanetFiber *fiber = NULL; JanetFiber *fiber = NULL;
Janet out; Janet out;
/* Use the mailbox we were given */
janet_vm_mailbox = pair->newbox;
janet_mailbox_ref(pair->newbox, 1);
/* Init VM */ /* Init VM */
janet_init(); 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 */ /* Get dictionaries for default encode/decode */
JanetTable *encode; JanetTable *encode;
if (pair->flags & JANET_THREAD_HEAVYWEIGHT) { if (pair->flags & JANET_THREAD_HEAVYWEIGHT) {
encode = janet_get_core_table("make-image-dict"); encode = janet_get_core_table("make-image-dict");
} else { } else {
encode = NULL; encode = NULL;
janet_vm_thread_decode = janet_table(0); 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));
} }
/* Create parent thread */ /* Create parent thread */
@ -482,9 +472,9 @@ static int thread_worker(JanetMailboxPair *pair) {
int status = janet_thread_receive(&reg, INFINITY); int status = janet_thread_receive(&reg, INFINITY);
if (status) goto error; if (status) goto error;
if (!janet_checktype(reg, JANET_TABLE)) goto error; if (!janet_checktype(reg, JANET_TABLE)) goto error;
janet_gcunroot(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_vm.abstract_registry = janet_unwrap_table(reg);
janet_gcroot(janet_wrap_table(janet_vm_abstract_registry)); janet_gcroot(janet_wrap_table(janet_vm.abstract_registry));
} }
/* Unmarshal the normal registry */ /* Unmarshal the normal registry */
@ -493,9 +483,9 @@ static int thread_worker(JanetMailboxPair *pair) {
int status = janet_thread_receive(&reg, INFINITY); int status = janet_thread_receive(&reg, INFINITY);
if (status) goto error; if (status) goto error;
if (!janet_checktype(reg, JANET_TABLE)) goto error; if (!janet_checktype(reg, JANET_TABLE)) goto error;
janet_gcunroot(janet_wrap_table(janet_vm_registry)); janet_gcunroot(janet_wrap_table(janet_vm.registry));
janet_vm_registry = janet_unwrap_table(reg); janet_vm.registry = janet_unwrap_table(reg);
janet_gcroot(janet_wrap_table(janet_vm_registry)); janet_gcroot(janet_wrap_table(janet_vm.registry));
} }
/* Unmarshal the function */ /* Unmarshal the function */
@ -580,28 +570,26 @@ static int janet_thread_start_child(JanetMailboxPair *pair) {
*/ */
void janet_threads_init(void) { void janet_threads_init(void) {
if (NULL == janet_vm_mailbox) { janet_vm.mailbox = janet_mailbox_create(1, 10);
janet_vm_mailbox = janet_mailbox_create(1, 10); janet_vm.thread_decode = NULL;
} janet_vm.thread_current = NULL;
janet_vm_thread_decode = NULL;
janet_vm_thread_current = NULL;
} }
void janet_threads_deinit(void) { void janet_threads_deinit(void) {
janet_mailbox_lock(janet_vm_mailbox); janet_mailbox_lock(janet_vm.mailbox);
janet_vm_mailbox->closed = 1; janet_vm.mailbox->closed = 1;
janet_mailbox_ref_with_lock(janet_vm_mailbox, -1); janet_mailbox_ref_with_lock(janet_vm.mailbox, -1);
janet_vm_mailbox = NULL; janet_vm.mailbox = NULL;
janet_vm_thread_current = NULL; janet_vm.thread_current = NULL;
janet_vm_thread_decode = NULL; janet_vm.thread_decode = NULL;
} }
JanetThread *janet_thread_current(void) { JanetThread *janet_thread_current(void) {
if (NULL == 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_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)); 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; 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); JanetThread *thread = janet_make_thread(pair->newbox, encode);
if (janet_thread_start_child(pair)) { if (janet_thread_start_child(pair)) {
destroy_mailbox_pair(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 (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"); janet_panic("could not send abstract registry to thread");
} }
} }
if (flags & JANET_THREAD_CFUNCTIONS) { 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"); janet_panic("could not send registry to thread");
} }
} }

View File

@ -366,7 +366,7 @@ const void *janet_strbinsearch(
void janet_register(const char *name, JanetCFunction cfun) { void janet_register(const char *name, JanetCFunction cfun) {
Janet key = janet_wrap_cfunction(cfun); Janet key = janet_wrap_cfunction(cfun);
Janet value = janet_csymbolv(name); 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 */ /* Add a def to an environment */
@ -433,7 +433,7 @@ static void _janet_cfuns_prefix(JanetTable *env, const char *regprefix, const Ja
} else { } else {
janet_def(env, cfuns->name, fun, cfuns->documentation); 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++; cfuns++;
} }
(janet_free)(longname_buffer); (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) { void janet_register_abstract_type(const JanetAbstractType *at) {
Janet sym = janet_csymbolv(at->name); 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)) { if (!janet_checktype(check, JANET_NIL) && at != janet_unwrap_pointer(check)) {
janet_panicf("cannot register abstract type %s, " janet_panicf("cannot register abstract type %s, "
"a type with the same name exists", at->name); "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) { 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)) { if (janet_checktype(wrapped, JANET_NIL)) {
return NULL; 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 key = janet_csymbolv(name);
janet_table_put(env, key, x); janet_table_put(env, key, x);
if (janet_checktype(x, JANET_CFUNCTION)) { if (janet_checktype(x, JANET_CFUNCTION)) {
janet_table_put(janet_vm_registry, x, key); janet_table_put(janet_vm.registry, x, key);
} }
} }

View File

@ -31,31 +31,27 @@
#include <math.h> #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) { static void push_traversal_node(void *lhs, void *rhs, int32_t index2) {
JanetTraversalNode node; JanetTraversalNode node;
node.self = (JanetGCObject *) lhs; node.self = (JanetGCObject *) lhs;
node.other = (JanetGCObject *) rhs; node.other = (JanetGCObject *) rhs;
node.index = 0; node.index = 0;
node.index2 = index2; node.index2 = index2;
if (janet_vm_traversal + 1 >= janet_vm_traversal_top) { if (janet_vm.traversal + 1 >= janet_vm.traversal_top) {
size_t oldsize = janet_vm_traversal - janet_vm_traversal_base; size_t oldsize = janet_vm.traversal - janet_vm.traversal_base;
size_t newsize = 2 * oldsize + 1; size_t newsize = 2 * oldsize + 1;
if (newsize < 128) { if (newsize < 128) {
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) { if (tn == NULL) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_vm_traversal_base = tn; janet_vm.traversal_base = tn;
janet_vm_traversal_top = janet_vm_traversal_base + newsize; janet_vm.traversal_top = janet_vm.traversal_base + newsize;
janet_vm_traversal = janet_vm_traversal_base + oldsize; 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 * 3 - early stop - lhs > rhs
*/ */
static int traversal_next(Janet *x, Janet *y) { static int traversal_next(Janet *x, Janet *y) {
JanetTraversalNode *t = janet_vm_traversal; JanetTraversalNode *t = janet_vm.traversal;
while (t && t > janet_vm_traversal_base) { while (t && t > janet_vm.traversal_base) {
JanetGCObject *self = t->self; JanetGCObject *self = t->self;
JanetTupleHead *tself = (JanetTupleHead *)self; JanetTupleHead *tself = (JanetTupleHead *)self;
JanetStructHead *sself = (JanetStructHead *)self; JanetStructHead *sself = (JanetStructHead *)self;
@ -81,7 +77,7 @@ static int traversal_next(Janet *x, Janet *y) {
int32_t index = t->index++; int32_t index = t->index++;
*x = tself->data[index]; *x = tself->data[index];
*y = tother->data[index]; *y = tother->data[index];
janet_vm_traversal = t; janet_vm.traversal = t;
return 0; return 0;
} }
if (t->index2 && tself->length != tother->length) { if (t->index2 && tself->length != tother->length) {
@ -94,20 +90,20 @@ static int traversal_next(Janet *x, Janet *y) {
int32_t index = t->index++; int32_t index = t->index++;
*x = sself->data[index].value; *x = sself->data[index].value;
*y = sother->data[index].value; *y = sother->data[index].value;
janet_vm_traversal = t; janet_vm.traversal = t;
return 0; return 0;
} }
for (int32_t i = t->index; i < sself->capacity; i++) { for (int32_t i = t->index; i < sself->capacity; i++) {
t->index2 = 1; t->index2 = 1;
*x = sself->data[t->index].key; *x = sself->data[t->index].key;
*y = sother->data[t->index].key; *y = sother->data[t->index].key;
janet_vm_traversal = t; janet_vm.traversal = t;
return 0; return 0;
} }
} }
t--; t--;
} }
janet_vm_traversal = t; janet_vm.traversal = t;
return 2; return 2;
} }
@ -196,17 +192,17 @@ Janet janet_next_impl(Janet ds, Janet key, int is_interpreter) {
status == JANET_STATUS_USER4) { status == JANET_STATUS_USER4) {
return janet_wrap_nil(); return janet_wrap_nil();
} }
janet_vm_fiber->child = child; janet_vm.fiber->child = child;
JanetSignal sig = janet_continue(child, janet_wrap_nil(), &retreg); JanetSignal sig = janet_continue(child, janet_wrap_nil(), &retreg);
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) { if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
if (is_interpreter) { if (is_interpreter) {
janet_signalv(sig, retreg); janet_signalv(sig, retreg);
} else { } else {
janet_vm_fiber->child = NULL; janet_vm.fiber->child = NULL;
janet_panicv(retreg); janet_panicv(retreg);
} }
} }
janet_vm_fiber->child = NULL; janet_vm.fiber->child = NULL;
if (sig == JANET_SIGNAL_OK || if (sig == JANET_SIGNAL_OK ||
sig == JANET_SIGNAL_ERROR || sig == JANET_SIGNAL_ERROR ||
sig == JANET_SIGNAL_USER0 || sig == JANET_SIGNAL_USER0 ||
@ -239,7 +235,7 @@ static int janet_compare_abstract(JanetAbstract xx, JanetAbstract yy) {
} }
int janet_equals(Janet x, Janet y) { int janet_equals(Janet x, Janet y) {
janet_vm_traversal = janet_vm_traversal_base; janet_vm.traversal = janet_vm.traversal_base;
do { do {
if (janet_type(x) != janet_type(y)) return 0; if (janet_type(x) != janet_type(y)) return 0;
switch (janet_type(x)) { switch (janet_type(x)) {
@ -347,7 +343,7 @@ int32_t janet_hash(Janet x) {
* If y is less, returns 1. All types are comparable * If y is less, returns 1. All types are comparable
* and should have strict ordering, excepts NaNs. */ * and should have strict ordering, excepts NaNs. */
int janet_compare(Janet x, Janet y) { int janet_compare(Janet x, Janet y) {
janet_vm_traversal = janet_vm_traversal_base; janet_vm.traversal = janet_vm.traversal_base;
int status; int status;
do { do {
JanetType tx = janet_type(x); JanetType tx = janet_type(x);

View File

@ -32,17 +32,6 @@
#include <math.h> #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 /* Virtual registers
* *
* One instruction word * One instruction word
@ -91,18 +80,18 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
func = janet_stack_frame(stack)->func; \ func = janet_stack_frame(stack)->func; \
} while (0) } while (0)
#define vm_return(sig, val) do { \ #define vm_return(sig, val) do { \
janet_vm_return_reg[0] = (val); \ janet_vm.return_reg[0] = (val); \
vm_commit(); \ vm_commit(); \
return (sig); \ return (sig); \
} while (0) } while (0)
#define vm_return_no_restore(sig, val) do { \ #define vm_return_no_restore(sig, val) do { \
janet_vm_return_reg[0] = (val); \ janet_vm.return_reg[0] = (val); \
return (sig); \ return (sig); \
} while (0) } while (0)
/* Next instruction variations */ /* Next instruction variations */
#define maybe_collect() do {\ #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_checkgc_next() maybe_collect(); vm_next()
#define vm_pcnext() pc++; vm_next() #define vm_pcnext() pc++; vm_next()
#define vm_checkgc_pcnext() maybe_collect(); vm_pcnext() #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; JanetSignal sig = (fiber->gc.flags & JANET_FIBER_STATUS_MASK) >> JANET_FIBER_STATUS_OFFSET;
fiber->gc.flags &= ~JANET_FIBER_STATUS_MASK; fiber->gc.flags &= ~JANET_FIBER_STATUS_MASK;
fiber->flags &= ~(JANET_FIBER_RESUME_SIGNAL | JANET_FIBER_FLAG_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; 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) { Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
/* Check entry conditions */ /* Check entry conditions */
if (!janet_vm_fiber) if (!janet_vm.fiber)
janet_panic("janet_call failed because there is no current 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"); janet_panic("C stack recursed too deeply");
/* Tracing */ /* Tracing */
@ -1290,8 +1279,8 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
} }
/* Push frame */ /* Push frame */
janet_fiber_pushn(janet_vm_fiber, argv, argc); janet_fiber_pushn(janet_vm.fiber, argv, argc);
if (janet_fiber_funcframe(janet_vm_fiber, fun)) { if (janet_fiber_funcframe(janet_vm.fiber, fun)) {
int32_t min = fun->def->min_arity; int32_t min = fun->def->min_arity;
int32_t max = fun->def->max_arity; int32_t max = fun->def->max_arity;
Janet funv = janet_wrap_function(fun); 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 least %d, got %d", funv, min, argc);
janet_panicf("arity mismatch in %v, expected at most %d, got %d", funv, max, 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 */ /* Set up */
int32_t oldn = janet_vm_stackn++; int32_t oldn = janet_vm.stackn++;
int handle = janet_gclock(); int handle = janet_gclock();
/* Run vm */ /* Run vm */
janet_vm_fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP; janet_vm.fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
JanetSignal signal = run_vm(janet_vm_fiber, janet_wrap_nil()); JanetSignal signal = run_vm(janet_vm.fiber, janet_wrap_nil());
/* Teardown */ /* Teardown */
janet_vm_stackn = oldn; janet_vm.stackn = oldn;
janet_gcunlock(handle); janet_gcunlock(handle);
if (signal != JANET_SIGNAL_OK) { 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) { static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
/* Check conditions */ /* Check conditions */
JanetFiberStatus old_status = janet_fiber_status(fiber); 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); janet_fiber_set_status(fiber, JANET_STATUS_ERROR);
*out = janet_cstringv("C stack recursed too deeply"); *out = janet_cstringv("C stack recursed too deeply");
return JANET_SIGNAL_ERROR; return JANET_SIGNAL_ERROR;
@ -1343,21 +1332,21 @@ static JanetSignal janet_check_can_resume(JanetFiber *fiber, Janet *out) {
} }
void janet_try_init(JanetTryState *state) { void janet_try_init(JanetTryState *state) {
state->stackn = janet_vm_stackn++; state->stackn = janet_vm.stackn++;
state->gc_handle = janet_vm_gc_suspend; state->gc_handle = janet_vm.gc_suspend;
state->vm_fiber = janet_vm_fiber; state->vm_fiber = janet_vm.fiber;
state->vm_jmp_buf = janet_vm_jmp_buf; state->vm_jmp_buf = janet_vm.signal_buf;
state->vm_return_reg = janet_vm_return_reg; state->vm_return_reg = janet_vm.return_reg;
janet_vm_return_reg = &(state->payload); janet_vm.return_reg = &(state->payload);
janet_vm_jmp_buf = &(state->buf); janet_vm.signal_buf = &(state->buf);
} }
void janet_restore(JanetTryState *state) { void janet_restore(JanetTryState *state) {
janet_vm_stackn = state->stackn; janet_vm.stackn = state->stackn;
janet_vm_gc_suspend = state->gc_handle; janet_vm.gc_suspend = state->gc_handle;
janet_vm_fiber = state->vm_fiber; janet_vm.fiber = state->vm_fiber;
janet_vm_jmp_buf = state->vm_jmp_buf; janet_vm.signal_buf = state->vm_jmp_buf;
janet_vm_return_reg = state->vm_return_reg; janet_vm.return_reg = state->vm_return_reg;
} }
static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *out) { 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 */ /* Continue child fiber if it exists */
if (fiber->child) { 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; JanetFiber *child = fiber->child;
uint32_t instr = (janet_stack_frame(fiber->data + fiber->frame)->pc)[0]; 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); JanetSignal sig = janet_continue(child, in, &in);
janet_vm_stackn--; janet_vm.stackn--;
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL; if (janet_vm.root_fiber == fiber) janet_vm.root_fiber = NULL;
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) { if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
*out = in; *out = in;
janet_fiber_set_status(fiber, sig); 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); JanetSignal sig = janet_try(&tstate);
if (!sig) { if (!sig) {
/* Normal setup */ /* Normal setup */
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber; if (janet_vm.root_fiber == NULL) janet_vm.root_fiber = fiber;
janet_vm_fiber = fiber; janet_vm.fiber = fiber;
janet_fiber_set_status(fiber, JANET_STATUS_ALIVE); janet_fiber_set_status(fiber, JANET_STATUS_ALIVE);
sig = run_vm(fiber, in); sig = run_vm(fiber, in);
} }
/* Restore */ /* 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_fiber_set_status(fiber, sig);
janet_restore(&tstate); janet_restore(&tstate);
fiber->last_value = tstate.payload; fiber->last_value = tstate.payload;
@ -1497,39 +1486,50 @@ Janet janet_mcall(const char *name, int32_t argc, Janet *argv) {
/* Setup VM */ /* Setup VM */
int janet_init(void) { int janet_init(void) {
/* Garbage collection */ /* Garbage collection */
janet_vm_blocks = NULL; janet_vm.blocks = NULL;
janet_vm_next_collection = 0; janet_vm.next_collection = 0;
janet_vm_gc_interval = 0x400000; janet_vm.gc_interval = 0x400000;
janet_vm_block_count = 0; janet_vm.block_count = 0;
janet_symcache_init(); janet_symcache_init();
/* Initialize gc roots */ /* Initialize gc roots */
janet_vm_roots = NULL; janet_vm.roots = NULL;
janet_vm_root_count = 0; janet_vm.root_count = 0;
janet_vm_root_capacity = 0; janet_vm.root_capacity = 0;
/* Scratch memory */ /* Scratch memory */
janet_scratch_mem = NULL; janet_vm.scratch_mem = NULL;
janet_scratch_len = 0; janet_vm.scratch_len = 0;
janet_scratch_cap = 0; janet_vm.scratch_cap = 0;
/* Initialize registry */ /* Initialize registry */
janet_vm_registry = janet_table(0); janet_vm.registry = janet_table(0);
janet_vm_abstract_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.registry));
janet_gcroot(janet_wrap_table(janet_vm_abstract_registry)); janet_gcroot(janet_wrap_table(janet_vm.abstract_registry));
/* Traversal */ /* Traversal */
janet_vm_traversal = NULL; janet_vm.traversal = NULL;
janet_vm_traversal_base = NULL; janet_vm.traversal_base = NULL;
janet_vm_traversal_top = NULL; janet_vm.traversal_top = NULL;
/* Core env */ /* Core env */
janet_vm_core_env = NULL; janet_vm.core_env = NULL;
/* Dynamic bindings */ /* Dynamic bindings */
janet_vm_top_dyns = NULL; janet_vm.top_dyns = NULL;
/* Seed RNG */ /* Seed RNG */
janet_rng_seed(janet_default_rng(), 0); janet_rng_seed(janet_default_rng(), 0);
/* Fibers */ /* Fibers */
janet_vm_fiber = NULL; janet_vm.fiber = NULL;
janet_vm_root_fiber = NULL; janet_vm.root_fiber = NULL;
janet_vm_stackn = 0; janet_vm.stackn = 0;
#ifdef JANET_THREADS #ifdef JANET_THREADS
janet_threads_init(); janet_threads_init();
#endif #endif
@ -1546,17 +1546,17 @@ int janet_init(void) {
void janet_deinit(void) { void janet_deinit(void) {
janet_clear_memory(); janet_clear_memory();
janet_symcache_deinit(); janet_symcache_deinit();
janet_free(janet_vm_roots); janet_free(janet_vm.roots);
janet_vm_roots = NULL; janet_vm.roots = NULL;
janet_vm_root_count = 0; janet_vm.root_count = 0;
janet_vm_root_capacity = 0; janet_vm.root_capacity = 0;
janet_vm_registry = NULL; janet_vm.registry = NULL;
janet_vm_abstract_registry = NULL; janet_vm.abstract_registry = NULL;
janet_vm_core_env = NULL; janet_vm.core_env = NULL;
janet_vm_top_dyns = NULL; janet_vm.top_dyns = NULL;
janet_free(janet_vm_traversal_base); janet_free(janet_vm.traversal_base);
janet_vm_fiber = NULL; janet_vm.fiber = NULL;
janet_vm_root_fiber = NULL; janet_vm.root_fiber = NULL;
#ifdef JANET_THREADS #ifdef JANET_THREADS
janet_threads_deinit(); janet_threads_deinit();
#endif #endif

View File

@ -163,7 +163,7 @@ Janet(janet_wrap_number)(double x) {
void *janet_memalloc_empty(int32_t count) { void *janet_memalloc_empty(int32_t count) {
int32_t i; int32_t i;
void *mem = janet_malloc((size_t) count * sizeof(JanetKV)); 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) { if (NULL == mem) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }

View File

@ -365,6 +365,9 @@ typedef enum {
JANET_STATUS_ALIVE JANET_STATUS_ALIVE
} JanetFiberStatus; } JanetFiberStatus;
/* For encapsulating all thread-local Janet state (except natives) */
typedef struct JanetVM JanetVM;
/* Use type punning for GC objects */ /* Use type punning for GC objects */
typedef struct JanetGCObject JanetGCObject; 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 */ /* VM functions */
JANET_API int janet_init(void); JANET_API int janet_init(void);
JANET_API void janet_deinit(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(JanetFiber *fiber, Janet in, Janet *out);
JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig); 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); JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);