2017-11-06 03:05:47 +00:00
|
|
|
/*
|
2018-05-18 03:41:20 +00:00
|
|
|
* Copyright (c) 2018 Calvin Rose
|
2017-11-06 03:05:47 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
#include <janet/janet.h>
|
2018-03-11 19:35:23 +00:00
|
|
|
#include "fiber.h"
|
2018-06-12 18:24:45 +00:00
|
|
|
#include "state.h"
|
2017-12-21 04:03:34 +00:00
|
|
|
#include "gc.h"
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Initialize a new fiber */
|
2018-09-06 02:18:42 +00:00
|
|
|
JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity) {
|
|
|
|
JanetFiber *fiber = janet_gcalloc(JANET_MEMORY_FIBER, sizeof(JanetFiber));
|
2018-03-11 19:35:23 +00:00
|
|
|
if (capacity < 16) {
|
|
|
|
capacity = 16;
|
|
|
|
}
|
2017-11-06 03:05:47 +00:00
|
|
|
fiber->capacity = capacity;
|
2017-11-21 02:39:44 +00:00
|
|
|
if (capacity) {
|
2018-09-06 02:18:42 +00:00
|
|
|
Janet *data = malloc(sizeof(Janet) * capacity);
|
2017-11-21 02:39:44 +00:00
|
|
|
if (NULL == data) {
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_OUT_OF_MEMORY;
|
2017-11-21 02:39:44 +00:00
|
|
|
}
|
|
|
|
fiber->data = data;
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->maxstack = JANET_STACK_MAX;
|
|
|
|
return janet_fiber_reset(fiber, callee);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear a fiber (reset it) */
|
2018-09-06 02:18:42 +00:00
|
|
|
JanetFiber *janet_fiber_reset(JanetFiber *fiber, JanetFunction *callee) {
|
2017-11-21 02:39:44 +00:00
|
|
|
fiber->frame = 0;
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->stackstart = JANET_FRAME_SIZE;
|
|
|
|
fiber->stacktop = JANET_FRAME_SIZE;
|
2018-03-11 19:35:23 +00:00
|
|
|
fiber->root = callee;
|
|
|
|
fiber->child = NULL;
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->flags = JANET_FIBER_MASK_YIELD;
|
|
|
|
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
|
2017-11-06 03:05:47 +00:00
|
|
|
return fiber;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure that the fiber has enough extra capacity */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) {
|
|
|
|
Janet *newData = realloc(fiber->data, sizeof(Janet) * n);
|
2017-11-06 03:05:47 +00:00
|
|
|
if (NULL == newData) {
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_OUT_OF_MEMORY;
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
fiber->data = newData;
|
|
|
|
fiber->capacity = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push a value on the next stack frame */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_push(JanetFiber *fiber, Janet x) {
|
2017-11-06 03:05:47 +00:00
|
|
|
if (fiber->stacktop >= fiber->capacity) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * fiber->stacktop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
fiber->data[fiber->stacktop++] = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push 2 values on the next stack frame */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_push2(JanetFiber *fiber, Janet x, Janet y) {
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t newtop = fiber->stacktop + 2;
|
2017-11-06 03:05:47 +00:00
|
|
|
if (newtop > fiber->capacity) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * newtop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
fiber->data[fiber->stacktop] = x;
|
|
|
|
fiber->data[fiber->stacktop + 1] = y;
|
|
|
|
fiber->stacktop = newtop;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push 3 values on the next stack frame */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_push3(JanetFiber *fiber, Janet x, Janet y, Janet z) {
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t newtop = fiber->stacktop + 3;
|
2017-11-06 03:05:47 +00:00
|
|
|
if (newtop > fiber->capacity) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * newtop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
fiber->data[fiber->stacktop] = x;
|
|
|
|
fiber->data[fiber->stacktop + 1] = y;
|
|
|
|
fiber->data[fiber->stacktop + 2] = z;
|
|
|
|
fiber->stacktop = newtop;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push an array on the next stack frame */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_pushn(JanetFiber *fiber, const Janet *arr, int32_t n) {
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t newtop = fiber->stacktop + n;
|
2017-11-06 03:05:47 +00:00
|
|
|
if (newtop > fiber->capacity) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * newtop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
memcpy(fiber->data + fiber->stacktop, arr, n * sizeof(Janet));
|
2017-11-06 03:05:47 +00:00
|
|
|
fiber->stacktop = newtop;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push a stack frame to a fiber */
|
2018-09-06 02:18:42 +00:00
|
|
|
int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
|
|
|
JanetStackFrame *newframe;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t i;
|
2018-01-12 18:54:37 +00:00
|
|
|
int32_t oldtop = fiber->stacktop;
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t oldframe = fiber->frame;
|
2018-01-04 02:36:10 +00:00
|
|
|
int32_t nextframe = fiber->stackstart;
|
2018-09-06 02:18:42 +00:00
|
|
|
int32_t nextstacktop = nextframe + func->def->slotcount + JANET_FRAME_SIZE;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2018-08-03 17:41:44 +00:00
|
|
|
/* Check strict arity */
|
2018-09-06 02:18:42 +00:00
|
|
|
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
2018-08-03 17:41:44 +00:00
|
|
|
if (func->def->arity != (fiber->stacktop - fiber->stackstart)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-06 03:05:47 +00:00
|
|
|
if (fiber->capacity < nextstacktop) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
2018-01-04 02:36:10 +00:00
|
|
|
/* Nil unset stack arguments (Needed for gc correctness) */
|
|
|
|
for (i = fiber->stacktop; i < nextstacktop; ++i) {
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->data[i] = janet_wrap_nil();
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the next frame */
|
2017-11-06 03:05:47 +00:00
|
|
|
fiber->frame = nextframe;
|
2018-01-04 02:36:10 +00:00
|
|
|
fiber->stacktop = fiber->stackstart = nextstacktop;
|
2018-09-06 02:18:42 +00:00
|
|
|
newframe = janet_fiber_frame(fiber);
|
2017-11-06 03:05:47 +00:00
|
|
|
newframe->prevframe = oldframe;
|
|
|
|
newframe->pc = func->def->bytecode;
|
|
|
|
newframe->func = func;
|
2018-02-12 21:43:59 +00:00
|
|
|
newframe->env = NULL;
|
2018-03-22 00:53:39 +00:00
|
|
|
newframe->flags = 0;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Check varargs */
|
2018-09-06 02:18:42 +00:00
|
|
|
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
|
2018-01-12 18:54:37 +00:00
|
|
|
int32_t tuplehead = fiber->frame + func->def->arity;
|
|
|
|
if (tuplehead >= oldtop) {
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
2018-01-12 18:54:37 +00:00
|
|
|
} else {
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
|
2018-01-12 18:54:37 +00:00
|
|
|
fiber->data + tuplehead,
|
|
|
|
oldtop - tuplehead));
|
|
|
|
}
|
|
|
|
}
|
2018-08-03 17:41:44 +00:00
|
|
|
|
|
|
|
/* Good return */
|
|
|
|
return 0;
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* If a frame has a closure environment, detach it from
|
|
|
|
* the stack and have it keep its own values */
|
2018-09-06 02:18:42 +00:00
|
|
|
static void janet_env_detach(JanetFuncEnv *env) {
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Check for closure environment */
|
2018-02-12 21:43:59 +00:00
|
|
|
if (env) {
|
2018-09-06 02:18:42 +00:00
|
|
|
size_t s = sizeof(Janet) * env->length;
|
|
|
|
Janet *vmem = malloc(s);
|
2018-01-05 21:17:55 +00:00
|
|
|
if (NULL == vmem) {
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_OUT_OF_MEMORY;
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
|
|
|
memcpy(vmem, env->as.fiber->data + env->offset, s);
|
|
|
|
env->offset = 0;
|
|
|
|
env->as.values = vmem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-06 03:05:47 +00:00
|
|
|
/* Create a tail frame for a function */
|
2018-09-06 02:18:42 +00:00
|
|
|
int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t i;
|
|
|
|
int32_t nextframetop = fiber->frame + func->def->slotcount;
|
2018-09-06 02:18:42 +00:00
|
|
|
int32_t nextstacktop = nextframetop + JANET_FRAME_SIZE;
|
2018-01-12 18:54:37 +00:00
|
|
|
int32_t stacksize;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2018-08-03 17:41:44 +00:00
|
|
|
/* Check strict arity */
|
2018-09-06 02:18:42 +00:00
|
|
|
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
2018-08-03 17:41:44 +00:00
|
|
|
if (func->def->arity != (fiber->stacktop - fiber->stackstart)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-06 03:05:47 +00:00
|
|
|
if (fiber->capacity < nextstacktop) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
Janet *stack = fiber->data + fiber->frame;
|
|
|
|
Janet *args = fiber->data + fiber->stackstart;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Detatch old function */
|
2018-09-06 02:18:42 +00:00
|
|
|
if (NULL != janet_fiber_frame(fiber)->func)
|
|
|
|
janet_env_detach(janet_fiber_frame(fiber)->env);
|
|
|
|
janet_fiber_frame(fiber)->env = NULL;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2018-01-12 18:54:37 +00:00
|
|
|
/* Check varargs */
|
2018-09-06 02:18:42 +00:00
|
|
|
if (func->def->flags & JANET_FUNCDEF_FLAG_VARARG) {
|
2018-01-12 18:54:37 +00:00
|
|
|
int32_t tuplehead = fiber->stackstart + func->def->arity;
|
|
|
|
if (tuplehead >= fiber->stacktop) {
|
2018-09-06 02:18:42 +00:00
|
|
|
if (tuplehead >= fiber->capacity) janet_fiber_setcapacity(fiber, 2 * (tuplehead + 1));
|
|
|
|
for (i = fiber->stacktop; i < tuplehead; ++i) fiber->data[i] = janet_wrap_nil();
|
|
|
|
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(NULL, 0));
|
2018-01-12 18:54:37 +00:00
|
|
|
} else {
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->data[tuplehead] = janet_wrap_tuple(janet_tuple_n(
|
2018-01-12 18:54:37 +00:00
|
|
|
fiber->data + tuplehead,
|
|
|
|
fiber->stacktop - tuplehead));
|
|
|
|
}
|
|
|
|
stacksize = tuplehead - fiber->stackstart + 1;
|
|
|
|
} else {
|
|
|
|
stacksize = fiber->stacktop - fiber->stackstart;
|
|
|
|
}
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
if (stacksize) memmove(stack, args, stacksize * sizeof(Janet));
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2018-01-04 02:36:10 +00:00
|
|
|
/* Nil unset locals (Needed for functional correctness) */
|
2018-01-12 18:54:37 +00:00
|
|
|
for (i = fiber->frame + stacksize; i < nextframetop; ++i)
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->data[i] = janet_wrap_nil();
|
2018-01-12 18:54:37 +00:00
|
|
|
|
|
|
|
/* Set stack stuff */
|
|
|
|
fiber->stacktop = fiber->stackstart = nextstacktop;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Set frame stuff */
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_frame(fiber)->func = func;
|
|
|
|
janet_fiber_frame(fiber)->pc = func->def->bytecode;
|
|
|
|
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_TAILCALL;
|
2018-08-03 17:41:44 +00:00
|
|
|
|
|
|
|
/* Good return */
|
|
|
|
return 0;
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Push a stack frame to a fiber for a c function */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) {
|
|
|
|
JanetStackFrame *newframe;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
2017-11-28 23:27:55 +00:00
|
|
|
int32_t oldframe = fiber->frame;
|
2018-01-04 02:36:10 +00:00
|
|
|
int32_t nextframe = fiber->stackstart;
|
2018-09-06 02:18:42 +00:00
|
|
|
int32_t nextstacktop = fiber->stacktop + JANET_FRAME_SIZE;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
if (fiber->capacity < nextstacktop) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_setcapacity(fiber, 2 * nextstacktop);
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the next frame */
|
|
|
|
fiber->frame = nextframe;
|
2018-01-04 02:36:10 +00:00
|
|
|
fiber->stacktop = fiber->stackstart = nextstacktop;
|
2018-09-06 02:18:42 +00:00
|
|
|
newframe = janet_fiber_frame(fiber);
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Set up the new frame */
|
|
|
|
newframe->prevframe = oldframe;
|
2018-06-12 18:24:45 +00:00
|
|
|
newframe->pc = (uint32_t *) cfun;
|
2017-11-06 03:05:47 +00:00
|
|
|
newframe->func = NULL;
|
2018-02-13 21:14:55 +00:00
|
|
|
newframe->env = NULL;
|
2018-03-22 00:53:39 +00:00
|
|
|
newframe->flags = 0;
|
2017-11-06 03:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Pop a stack frame from the fiber. Returns the new stack frame, or
|
|
|
|
* NULL if there are no more frames */
|
2018-09-06 02:18:42 +00:00
|
|
|
void janet_fiber_popframe(JanetFiber *fiber) {
|
|
|
|
JanetStackFrame *frame = janet_fiber_frame(fiber);
|
2018-02-07 05:44:51 +00:00
|
|
|
if (fiber->frame == 0) return;
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Clean up the frame (detach environments) */
|
|
|
|
if (NULL != frame->func)
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_env_detach(frame->env);
|
2017-11-06 03:05:47 +00:00
|
|
|
|
|
|
|
/* Shrink stack */
|
2018-01-04 02:36:10 +00:00
|
|
|
fiber->stacktop = fiber->stackstart = fiber->frame;
|
2017-11-06 03:05:47 +00:00
|
|
|
fiber->frame = frame->prevframe;
|
|
|
|
}
|
2018-03-22 00:53:39 +00:00
|
|
|
|
|
|
|
/* CFuns */
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_new(JanetArgs args) {
|
|
|
|
JanetFiber *fiber;
|
|
|
|
JanetFunction *func;
|
|
|
|
JANET_MINARITY(args, 1);
|
|
|
|
JANET_MAXARITY(args, 2);
|
|
|
|
JANET_ARG_FUNCTION(func, args, 0);
|
|
|
|
if (func->def->flags & JANET_FUNCDEF_FLAG_FIXARITY) {
|
2018-08-03 17:41:44 +00:00
|
|
|
if (func->def->arity != 1) {
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_THROW(args, "expected unit arity function in fiber constructor");
|
2018-08-03 17:41:44 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber = janet_fiber(func, 64);
|
2018-05-09 21:01:58 +00:00
|
|
|
if (args.n == 2) {
|
|
|
|
const uint8_t *flags;
|
|
|
|
int32_t len, i;
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_ARG_BYTES(flags, len, args, 1);
|
2018-05-17 02:09:36 +00:00
|
|
|
fiber->flags = 0;
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_fiber_set_status(fiber, JANET_STATUS_NEW);
|
2018-05-09 21:01:58 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
2018-05-17 02:09:36 +00:00
|
|
|
if (flags[i] >= '0' && flags[i] <= '9') {
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->flags |= JANET_FIBER_MASK_USERN(flags[i] - '0');
|
2018-05-17 02:09:36 +00:00
|
|
|
} else {
|
|
|
|
switch (flags[i]) {
|
|
|
|
default:
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_THROW(args, "invalid flag, expected a, d, e, u, or y");
|
2018-05-17 02:09:36 +00:00
|
|
|
case ':':
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
fiber->flags |=
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_FIBER_MASK_DEBUG |
|
|
|
|
JANET_FIBER_MASK_ERROR |
|
|
|
|
JANET_FIBER_MASK_USER |
|
|
|
|
JANET_FIBER_MASK_YIELD;
|
2018-05-17 02:09:36 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->flags |= JANET_FIBER_MASK_DEBUG;
|
2018-05-17 02:09:36 +00:00
|
|
|
break;
|
|
|
|
case 'e':
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->flags |= JANET_FIBER_MASK_ERROR;
|
2018-05-17 02:09:36 +00:00
|
|
|
break;
|
|
|
|
case 'u':
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->flags |= JANET_FIBER_MASK_USER;
|
2018-05-17 02:09:36 +00:00
|
|
|
break;
|
|
|
|
case 'y':
|
2018-09-06 02:18:42 +00:00
|
|
|
fiber->flags |= JANET_FIBER_MASK_YIELD;
|
2018-05-17 02:09:36 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-05-09 21:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_RETURN_FIBER(args, fiber);
|
2018-05-09 21:01:58 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_status(JanetArgs args) {
|
|
|
|
JanetFiber *fiber;
|
2018-03-22 00:53:39 +00:00
|
|
|
const char *status = "";
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_FIXARITY(args, 1);
|
|
|
|
JANET_ARG_FIBER(fiber, args, 0);
|
|
|
|
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
|
|
|
|
JANET_FIBER_STATUS_OFFSET;
|
2018-05-17 02:09:36 +00:00
|
|
|
switch (s) {
|
2018-09-06 02:18:42 +00:00
|
|
|
case JANET_STATUS_DEAD: status = ":dead"; break;
|
|
|
|
case JANET_STATUS_ERROR: status = ":error"; break;
|
|
|
|
case JANET_STATUS_DEBUG: status = ":debug"; break;
|
|
|
|
case JANET_STATUS_PENDING: status = ":pending"; break;
|
|
|
|
case JANET_STATUS_USER0: status = ":user0"; break;
|
|
|
|
case JANET_STATUS_USER1: status = ":user1"; break;
|
|
|
|
case JANET_STATUS_USER2: status = ":user2"; break;
|
|
|
|
case JANET_STATUS_USER3: status = ":user3"; break;
|
|
|
|
case JANET_STATUS_USER4: status = ":user4"; break;
|
|
|
|
case JANET_STATUS_USER5: status = ":user5"; break;
|
|
|
|
case JANET_STATUS_USER6: status = ":user6"; break;
|
|
|
|
case JANET_STATUS_USER7: status = ":user7"; break;
|
|
|
|
case JANET_STATUS_USER8: status = ":user8"; break;
|
|
|
|
case JANET_STATUS_USER9: status = ":user9"; break;
|
|
|
|
case JANET_STATUS_NEW: status = ":new"; break;
|
2018-05-17 02:09:36 +00:00
|
|
|
default:
|
2018-09-06 02:18:42 +00:00
|
|
|
case JANET_STATUS_ALIVE: status = ":alive"; break;
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_RETURN_CSYMBOL(args, status);
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract info from one stack frame */
|
2018-09-06 02:18:42 +00:00
|
|
|
static Janet doframe(JanetStackFrame *frame) {
|
2018-03-22 00:53:39 +00:00
|
|
|
int32_t off;
|
2018-09-06 02:18:42 +00:00
|
|
|
JanetTable *t = janet_table(3);
|
|
|
|
JanetFuncDef *def = NULL;
|
2018-03-22 00:53:39 +00:00
|
|
|
if (frame->func) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
|
2018-03-22 00:53:39 +00:00
|
|
|
def = frame->func->def;
|
|
|
|
if (def->name) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-09-06 02:18:42 +00:00
|
|
|
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
2018-06-12 18:24:45 +00:00
|
|
|
if (cfun) {
|
2018-09-06 02:18:42 +00:00
|
|
|
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
|
|
|
if (!janet_checktype(name, JANET_NIL)) {
|
|
|
|
janet_table_put(t, janet_csymbolv(":name"), name);
|
2018-06-12 18:24:45 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
if (frame->flags & JANET_STACKFRAME_TAILCALL) {
|
|
|
|
janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
2018-06-12 18:24:45 +00:00
|
|
|
if (frame->func && frame->pc) {
|
2018-08-06 01:32:32 +00:00
|
|
|
off = (int32_t) (frame->pc - def->bytecode);
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
|
2018-03-22 00:53:39 +00:00
|
|
|
if (def->sourcemap) {
|
2018-09-06 02:18:42 +00:00
|
|
|
JanetSourceMapping mapping = def->sourcemap[off];
|
|
|
|
janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(mapping.line));
|
|
|
|
janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(mapping.column));
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
|
|
|
if (def->source) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
return janet_wrap_table(t);
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_stack(JanetArgs args) {
|
|
|
|
JanetFiber *fiber;
|
|
|
|
JanetArray *array;
|
|
|
|
JANET_FIXARITY(args, 1);
|
|
|
|
JANET_ARG_FIBER(fiber, args, 0);
|
|
|
|
array = janet_array(0);
|
2018-03-22 00:53:39 +00:00
|
|
|
{
|
|
|
|
int32_t i = fiber->frame;
|
2018-09-06 02:18:42 +00:00
|
|
|
JanetStackFrame *frame;
|
2018-03-22 00:53:39 +00:00
|
|
|
while (i > 0) {
|
2018-09-06 02:18:42 +00:00
|
|
|
frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
|
|
|
janet_array_push(array, doframe(frame));
|
2018-03-22 00:53:39 +00:00
|
|
|
i = frame->prevframe;
|
|
|
|
}
|
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_RETURN_ARRAY(args, array);
|
2018-03-22 00:53:39 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_current(JanetArgs args) {
|
|
|
|
JANET_FIXARITY(args, 0);
|
|
|
|
JANET_RETURN_FIBER(args, janet_vm_fiber);
|
2018-05-11 00:25:49 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_lineage(JanetArgs args) {
|
|
|
|
JanetFiber *fiber;
|
|
|
|
JanetArray *array;
|
|
|
|
JANET_FIXARITY(args, 1);
|
|
|
|
JANET_ARG_FIBER(fiber, args, 0);
|
|
|
|
array = janet_array(0);
|
2018-05-11 00:25:49 +00:00
|
|
|
while (fiber) {
|
2018-09-06 02:18:42 +00:00
|
|
|
janet_array_push(array, janet_wrap_fiber(fiber));
|
2018-05-11 00:25:49 +00:00
|
|
|
fiber = fiber->child;
|
|
|
|
}
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_RETURN_ARRAY(args, array);
|
2018-05-11 00:25:49 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_maxstack(JanetArgs args) {
|
|
|
|
JanetFiber *fiber;
|
|
|
|
JANET_FIXARITY(args, 1);
|
|
|
|
JANET_ARG_FIBER(fiber, args, 0);
|
|
|
|
JANET_RETURN_INTEGER(args, fiber->maxstack);
|
2018-06-03 18:00:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static int cfun_setmaxstack(JanetArgs args) {
|
|
|
|
JanetFiber *fiber;
|
2018-06-03 18:00:05 +00:00
|
|
|
int32_t maxs;
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_FIXARITY(args, 2);
|
|
|
|
JANET_ARG_FIBER(fiber, args, 0);
|
|
|
|
JANET_ARG_INTEGER(maxs, args, 1);
|
2018-06-03 18:00:05 +00:00
|
|
|
if (maxs < 0) {
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_THROW(args, "expected positive integer");
|
2018-06-03 18:00:05 +00:00
|
|
|
}
|
|
|
|
fiber->maxstack = maxs;
|
2018-09-06 02:18:42 +00:00
|
|
|
JANET_RETURN_FIBER(args, fiber);
|
2018-06-03 18:00:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 02:18:42 +00:00
|
|
|
static const JanetReg cfuns[] = {
|
2018-11-15 20:45:41 +00:00
|
|
|
{"fiber.new", cfun_new, NULL},
|
|
|
|
{"fiber.status", cfun_status, NULL},
|
|
|
|
{"fiber.stack", cfun_stack, NULL},
|
|
|
|
{"fiber.current", cfun_current, NULL},
|
|
|
|
{"fiber.lineage", cfun_lineage, NULL},
|
|
|
|
{"fiber.maxstack", cfun_maxstack, NULL},
|
|
|
|
{"fiber.setmaxstack", cfun_setmaxstack, NULL},
|
|
|
|
{NULL, NULL, NULL}
|
2018-03-22 00:53:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Module entry point */
|
2018-09-06 02:18:42 +00:00
|
|
|
int janet_lib_fiber(JanetArgs args) {
|
|
|
|
JanetTable *env = janet_env(args);
|
|
|
|
janet_cfuns(env, NULL, cfuns);
|
2018-03-22 00:53:39 +00:00
|
|
|
return 0;
|
|
|
|
}
|