1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-30 09:03:15 +00:00

Switch to assymetric coroutines instead of symmetric.

This commit is contained in:
Calvin Rose 2018-03-11 15:35:23 -04:00
parent 0b6ac1698c
commit 2a0dc5f1ad
19 changed files with 301 additions and 316 deletions

View File

@ -85,6 +85,7 @@ src/core/vm.c
src/core/wrap.c src/core/wrap.c
src/core/gc.h src/core/gc.h
src/core/fiber.h
src/core/symcache.h src/core/symcache.h
src/core/util.h src/core/util.h
) )

View File

@ -120,6 +120,7 @@ static const DstInstructionDef dst_ops[] = {
{"push3", DOP_PUSH_3}, {"push3", DOP_PUSH_3},
{"put", DOP_PUT}, {"put", DOP_PUT},
{"puti", DOP_PUT_INDEX}, {"puti", DOP_PUT_INDEX},
{"res", DOP_RESUME},
{"ret", DOP_RETURN}, {"ret", DOP_RETURN},
{"retn", DOP_RETURN_NIL}, {"retn", DOP_RETURN_NIL},
{"setu", DOP_SET_UPVALUE}, {"setu", DOP_SET_UPVALUE},
@ -131,8 +132,8 @@ static const DstInstructionDef dst_ops[] = {
{"sruim", DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE}, {"sruim", DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE},
{"sub", DOP_SUBTRACT}, {"sub", DOP_SUBTRACT},
{"tcall", DOP_TAILCALL}, {"tcall", DOP_TAILCALL},
{"tran", DOP_TRANSFER}, {"tchck", DOP_TYPECHECK},
{"tchck", DOP_TYPECHECK} {"yield", DOP_YIELD}
}; };
/* Check a dst string against a bunch of test_strings. Return the /* Check a dst string against a bunch of test_strings. Return the

View File

@ -25,9 +25,18 @@
(varset! i (+ i 1)) (varset! i (+ i 1))
ret) ret)
}) })
(defn fiber-seq [x]
{
:more (fn [] (or
(= (fiber-status x) :pending)
(= (fiber-status x) :new)))
:next (fn []
(resume x))
})
(def seqs { (def seqs {
:array array-seq :array array-seq
:tuple array-seq :tuple array-seq
:fiber fiber-seq
:struct (fn [x] x)}) :struct (fn [x] x)})
(fn [x] (fn [x]
(def makeseq (get seqs (type x))) (def makeseq (get seqs (type x)))
@ -81,8 +90,7 @@
(tuple 'def endsym end) (tuple 'def endsym end)
(tuple 'while (tuple '< sym endsym) (tuple 'while (tuple '< sym endsym)
(tuple-prepend body 'do) (tuple-prepend body 'do)
(tuple 'varset! sym (tuple '+ sym 1)) (tuple 'varset! sym (tuple '+ sym 1)))))
)))
(defn pairs [x] (defn pairs [x]
(var lastkey (next x nil)) (var lastkey (next x nil))
@ -118,15 +126,15 @@
(var *read* nil) (var *read* nil)
(var *onvalue* identity) (var *onvalue* identity)
(var *env* _env) (var *env* (setproto @{} _env))
(def require-loading @{}) (def require-loading @{})
(defn onerr [t e] (defn onerr [t e]
(print (string t " error: " e))) (print (string t " error: " e)))
(defn char-stream [getchunk ondone] (defn char-stream [getchunk]
(fiber (fn [parent] (fiber (fn []
(def buf @"") (def buf @"")
(var len 1) (var len 1)
(while (< 0 len) (while (< 0 len)
@ -134,66 +142,75 @@
(getchunk buf) (getchunk buf)
(varset! len (length buf)) (varset! len (length buf))
(for [i 0 len] (for [i 0 len]
(transfer parent (get buf i)))) (yield (get buf i))))
(ondone)))) 0)))
(defn val-stream [chars] (defn val-stream [chars ondone]
(fiber (fn [parent] (fiber (fn []
(var up parent)
(def me (fiber-current))
(def p (parser 1)) (def p (parser 1))
(while true (var going true)
(while going
(def s (parser-status p)) (def s (parser-status p))
(if (= s :full) (if (= s :full)
(varset! up (transfer up (parser-produce p))) (yield (parser-produce p))
(if (= s :error) (if (= s :error)
(onerr "parse" (parser-error p)) (onerr "parse" (parser-error p))
(parser-byte p (transfer chars me)))))))) (do
(def stat (fiber-status chars))
(if (or (= :new stat) (= :pending stat))
(parser-byte p (resume chars))
(varset! going false))))))
(ondone))))
(defn require [path] (defn require [path]
(when (get require-loading path) (when (get require-loading path)
(error (string "circular dependency: module " path "is already loading"))) (error (string "circular dependency: module " path " is already loading")))
(def oldread *read*) (def oldread *read*)
(def oldonvalue *onvalue*) (def oldonvalue *onvalue*)
(def oldenv *env*)
(def f (file-open path)) (def f (file-open path))
(def getter (fn [buf] (file-read f 1024 buf) buf)) (defn getter [buf] (file-read f 1024 buf) buf)
(def cs (char-stream getter (fn [] (defn resetter []
(put require-loading path nil) (put require-loading path nil)
(file-close f)
(varset! *read* oldread) (varset! *read* oldread)
(varset! *onvalue* oldonvalue) (varset! *onvalue* oldonvalue)
nil))) (varset! *env* oldenv)
(def vs (val-stream cs)) (file-close f)
(varset! *onvalue* identity)
(varset! *read* (fn [] (transfer vs (fiber-current))))
nil) nil)
(def cs (char-stream getter))
(def vs (val-stream cs resetter))
(varset! *onvalue* identity)
(varset! *read* (fn [] (resume vs)))
(varset! *env* (setproto @{} _env))
*env*)
(defn dorepl [] (defn dorepl []
(def oldread *read*) (def oldread *read*)
(def cs (char-stream (fn [buf] (defn getter [buf]
(file-write stdout ">> ") (file-write stdout ">> ")
(file-read stdin :line buf)) (file-read stdin :line buf))
(fn [] (defn resetter []
(varset! *read* oldread) (varset! *read* oldread)
nil))) nil)
(def vs (val-stream cs)) (def cs (char-stream getter))
(def vs (val-stream cs resetter))
(varset! *onvalue* (fn [ret] (varset! *onvalue* (fn [ret]
(put _env '_ @{'value ret}) (put *env* '_ @{'value ret})
(describe ret))) (describe ret)))
(varset! *read* (fn [] (transfer vs (fiber-current))))) (varset! *read* (fn [] (resume vs))))
(defn dostring [str] (defn dostring [str]
(def oldread *read*) (def oldread *read*)
(def cs (char-stream (fn [buf] (defn getter [buf]
(buffer-push-string buf str) (buffer-push-string buf str)
(buffer-push-string buf "\n") (buffer-push-string buf "\n"))
buf) (defn resetter []
(fn []
(varset! *read* oldread) (varset! *read* oldread)
nil))) nil)
(def vs (val-stream cs)) (def cs (char-stream getter))
(def vs (val-stream cs resetter))
(varset! *onvalue* identity) (varset! *onvalue* identity)
(varset! *read* (fn [] (transfer vs (fiber-current))))) (varset! *read* (fn [] (resume vs))))
(defn init-loop [] (defn init-loop []
(while *read* (while *read*
@ -204,7 +221,7 @@
(if (= (type res) :function) (if (= (type res) :function)
(*onvalue* (res)) (*onvalue* (res))
(onerr "compile" (get res :error))))))) (onerr "compile" (get res :error)))))))
(def eb (transfer wrapper)) (def eb (resume wrapper))
(if (= (fiber-status wrapper) :error) (onerr "runtime" eb)))) (if (= (fiber-status wrapper) :error) (onerr "runtime" eb wrapper))))
(defn init-repl [] (dorepl) (init-loop)) (defn init-repl [] (dorepl) (init-loop))

View File

@ -813,7 +813,6 @@ recur:
} else { } else {
/* Check macro */ /* Check macro */
DstTable *env = c->env; DstTable *env = c->env;
int status;
Dst fn; Dst fn;
Dst entry = dst_table_get(env, headval); Dst entry = dst_table_get(env, headval);
for (;;) { for (;;) {
@ -825,8 +824,11 @@ recur:
dstc_cerror(c, ast, "macro expansion recursed too deeply"); dstc_cerror(c, ast, "macro expansion recursed too deeply");
return dstc_cslot(dst_wrap_nil()); return dstc_cslot(dst_wrap_nil());
} else { } else {
status = dst_call_suspend(fn, &x, dst_tuple_length(tup) - 1, tup + 1); DstFiber *f = dst_fiber(dst_unwrap_function(fn), 64);
if (status) { int lock = dst_gclock();
x = dst_resume(f, dst_tuple_length(tup) - 1, tup + 1);
dst_gcunlock(lock);
if (f->status == DST_FIBER_ERROR || f->status == DST_FIBER_DEBUG) {
dstc_cerror(c, ast, "error in macro expansion"); dstc_cerror(c, ast, "error in macro expansion");
} }
/* Tail recur on the value */ /* Tail recur on the value */

View File

@ -41,8 +41,9 @@ int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len) {
DstCompileResult cres = dst_compile(form, env, 0); DstCompileResult cres = dst_compile(form, env, 0);
if (cres.status == DST_COMPILE_OK) { if (cres.status == DST_COMPILE_OK) {
DstFunction *f = dst_thunk(cres.funcdef); DstFunction *f = dst_thunk(cres.funcdef);
Dst ret; DstFiber *fiber = dst_fiber(f, 64);
if (dst_run(dst_wrap_function(f), &ret)) { Dst ret = dst_run(fiber);
if (fiber->status != DST_FIBER_DEAD) {
printf("internal runtime error: %s\n", (const char *) dst_to_string(ret)); printf("internal runtime error: %s\n", (const char *) dst_to_string(ret));
errflags |= 0x01; errflags |= 0x01;
} }

View File

@ -43,7 +43,6 @@ static const DstReg cfuns[] = {
{"struct", dst_core_struct}, {"struct", dst_core_struct},
{"fiber", dst_core_fiber}, {"fiber", dst_core_fiber},
{"fiber-status", dst_core_fiber_status}, {"fiber-status", dst_core_fiber_status},
{"fiber-current", dst_core_fiber_current},
{"buffer", dst_core_buffer}, {"buffer", dst_core_buffer},
{"gensym", dst_core_gensym}, {"gensym", dst_core_gensym},
{"get", dst_core_get}, {"get", dst_core_get},
@ -74,13 +73,12 @@ DstTable *dst_stl_env() {
}; };
static uint32_t yield_asm[] = { static uint32_t yield_asm[] = {
DOP_LOAD_NIL | (1 << 8), DOP_YIELD,
DOP_TRANSFER | (1 << 16),
DOP_RETURN DOP_RETURN
}; };
static uint32_t transfer_asm[] = { static uint32_t resume_asm[] = {
DOP_TRANSFER | (1 << 24), DOP_RESUME | (1 << 24),
DOP_RETURN DOP_RETURN
}; };
@ -93,13 +91,10 @@ DstTable *dst_stl_env() {
dst_env_def(env, "error", dst_wrap_function(dst_quick_asm(1, 0, 1, error_asm, sizeof(error_asm)))); dst_env_def(env, "error", dst_wrap_function(dst_quick_asm(1, 0, 1, error_asm, sizeof(error_asm))));
dst_env_def(env, "apply", dst_wrap_function(dst_quick_asm(2, 0, 2, apply_asm, sizeof(apply_asm)))); dst_env_def(env, "apply", dst_wrap_function(dst_quick_asm(2, 0, 2, apply_asm, sizeof(apply_asm))));
dst_env_def(env, "yield", dst_wrap_function(dst_quick_asm(1, 0, 2, yield_asm, sizeof(yield_asm)))); dst_env_def(env, "yield", dst_wrap_function(dst_quick_asm(1, 0, 2, yield_asm, sizeof(yield_asm))));
dst_env_def(env, "transfer", dst_wrap_function(dst_quick_asm(2, 0, 2, transfer_asm, sizeof(transfer_asm)))); dst_env_def(env, "resume", dst_wrap_function(dst_quick_asm(2, 0, 2, resume_asm, sizeof(resume_asm))));
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION)); dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
/* Allow references to the environment */
dst_env_def(env, "_env", ret);
/* Set as gc root */ /* Set as gc root */
dst_gcroot(dst_wrap_table(env)); dst_gcroot(dst_wrap_table(env));
@ -119,6 +114,9 @@ DstTable *dst_stl_env() {
dst_lib_asm(args); dst_lib_asm(args);
} }
/* Allow references to the environment */
dst_env_def(env, "_env", ret);
/* Run bootstrap source */ /* Run bootstrap source */
dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen)); dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen));

