1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 19:19:53 +00:00

Work on marshaling fiber.

This commit is contained in:
Calvin Rose 2018-08-24 08:22:43 -04:00
parent f5b4bc4fdf
commit b8a6cd84c0
2 changed files with 137 additions and 15 deletions

View File

@ -186,6 +186,7 @@ recur:
return; return;
dst_gc_mark(fiber); dst_gc_mark(fiber);
if (fiber->root)
dst_mark_function(fiber->root); dst_mark_function(fiber->root);
i = fiber->frame; i = fiber->frame;

View File

@ -446,20 +446,22 @@ enum {
UMR_EXPECTED_FIBER, UMR_EXPECTED_FIBER,
UMR_EXPECTED_STRING, UMR_EXPECTED_STRING,
UMR_INVALID_REFERENCE, UMR_INVALID_REFERENCE,
UMR_INVALID_BYTECODE UMR_INVALID_BYTECODE,
UMR_INVALID_FIBER
} UnmarshalResult; } UnmarshalResult;
const char *umr_strings[] = { const char *umr_strings[] = {
"", "",
"stack overflow", "stack overflow",
"unexpected end of source", "unexpected end of source",
"unknown byte", "unmarshal error",
"expected integer", "expected integer",
"expected table", "expected table",
"expected fiber", "expected fiber",
"expected string", "expected string",
"invalid reference", "invalid reference",
"invalid bytecode" "invalid bytecode",
"invalid fiber"
}; };
/* Helper to read a 32 bit integer from an unmarshal state */ /* Helper to read a 32 bit integer from an unmarshal state */
@ -506,26 +508,31 @@ static const uint8_t *unmarshal_one_env(
*out = st->lookup_envs[index]; *out = st->lookup_envs[index];
} else { } else {
DstFuncEnv *env = dst_gcalloc(DST_MEMORY_FUNCENV, sizeof(DstFuncEnv)); DstFuncEnv *env = dst_gcalloc(DST_MEMORY_FUNCENV, sizeof(DstFuncEnv));
env->length = 0;
env->offset = 0;
dst_v_push(st->lookup_envs, env); dst_v_push(st->lookup_envs, env);
env->offset = readint(st, &data); int32_t offset = readint(st, &data);
env->length = readint(st, &data); int32_t length = readint(st, &data);
if (env->offset) { if (offset) {
/* On stack variant */ /* On stack variant */
Dst fiberv; Dst fiberv;
data = unmarshal_one(st, data, &fiberv, flags); data = unmarshal_one(st, data, &fiberv, flags);
if (!dst_checktype(fiberv, DST_FIBER)) longjmp(st->err, UMR_EXPECTED_FIBER); if (!dst_checktype(fiberv, DST_FIBER)) longjmp(st->err, UMR_EXPECTED_FIBER);
env->as.fiber = dst_unwrap_fiber(fiberv); env->as.fiber = dst_unwrap_fiber(fiberv);
/* Unmarshaling fiber may set values */
if (env->offset != 0 && env->offset != offset) longjmp(st->err, UMR_UNKNOWN);
if (env->length != 0 && env->length != length) longjmp(st->err, UMR_UNKNOWN);
} else { } else {
/* Off stack variant */ /* Off stack variant */
env->as.values = malloc(sizeof(Dst) * env->length); env->as.values = malloc(sizeof(Dst) * length);
if (!env->as.values) { if (!env->as.values) {
DST_OUT_OF_MEMORY; DST_OUT_OF_MEMORY;
} }
for (int32_t i = 0; i < env->length; i++) { for (int32_t i = 0; i < env->length; i++)
data = unmarshal_one(st, data, env->as.values + i, flags); data = unmarshal_one(st, data, env->as.values + i, flags);
} }
} env->offset = offset;
/* Set out */ env->length = length;
*out = env; *out = env;
} }
return data; return data;
@ -670,15 +677,129 @@ static const uint8_t *unmarshal_one_def(
return data; return data;
} }
/* Unmarshal a fiber */
static const uint8_t *unmarshal_one_fiber( static const uint8_t *unmarshal_one_fiber(
UnmarshalState *st, UnmarshalState *st,
const uint8_t *data, const uint8_t *data,
DstFiber **out, DstFiber **out,
int flags) { int flags) {
longjmp(st->err, UMR_UNKNOWN);
(void) out; /* Initialize a new fiber */
(void) flags; DstFiber *fiber = dst_gcalloc(DST_MEMORY_FIBER, sizeof(DstFiber));
return data + 1; fiber->flags = 0;
fiber->frame = 0;
fiber->stackstart = 0;
fiber->stacktop = 0;
fiber->capacity = 0;
fiber->root = NULL;
fiber->child = NULL;
/* Set frame later so fiber can be GCed at anytime if unmarshaling fails */
int32_t frame = 0;
int32_t stack = 0;
int32_t stacktop = 0;
/* Read ints */
fiber->flags = readint(st, &data);
frame = readint(st, &data);
fiber->stackstart = readint(st, &data);
fiber->stacktop = readint(st, &data);
fiber->maxstack = readint(st, &data);
/* Check for bad flags and ints */
if (frame + DST_FRAME_SIZE > fiber->stackstart ||
fiber->stackstart > fiber->stacktop ||
fiber->stacktop > fiber->capacity ||
fiber->stacktop > fiber->maxstack) {
goto error;
}
/* Get root fuction */
Dst funcv;
data = dst_unmarshal_one(st, data, &funcv, flags + 1);
if (!dst_checktype(funcv, DST_FUNCTION)) goto error;
fiber->root = dst_unwrap_function(funcv);
/* Allocate stack memory */
fiber->capacity = fiber->stacktop + 10;
fiber->data = malloc(sizeof(Dst) * fiber->capacity);
if (!fiber->data) {
DST_OUT_OF_MEMORY;
}
/* get frames */
stack = frame;
stacktop = fiber->stackstart - DST_FRAME_SIZE;
while (stack > 0) {
DstFunction *func;
DstFuncDef *def;
DstFuncEnv *env;
int32_t frameflags = readint(st, &data);
int32_t prevframe = readint(st, &data);
int32_t pcdiff = readint(st, &data);
/* Get frame items */
Dst *framestack = fiber->data + stack;
DstStackFrame *framep = (DstStackFrame *)framestack - 1;
/* Get function */
Dst funcv;
data = unmarshal_one(st, data, &funcv, flags + 1);
if (!dst_checktype(framefunc, DST_FUNCTION))
goto error;
func = dst_unwrap_function(funcv);
def = func->def;
/* Check env */
if (frameflags & DST_STACKFRAME_HASENV) {
frameflags &= ~DST_STACKFRAME_HASENV;
int32_t offset = stack;
int32_t length = stacktop - stack;
data = unmarshal_one_env(st, data, &env, flags + 1);
if (env->offset != 0 && env->offset != offset) goto error;
if (env->length != 0 && env->length != offset) goto error;
env->offset = offset;
env->length = length;
}
/* Error checking */
int32_t expected_framesize = def->arity + !!(def->flags & DST_FUNCDEF_FLAG_VARARG);
if (expected_framesize != stacktop - stack) goto error;
if (pcdiff < 0 || pcdiff >= def->bytecode_length) goto error;
if (prevframe + DST_FRAME_SIZE > stack) goto error;
/* Get stack items */
for (int32_t i = stack; i < stacktop; i++) {
data = dst_unmarshal_one(st, data, fiber->data + i, flags + 1);
}
/* Set frame */
framep->env = env;
framep->pc = def->bytecode + pcdiff;
framep->prevframe = prevframe;
framep->flags = frameflags;
framep->func = func;
/* Goto previous frame */
stacktop = stack - DST_FRAME_SIZE;
stack = prevframe;
}
if (stack < 0) goto error;
/* Check for child fiber */
if (fiber->flags & DST_FIBER_HAS_CHILD) {
fiber->flags &= ~DST_FIBER_FLAG_HASCHILD;
data = unmarshal_one_fiber(st, data, &(fiber->child), flags + 1);
}
/* Return data */
fiber->frame = frame;
*out = dst_wrap_fiber(fiber);
return data;
error:
longjmp(st->err, UMR_INVALID_FIBER);
return NULL;
} }
static const uint8_t *unmarshal_one( static const uint8_t *unmarshal_one(