View File

@ -80,7 +80,8 @@ enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT] = {
DIT_S, /* DOP_PUSH_ARRAY, */ DIT_S, /* DOP_PUSH_ARRAY, */
DIT_SS, /* DOP_CALL, */ DIT_SS, /* DOP_CALL, */
DIT_S, /* DOP_TAILCALL, */ DIT_S, /* DOP_TAILCALL, */
DIT_SSS, /* DOP_TRANSFER, */ DIT_SSS, /* DOP_RESUME, */
DIT_SS, /* DOP_YIELD, */
DIT_SSS, /* DOP_GET, */ DIT_SSS, /* DOP_GET, */
DIT_SSS, /* DOP_PUT, */ DIT_SSS, /* DOP_PUT, */
DIT_SSU, /* DOP_GET_INDEX, */ DIT_SSU, /* DOP_GET_INDEX, */

View File

@ -137,10 +137,9 @@ int dst_core_struct(DstArgs args) {
int dst_core_fiber(DstArgs args) { int dst_core_fiber(DstArgs args) {
DstFiber *fiber; DstFiber *fiber;
if (args.n < 1) return dst_throw(args, "expected at least one argument"); if (args.n < 1) return dst_throw(args, "expected at least one argument");
if (!dst_checktype(args.v[0], DST_FUNCTION)) return dst_throw(args, "expected a function"); if (!dst_checktype(args.v[0], DST_FUNCTION))
fiber = dst_fiber(64); return dst_throw(args, "expected a function");
fiber->parent = dst_vm_fiber; fiber = dst_fiber(dst_unwrap_function(args.v[0]), 64);
dst_fiber_funcframe(fiber, dst_unwrap_function(args.v[0]));
return dst_return(args, dst_wrap_fiber(fiber)); return dst_return(args, dst_wrap_fiber(fiber));
} }
@ -226,10 +225,6 @@ int dst_core_fiber_status(DstArgs args) {
return dst_return(args, dst_csymbolv(status)); return dst_return(args, dst_csymbolv(status));
} }
int dst_core_fiber_current(DstArgs args) {
return dst_return(args, dst_wrap_fiber(dst_vm_fiber));
}
int dst_core_put(DstArgs args) { int dst_core_put(DstArgs args) {
Dst ds, key, value; Dst ds, key, value;
DstArgs subargs = args; DstArgs subargs = args;

View File

@ -21,11 +21,15 @@
*/ */
#include <dst/dst.h> #include <dst/dst.h>
#include "fiber.h"
#include "gc.h" #include "gc.h"
/* Initialize a new fiber */ /* Initialize a new fiber */
DstFiber *dst_fiber(int32_t capacity) { DstFiber *dst_fiber(DstFunction *callee, int32_t capacity) {
DstFiber *fiber = dst_gcalloc(DST_MEMORY_FIBER, sizeof(DstFiber)); DstFiber *fiber = dst_gcalloc(DST_MEMORY_FIBER, sizeof(DstFiber));
if (capacity < 16) {
capacity = 16;
}
fiber->capacity = capacity; fiber->capacity = capacity;
if (capacity) { if (capacity) {
Dst *data = malloc(sizeof(Dst) * capacity); Dst *data = malloc(sizeof(Dst) * capacity);
@ -33,22 +37,21 @@ DstFiber *dst_fiber(int32_t capacity) {
DST_OUT_OF_MEMORY; DST_OUT_OF_MEMORY;
} }
fiber->data = data; fiber->data = data;
} else {
fiber->data = NULL;
} }
fiber->parent = NULL;
fiber->maxstack = DST_STACK_MAX; fiber->maxstack = DST_STACK_MAX;
fiber->flags = DST_FIBER_MASK_DEBUG; fiber->flags = DST_FIBER_MASK_DEBUG;
return dst_fiber_reset(fiber); return dst_fiber_reset(fiber, callee);
} }
/* Clear a fiber (reset it) */ /* Clear a fiber (reset it) */
DstFiber *dst_fiber_reset(DstFiber *fiber) { DstFiber *dst_fiber_reset(DstFiber *fiber, DstFunction *callee) {
fiber->frame = 0; fiber->frame = 0;
fiber->stackstart = DST_FRAME_SIZE; fiber->stackstart = DST_FRAME_SIZE;
fiber->stacktop = DST_FRAME_SIZE; fiber->stacktop = DST_FRAME_SIZE;
fiber->status = DST_FIBER_NEW; fiber->status = DST_FIBER_NEW;
fiber->parent = NULL; fiber->root = callee;
fiber->child = NULL;
fiber->flags |= DST_FIBER_FLAG_NEW;
return fiber; return fiber;
} }

41
src/core/fiber.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2017 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 DST_FIBER_H_defined
#define DST_FIBER_H_defined
#include <dst/dst.h>
#define dst_stack_frame(s) ((DstStackFrame *)((s) - DST_FRAME_SIZE))
#define dst_fiber_frame(f) dst_stack_frame((f)->data + (f)->frame)
DstFiber *dst_fiber_reset(DstFiber *fiber, DstFunction *callee);
void dst_fiber_setcapacity(DstFiber *fiber, int32_t n);
void dst_fiber_push(DstFiber *fiber, Dst x);
void dst_fiber_push2(DstFiber *fiber, Dst x, Dst y);
void dst_fiber_push3(DstFiber *fiber, Dst x, Dst y, Dst z);
void dst_fiber_pushn(DstFiber *fiber, const Dst *arr, int32_t n);
void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func);
void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func);
void dst_fiber_cframe(DstFiber *fiber);
void dst_fiber_popframe(DstFiber *fiber);
#endif

View File

@ -180,10 +180,14 @@ static void dst_mark_function(DstFunction *func) {
static void dst_mark_fiber(DstFiber *fiber) { static void dst_mark_fiber(DstFiber *fiber) {
int32_t i, j; int32_t i, j;
DstStackFrame *frame; DstStackFrame *frame;
recur:
if (dst_gc_reachable(fiber)) if (dst_gc_reachable(fiber))
return; return;
dst_gc_mark(fiber); dst_gc_mark(fiber);
if (fiber->flags & DST_FIBER_FLAG_NEW)
dst_mark_function(fiber->root);
i = fiber->frame; i = fiber->frame;
j = fiber->stackstart - DST_FRAME_SIZE; j = fiber->stackstart - DST_FRAME_SIZE;
while (i > 0) { while (i > 0) {
@ -198,8 +202,10 @@ static void dst_mark_fiber(DstFiber *fiber) {
i = frame->prevframe; i = frame->prevframe;
} }
if (NULL != fiber->parent) if (fiber->child) {
dst_mark_fiber(fiber->parent); fiber = fiber->child;
goto recur;
}
} }
/* Deinitialize a block of memory */ /* Deinitialize a block of memory */
@ -309,8 +315,6 @@ void *dst_gcalloc(enum DstMemoryType type, size_t size) {
void dst_collect(void) { void dst_collect(void) {
uint32_t i; uint32_t i;
if (dst_vm_gc_suspend) return; if (dst_vm_gc_suspend) return;
if (dst_vm_fiber)
dst_mark_fiber(dst_vm_fiber);
for (i = 0; i < dst_vm_root_count; i++) for (i = 0; i < dst_vm_root_count; i++)
dst_mark(dst_vm_roots[i]); dst_mark(dst_vm_roots[i]);
dst_sweep(); dst_sweep();

View File

@ -249,8 +249,10 @@ static int dst_io_gc(void *p, size_t len) {
static int dst_io_fclose(DstArgs args) { static int dst_io_fclose(DstArgs args) {
IOFile *iof = checkfile(args, 0); IOFile *iof = checkfile(args, 0);
if (!iof) return 1; if (!iof) return 1;
if (iof->flags & (IO_CLOSED | IO_NOT_CLOSEABLE)) if (iof->flags & (IO_CLOSED))
return dst_throw(args, "could not close file"); return dst_throw(args, "file already closed");
if (iof->flags & (IO_NOT_CLOSEABLE))
return dst_throw(args, "file not closable");
if (fclose(iof->file)) return dst_throw(args, "could not close file"); if (fclose(iof->file)) return dst_throw(args, "could not close file");
iof->flags |= IO_CLOSED; iof->flags |= IO_CLOSED;
return dst_return(args, dst_wrap_abstract(iof)); return dst_return(args, dst_wrap_abstract(iof));

View File

@ -22,35 +22,15 @@
#include <dst/dst.h> #include <dst/dst.h>
#include <dst/dstopcodes.h> #include <dst/dstopcodes.h>
#include "symcache.h" #include "fiber.h"
#include "gc.h" #include "gc.h"
#include "symcache.h"
/* VM State */ /* VM state */
DstFiber *dst_vm_fiber = NULL;
int dst_vm_stackn = 0; int dst_vm_stackn = 0;
/* Helper to ensure proper fiber is activated after returning */
static int dst_update_fiber(uint32_t mask) {
if (dst_vm_fiber->frame == 0) {
dst_vm_fiber->status = DST_FIBER_DEAD;
}
while (dst_vm_fiber->status == DST_FIBER_DEAD ||
dst_vm_fiber->status == DST_FIBER_ERROR ||
dst_vm_fiber->status == DST_FIBER_DEBUG ||
dst_vm_fiber->flags & mask) {
if (NULL != dst_vm_fiber->parent) {
dst_vm_fiber = dst_vm_fiber->parent;
} else {
/* The root thread has terminated */
return 1;
}
}
dst_vm_fiber->status = DST_FIBER_ALIVE;
return 0;
}
/* Start running the VM from where it left off. */ /* Start running the VM from where it left off. */
static int dst_continue(Dst *returnreg) { Dst dst_run(DstFiber *fiber) {
/* VM state */ /* VM state */
register Dst *stack; register Dst *stack;
@ -63,11 +43,22 @@ static int dst_continue(Dst *returnreg) {
/* Increment the stackn */ /* Increment the stackn */
if (dst_vm_stackn >= DST_RECURSION_GUARD) { if (dst_vm_stackn >= DST_RECURSION_GUARD) {
*returnreg = dst_cstringv("C stack recursed too deeply"); fiber->status = DST_FIBER_ERROR;
return 1; return dst_cstringv("C stack recursed too deeply");
} }
dst_vm_stackn++; dst_vm_stackn++;
/* Reset fiber state */
if (fiber->flags & DST_FIBER_FLAG_NEW) {
dst_fiber_funcframe(fiber, fiber->root);
fiber->flags &= ~DST_FIBER_FLAG_NEW;
}
fiber->status = DST_FIBER_ALIVE;
dst_gcroot(dst_wrap_fiber(fiber));
stack = fiber->data + fiber->frame;
pc = dst_stack_frame(stack)->pc;
func = dst_stack_frame(stack)->func;
/* Use computed gotos for GCC and clang, otherwise use switch */ /* Use computed gotos for GCC and clang, otherwise use switch */
#ifdef __GNUC__ #ifdef __GNUC__
#define VM_START() {vm_next(); #define VM_START() {vm_next();
@ -130,7 +121,8 @@ static void *op_lookup[255] = {
&&label_DOP_PUSH_ARRAY, &&label_DOP_PUSH_ARRAY,
&&label_DOP_CALL, &&label_DOP_CALL,
&&label_DOP_TAILCALL, &&label_DOP_TAILCALL,
&&label_DOP_TRANSFER, &&label_DOP_RESUME,
&&label_DOP_YIELD,
&&label_DOP_GET, &&label_DOP_GET,
&&label_DOP_PUT, &&label_DOP_PUT,
&&label_DOP_GET_INDEX, &&label_DOP_GET_INDEX,
@ -147,7 +139,7 @@ static void *op_lookup[255] = {
#define vm_next() continue #define vm_next() continue
#endif #endif
#define vm_checkgc_next() dst_maybe_collect(); vm_next() #define vm_checkgc_next() do { dst_maybe_collect(); vm_next() } while (0)
/* Used to extract bits from the opcode that correspond to arguments. /* Used to extract bits from the opcode that correspond to arguments.
* Pulls out unsigned integers */ * Pulls out unsigned integers */
@ -194,14 +186,6 @@ static void *op_lookup[255] = {
vm_next();\ vm_next();\
} }
#define vm_init_fiber_state() \
dst_vm_fiber->status = DST_FIBER_ALIVE;\
stack = dst_vm_fiber->data + dst_vm_fiber->frame;\
pc = dst_stack_frame(stack)->pc;\
func = dst_stack_frame(stack)->func;
vm_init_fiber_state();
/* Main interpreter loop. Sematically is a switch on /* Main interpreter loop. Sematically is a switch on
* (*pc & 0xFF) inside of an infinte loop. */ * (*pc & 0xFF) inside of an infinte loop. */
VM_START(); VM_START();
@ -513,8 +497,8 @@ static void *op_lookup[255] = {
if (!frame->env) { if (!frame->env) {
/* Lazy capture of current stack frame */ /* Lazy capture of current stack frame */
DstFuncEnv *env = dst_gcalloc(DST_MEMORY_FUNCENV, sizeof(DstFuncEnv)); DstFuncEnv *env = dst_gcalloc(DST_MEMORY_FUNCENV, sizeof(DstFuncEnv));
env->offset = dst_vm_fiber->frame; env->offset = fiber->frame;
env->as.fiber = dst_vm_fiber; env->as.fiber = fiber;
env->length = func->def->slotcount; env->length = func->def->slotcount;
frame->env = env; frame->env = env;
} }
@ -530,26 +514,26 @@ static void *op_lookup[255] = {
} }
VM_OP(DOP_PUSH) VM_OP(DOP_PUSH)
dst_fiber_push(dst_vm_fiber, stack[oparg(1, 0xFFFFFF)]); dst_fiber_push(fiber, stack[oparg(1, 0xFFFFFF)]);
pc++; pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
vm_checkgc_next(); vm_checkgc_next();
VM_OP(DOP_PUSH_2) VM_OP(DOP_PUSH_2)
dst_fiber_push2(dst_vm_fiber, dst_fiber_push2(fiber,
stack[oparg(1, 0xFF)], stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFFFF)]); stack[oparg(2, 0xFFFF)]);
pc++; pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
vm_checkgc_next(); vm_checkgc_next();
VM_OP(DOP_PUSH_3) VM_OP(DOP_PUSH_3)
dst_fiber_push3(dst_vm_fiber, dst_fiber_push3(fiber,
stack[oparg(1, 0xFF)], stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFF)], stack[oparg(2, 0xFF)],
stack[oparg(3, 0xFF)]); stack[oparg(3, 0xFF)]);
pc++; pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
vm_checkgc_next(); vm_checkgc_next();
VM_OP(DOP_PUSH_ARRAY) VM_OP(DOP_PUSH_ARRAY)
@ -557,35 +541,35 @@ static void *op_lookup[255] = {
const Dst *vals; const Dst *vals;
int32_t len; int32_t len;
if (dst_seq_view(stack[oparg(1, 0xFFFFFF)], &vals, &len)) { if (dst_seq_view(stack[oparg(1, 0xFFFFFF)], &vals, &len)) {
dst_fiber_pushn(dst_vm_fiber, vals, len); dst_fiber_pushn(fiber, vals, len);
} else { } else {
vm_throw("expected array/tuple"); vm_throw("expected array/tuple");
} }
} }
pc++; pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
vm_checkgc_next(); vm_checkgc_next();
VM_OP(DOP_CALL) VM_OP(DOP_CALL)
{ {
Dst callee = stack[oparg(2, 0xFFFF)]; Dst callee = stack[oparg(2, 0xFFFF)];
if (dst_vm_fiber->maxstack && if (fiber->maxstack &&
dst_vm_fiber->stacktop > dst_vm_fiber->maxstack) { fiber->stacktop > fiber->maxstack) {
vm_throw("stack overflow"); vm_throw("stack overflow");
} }
if (dst_checktype(callee, DST_FUNCTION)) { if (dst_checktype(callee, DST_FUNCTION)) {
func = dst_unwrap_function(callee); func = dst_unwrap_function(callee);
dst_stack_frame(stack)->pc = pc; dst_stack_frame(stack)->pc = pc;
dst_fiber_funcframe(dst_vm_fiber, func); dst_fiber_funcframe(fiber, func);
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
pc = func->def->bytecode; pc = func->def->bytecode;
vm_checkgc_next(); vm_checkgc_next();
} else if (dst_checktype(callee, DST_CFUNCTION)) { } else if (dst_checktype(callee, DST_CFUNCTION)) {
DstArgs args; DstArgs args;
args.n = dst_vm_fiber->stacktop - dst_vm_fiber->stackstart; args.n = fiber->stacktop - fiber->stackstart;
dst_fiber_cframe(dst_vm_fiber); dst_fiber_cframe(fiber);
retreg = dst_wrap_nil(); retreg = dst_wrap_nil();
args.v = dst_vm_fiber->data + dst_vm_fiber->frame; args.v = fiber->data + fiber->frame;
args.ret = &retreg; args.ret = &retreg;
if (dst_unwrap_cfunction(callee)(args)) { if (dst_unwrap_cfunction(callee)(args)) {
goto vm_error; goto vm_error;
@ -600,16 +584,16 @@ static void *op_lookup[255] = {
Dst callee = stack[oparg(1, 0xFFFFFF)]; Dst callee = stack[oparg(1, 0xFFFFFF)];
if (dst_checktype(callee, DST_FUNCTION)) { if (dst_checktype(callee, DST_FUNCTION)) {
func = dst_unwrap_function(callee); func = dst_unwrap_function(callee);
dst_fiber_funcframe_tail(dst_vm_fiber, func); dst_fiber_funcframe_tail(fiber, func);
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
pc = func->def->bytecode; pc = func->def->bytecode;
vm_checkgc_next(); vm_checkgc_next();
} else if (dst_checktype(callee, DST_CFUNCTION)) { } else if (dst_checktype(callee, DST_CFUNCTION)) {
DstArgs args; DstArgs args;
args.n = dst_vm_fiber->stacktop - dst_vm_fiber->stackstart; args.n = fiber->stacktop - fiber->stackstart;
dst_fiber_cframe(dst_vm_fiber); dst_fiber_cframe(fiber);
retreg = dst_wrap_nil(); retreg = dst_wrap_nil();
args.v = dst_vm_fiber->data + dst_vm_fiber->frame; args.v = fiber->data + fiber->frame;
args.ret = &retreg; args.ret = &retreg;
if (dst_unwrap_cfunction(callee)(args)) { if (dst_unwrap_cfunction(callee)(args)) {
goto vm_error; goto vm_error;
@ -619,52 +603,59 @@ static void *op_lookup[255] = {
vm_throw("expected function"); vm_throw("expected function");
} }
VM_OP(DOP_TRANSFER) VM_OP(DOP_RESUME)
{ {
int status;
DstFiber *nextfiber; DstFiber *nextfiber;
DstStackFrame *frame = dst_stack_frame(stack); Dst fiberval = stack[oparg(2, 0xFF)];
Dst temp = stack[oparg(2, 0xFF)]; Dst val = stack[oparg(3, 0xFF)];
retreg = stack[oparg(3, 0xFF)]; vm_assert(dst_checktype(fiberval, DST_FIBER), "expected fiber");
vm_assert(dst_checktype(temp, DST_FIBER) || nextfiber = dst_unwrap_fiber(fiberval);
dst_checktype(temp, DST_NIL), "expected fiber"); switch (nextfiber->status) {
nextfiber = dst_checktype(temp, DST_FIBER) default:
? dst_unwrap_fiber(temp) vm_throw("expected pending or new fiber");
: dst_vm_fiber->parent; case DST_FIBER_NEW:
/* Check for root fiber */ {
if (NULL == nextfiber) { dst_fiber_push(nextfiber, val);
frame->pc = pc; dst_fiber_funcframe(nextfiber, nextfiber->root);
*returnreg = retreg; nextfiber->flags &= ~DST_FIBER_FLAG_NEW;
dst_vm_stackn--; break;
return 0; }
case DST_FIBER_PENDING:
{
DstStackFrame *nextframe = dst_fiber_frame(nextfiber);
nextfiber->data[nextfiber->frame + ((*nextframe->pc >> 8) & 0xFF)] = val;
nextframe->pc++;
break;
}
}
fiber->child = nextfiber;
retreg = dst_run(nextfiber);
switch (nextfiber->status) {
case DST_FIBER_DEBUG:
if (fiber->flags & DST_FIBER_MASK_DEBUG) goto vm_debug;
fiber->child = NULL;
break;
case DST_FIBER_ERROR:
if (fiber->flags & DST_FIBER_MASK_ERROR) goto vm_error;
fiber->child = NULL;
break;
default:
fiber->child = NULL;
if (fiber->flags & DST_FIBER_MASK_RETURN) goto vm_return_root;
break;
} }
status = nextfiber->status;
vm_assert(status == DST_FIBER_PENDING ||
status == DST_FIBER_NEW, "can only transfer to new or pending fiber");
frame->pc = pc;
dst_vm_fiber->status = DST_FIBER_PENDING;
dst_vm_fiber = nextfiber;
vm_init_fiber_state();
if (status == DST_FIBER_PENDING) {
/* The next fiber is currently on a transfer instruction. */
stack[oparg(1, 0xFF)] = retreg; stack[oparg(1, 0xFF)] = retreg;
pc++; pc++;
} else {
/* The next fiber is new and is on the first instruction */
if ((func->def->flags & DST_FUNCDEF_FLAG_VARARG) &&
!func->def->arity) {
/* Fully var arg function */
Dst *tup = dst_tuple_begin(1);
tup[0] = retreg;
stack[0] = dst_wrap_tuple(dst_tuple_end(tup));
} else if (func->def->arity) {
/* Non zero arity function */
stack[0] = retreg;
}
}
vm_checkgc_next(); vm_checkgc_next();
} }
VM_OP(DOP_YIELD)
{
retreg = stack[oparg(2, 0xFFFF)];
fiber->status = DST_FIBER_PENDING;
goto vm_exit;
}
VM_OP(DOP_PUT) VM_OP(DOP_PUT)
dst_put(stack[oparg(1, 0xFF)], dst_put(stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFF)], stack[oparg(2, 0xFF)],
@ -698,12 +689,12 @@ static void *op_lookup[255] = {
++pc; ++pc;
vm_next(); vm_next();
/* Return from c function. Simpler than retuning from dst function */ /* Return from c function. Simpler than returning from dst function */
vm_return_cfunc: vm_return_cfunc:
{ {
dst_fiber_popframe(dst_vm_fiber); dst_fiber_popframe(fiber);
if (dst_update_fiber(DST_FIBER_MASK_RETURN)) goto vm_exit_value; if (fiber->frame == 0) goto vm_return_root;
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
stack[oparg(1, 0xFF)] = retreg; stack[oparg(1, 0xFF)] = retreg;
pc++; pc++;
vm_checkgc_next(); vm_checkgc_next();
@ -712,39 +703,54 @@ static void *op_lookup[255] = {
/* Return from a cfunction that is in tail position (pop 2 stack frames) */ /* Return from a cfunction that is in tail position (pop 2 stack frames) */
vm_return_cfunc_tail: vm_return_cfunc_tail:
{ {
dst_fiber_popframe(dst_vm_fiber); dst_fiber_popframe(fiber);
if (dst_update_fiber(DST_FIBER_MASK_RETURN)) goto vm_exit_value; dst_fiber_popframe(fiber);
goto vm_return; if (fiber->frame == 0) goto vm_return_root;
goto vm_reset;
} }
/* Handle returning from stack frame. Expect return value in retreg */ /* Handle returning from stack frame. Expect return value in retreg */
vm_return: vm_return:
{ {
dst_fiber_popframe(dst_vm_fiber); dst_fiber_popframe(fiber);
if (dst_update_fiber(DST_FIBER_MASK_RETURN)) goto vm_exit_value; if (fiber->frame == 0) goto vm_return_root;
goto vm_reset; goto vm_reset;
} }
/* Exit loop with return value */
vm_return_root:
{
fiber->status = DST_FIBER_DEAD;
goto vm_exit;
}
/* Handle errors from c functions and vm opcodes */ /* Handle errors from c functions and vm opcodes */
vm_error: vm_error:
{ {
dst_vm_fiber->status = DST_FIBER_ERROR; fiber->status = DST_FIBER_ERROR;
if (dst_update_fiber(DST_FIBER_MASK_ERROR)) goto vm_exit_error; goto vm_exit;
goto vm_reset;
} }
/* Handle debugger interrupts */ /* Handle debugger interrupts */
vm_debug: vm_debug:
{ {
dst_vm_fiber->status = DST_FIBER_DEBUG; fiber->status = DST_FIBER_DEBUG;
if (dst_update_fiber(DST_FIBER_MASK_DEBUG)) goto vm_exit_debug; goto vm_exit;
goto vm_reset; }
/* Exit from vm loop */
vm_exit:
{
dst_stack_frame(stack)->pc = pc;
dst_vm_stackn--;
dst_gcunroot(dst_wrap_fiber(fiber));
return retreg;
} }
/* Reset state of machine */ /* Reset state of machine */
vm_reset: vm_reset:
{ {
stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack = fiber->data + fiber->frame;
func = dst_stack_frame(stack)->func; func = dst_stack_frame(stack)->func;
pc = dst_stack_frame(stack)->pc; pc = dst_stack_frame(stack)->pc;
stack[oparg(1, 0xFF)] = retreg; stack[oparg(1, 0xFF)] = retreg;
@ -752,30 +758,6 @@ static void *op_lookup[255] = {
vm_checkgc_next(); vm_checkgc_next();
} }
/* Exit loop with return value */
vm_exit_value:
{
*returnreg = retreg;
dst_vm_stackn--;
return 0;
}
/* Exit loop with error value */
vm_exit_error:
{
*returnreg = retreg;
dst_vm_stackn--;
return 1;
}
/* Exit loop with debug */
vm_exit_debug:
{
*returnreg = dst_wrap_nil();
dst_vm_stackn--;
return 2;
}
VM_END() VM_END()
#undef oparg #undef oparg
@ -786,81 +768,33 @@ static void *op_lookup[255] = {
#undef vm_binop_real #undef vm_binop_real
#undef vm_binop_integer #undef vm_binop_integer
#undef vm_binop_immediate #undef vm_binop_immediate
#undef vm_init_fiber_state
} }
/* Run the vm with a given function. This function is Dst dst_resume(DstFiber *fiber, int32_t argn, const Dst *argv) {
* called to start the vm. */ switch (fiber->status) {
int dst_run(Dst callee, Dst *returnreg) { default:
if (dst_vm_fiber) { dst_exit("expected new or pending or fiber");
dst_fiber_reset(dst_vm_fiber); case DST_FIBER_NEW:
} else { {
dst_vm_fiber = dst_fiber(64); int32_t i;
for (i = 0; i < argn; i++)
dst_fiber_push(fiber, argv[i]);
dst_fiber_funcframe(fiber, fiber->root);
fiber->flags &= ~DST_FIBER_FLAG_NEW;
break;
} }
if (dst_checktype(callee, DST_CFUNCTION)) { case DST_FIBER_PENDING:
DstArgs args; {
*returnreg = dst_wrap_nil(); DstStackFrame *frame = dst_fiber_frame(fiber);
dst_fiber_cframe(dst_vm_fiber); fiber->data[fiber->frame + ((*frame->pc >> 8) & 0xFF)] = argn > 0
args.n = 0; ? argv[0]
args.v = dst_vm_fiber->data + dst_vm_fiber->frame; : dst_wrap_nil();
args.ret = returnreg; frame->pc++;
return dst_unwrap_cfunction(callee)(args); break;
} else if (dst_checktype(callee, DST_FUNCTION)) {
dst_fiber_funcframe(dst_vm_fiber, dst_unwrap_function(callee));
return dst_continue(returnreg);
} }
*returnreg = dst_cstringv("expected function");
return 1;
}
/* Helper for calling a function */
static int dst_call_help(Dst callee, Dst *returnreg, int32_t argn, const Dst* argv) {
dst_vm_fiber = dst_fiber(64);
dst_fiber_pushn(dst_vm_fiber, argv, argn);
if (dst_checktype(callee, DST_CFUNCTION)) {
DstArgs args;
*returnreg = dst_wrap_nil();
dst_fiber_cframe(dst_vm_fiber);
args.n = argn;
args.v = dst_vm_fiber->data + dst_vm_fiber->frame;
args.ret = returnreg;
return dst_unwrap_cfunction(callee)(args);
} else if (dst_checktype(callee, DST_FUNCTION)) {
dst_fiber_funcframe(dst_vm_fiber, dst_unwrap_function(callee));
return dst_continue(returnreg);
} else {
*returnreg = dst_cstringv("expected function");
return 1;
} }
} return dst_run(fiber);
/* Run from inside a cfunction. This should only be used for
* short functions as it prevents re-entering the current fiber
* and suspend garbage collection. Currently used in the compiler
* for macro evaluation. */
int dst_call_suspend(Dst callee, Dst *returnreg, int32_t argn, const Dst *argv) {
int ret;
int lock;
DstFiber *oldfiber = dst_vm_fiber;
lock = dst_vm_gc_suspend++;
ret = dst_call_help(callee, returnreg, argn, argv);
dst_vm_fiber = oldfiber;
dst_vm_gc_suspend = lock;
return ret;
}
/* Run from inside a cfunction. This will not suspend GC, so
* the caller must be sure that no Dst*'s are left dangling in the calling function.
* Such values can be locked with dst_gcroot and unlocked with dst_gcunroot. */
int dst_call(Dst callee, Dst *returnreg, int32_t argn, const Dst *argv) {
int ret;
DstFiber *oldfiber = dst_vm_fiber;
dst_gcroot(dst_wrap_fiber(oldfiber));
ret = dst_call_help(callee, returnreg, argn, argv);
dst_gcunroot(dst_wrap_fiber(oldfiber));
dst_vm_fiber = oldfiber;
return ret;
} }
/* Setup functions */ /* Setup functions */
@ -874,8 +808,6 @@ int dst_init() {
* there are no memory bugs during dev */ * there are no memory bugs during dev */
dst_vm_gc_interval = 0x100000; dst_vm_gc_interval = 0x100000;
dst_symcache_init(); dst_symcache_init();
/* Set thread */
dst_vm_fiber = NULL;
/* Initialize gc roots */ /* Initialize gc roots */
dst_vm_roots = NULL; dst_vm_roots = NULL;
dst_vm_root_count = 0; dst_vm_root_count = 0;
@ -886,7 +818,6 @@ int dst_init() {
/* Clear all memory associated with the VM */ /* Clear all memory associated with the VM */
void dst_deinit() { void dst_deinit() {
dst_clear_memory(); dst_clear_memory();
dst_vm_fiber = NULL;
dst_symcache_deinit(); dst_symcache_deinit();
free(dst_vm_roots); free(dst_vm_roots);
dst_vm_roots = NULL; dst_vm_roots = NULL;

View File

@ -130,19 +130,7 @@ void dst_table_merge_struct(DstTable *table, const DstKV *other);
DstKV *dst_table_find(DstTable *t, Dst key); DstKV *dst_table_find(DstTable *t, Dst key);
/* Fiber */ /* Fiber */
DstFiber *dst_fiber(int32_t capacity); DstFiber *dst_fiber(DstFunction *callee, int32_t capacity);
#define dst_stack_frame(s) ((DstStackFrame *)((s) - DST_FRAME_SIZE))
#define dst_fiber_frame(f) dst_stack_frame((f)->data + (f)->frame)
DstFiber *dst_fiber_reset(DstFiber *fiber);
void dst_fiber_setcapacity(DstFiber *fiber, int32_t n);
void dst_fiber_push(DstFiber *fiber, Dst x);
void dst_fiber_push2(DstFiber *fiber, Dst x, Dst y);
void dst_fiber_push3(DstFiber *fiber, Dst x, Dst y, Dst z);
void dst_fiber_pushn(DstFiber *fiber, const Dst *arr, int32_t n);
void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func);
void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func);
void dst_fiber_cframe(DstFiber *fiber);
void dst_fiber_popframe(DstFiber *fiber);
/* Treat similar types through uniform interfaces for iteration */ /* Treat similar types through uniform interfaces for iteration */
int dst_seq_view(Dst seq, const Dst **data, int32_t *len); int dst_seq_view(Dst seq, const Dst **data, int32_t *len);
@ -169,7 +157,7 @@ int dst_gcunrootall(Dst root);
#define dst_maybe_collect() do {\ #define dst_maybe_collect() do {\
if (dst_vm_next_collection >= dst_vm_gc_interval) dst_collect(); } while (0) if (dst_vm_next_collection >= dst_vm_gc_interval) dst_collect(); } while (0)
#define dst_gclock() (dst_vm_gc_suspend++) #define dst_gclock() (dst_vm_gc_suspend++)
#define dst_gcunlock() (dst_vm_gc_suspend--) #define dst_gcunlock(lock) (dst_vm_gc_suspend = lock)
/* Functions */ /* Functions */
DstFuncDef *dst_funcdef_alloc(void); DstFuncDef *dst_funcdef_alloc(void);
@ -192,9 +180,8 @@ int dst_cstrcmp(const uint8_t *str, const char *other);
/* VM functions */ /* VM functions */
int dst_init(void); int dst_init(void);
void dst_deinit(void); void dst_deinit(void);
int dst_run(Dst callee, Dst *returnreg); Dst dst_run(DstFiber *fiber);
int dst_call(Dst callee, Dst *returnreg, int32_t argn, const Dst *argv); Dst dst_resume(DstFiber *fiber, int32_t argn, const Dst *argv);
int dst_call_suspend(Dst callee, Dst *returnreg, int32_t argn, const Dst *argv);
/* C Function helpers */ /* C Function helpers */
#define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1) #define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1)

View File

@ -94,7 +94,7 @@ int dst_core_rawget(DstArgs args);
int dst_core_getproto(DstArgs args); int dst_core_getproto(DstArgs args);
int dst_core_setproto(DstArgs args); int dst_core_setproto(DstArgs args);
int dst_core_fiber_status(DstArgs args); int dst_core_fiber_status(DstArgs args);
int dst_core_fiber_current(DstArgs args); int dst_core_fiber_location(DstArgs args);
int dst_core_put(DstArgs args); int dst_core_put(DstArgs args);
int dst_core_gccollect(DstArgs args); int dst_core_gccollect(DstArgs args);
int dst_core_gcsetinterval(DstArgs args); int dst_core_gcsetinterval(DstArgs args);

View File

@ -112,7 +112,8 @@ enum DstOpCode {
DOP_PUSH_ARRAY, DOP_PUSH_ARRAY,
DOP_CALL, DOP_CALL,
DOP_TAILCALL, DOP_TAILCALL,
DOP_TRANSFER, DOP_RESUME,
DOP_YIELD,
DOP_GET, DOP_GET,
DOP_PUT, DOP_PUT,
DOP_GET_INDEX, DOP_GET_INDEX,

View File

@ -57,9 +57,6 @@ extern Dst *dst_vm_roots;
extern uint32_t dst_vm_root_count; extern uint32_t dst_vm_root_count;
extern uint32_t dst_vm_root_capacity; extern uint32_t dst_vm_root_capacity;
/* GC roots - TODO consider a top level fiber pool (per thread?) */
extern DstFiber *dst_vm_fiber;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -310,11 +310,14 @@ struct DstArgs {
#define DST_FIBER_MASK_ERROR 2 #define DST_FIBER_MASK_ERROR 2
#define DST_FIBER_MASK_DEBUG 4 #define DST_FIBER_MASK_DEBUG 4
#define DST_FIBER_FLAG_NEW 8
/* A lightweight green thread in dst. Does not correspond to /* A lightweight green thread in dst. Does not correspond to
* operating system threads. */ * operating system threads. */
struct DstFiber { struct DstFiber {
Dst *data; Dst *data;
DstFiber *parent; DstFiber *child; /* When a fiber enters the error or debug state, keep track of the original fiber that raised the error. */
DstFunction *root; /* First value */
int32_t frame; /* Index of the stack frame */ int32_t frame; /* Index of the stack frame */
int32_t stackstart; /* Beginning of next args */ int32_t stackstart; /* Beginning of next args */
int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */

View File

@ -160,18 +160,18 @@
(def afiber (fiber (fn [x] (def afiber (fiber (fn [x]
(error (string "hello, " x))))) (error (string "hello, " x)))))
(def afiber-result (transfer afiber "world!")) (def afiber-result (resume afiber "world!"))
(assert (= afiber-result "hello, world!") "fiber error result") (assert (= afiber-result "hello, world!") "fiber error result")
(assert (= (fiber-status afiber) :error) "fiber error status") (assert (= (fiber-status afiber) :error) "fiber error status")
# yield tests # yield tests
(def t (fiber (fn [] (transfer nil 1) (yield 2) 3))) (def t (fiber (fn [] (yield 1) (yield 2) 3)))
(assert (= 1 (transfer t)) "initial transfer to new fiber") (assert (= 1 (resume t)) "initial transfer to new fiber")
(assert (= 2 (transfer t)) "second transfer to fiber") (assert (= 2 (resume t)) "second transfer to fiber")
(assert (= 3 (transfer t)) "return from fiber") (assert (= 3 (resume t)) "return from fiber")
(assert (= (fiber-status t) :dead) "finished fiber is dead") (assert (= (fiber-status t) :dead) "finished fiber is dead")
# Var arg tests # Var arg tests