|
|
|
@@ -30,8 +30,6 @@
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
jmp_buf err;
|
|
|
|
|
Janet current;
|
|
|
|
|
JanetBuffer *buf;
|
|
|
|
|
JanetTable seen;
|
|
|
|
|
JanetTable *rreg;
|
|
|
|
@@ -40,26 +38,6 @@ typedef struct {
|
|
|
|
|
int32_t nextid;
|
|
|
|
|
} MarshalState;
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
MR_OK,
|
|
|
|
|
MR_STACKOVERFLOW,
|
|
|
|
|
MR_NYI,
|
|
|
|
|
MR_NRV,
|
|
|
|
|
MR_C_STACKFRAME,
|
|
|
|
|
MR_OVERFLOW,
|
|
|
|
|
MR_LIVEFIBER
|
|
|
|
|
} MarshalResult;
|
|
|
|
|
|
|
|
|
|
const char *mr_strings[] = {
|
|
|
|
|
"",
|
|
|
|
|
"stack overflow",
|
|
|
|
|
"type NYI",
|
|
|
|
|
"no registry value",
|
|
|
|
|
"fiber has c stack frame",
|
|
|
|
|
"buffer overflow",
|
|
|
|
|
"alive fiber"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Lead bytes in marshaling protocol */
|
|
|
|
|
enum {
|
|
|
|
|
LB_REAL = 200,
|
|
|
|
@@ -156,10 +134,12 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags);
|
|
|
|
|
static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags);
|
|
|
|
|
static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags);
|
|
|
|
|
|
|
|
|
|
/* Prevent stack overflows */
|
|
|
|
|
#define MARSH_STACKCHECK if ((flags & 0xFFFF) > JANET_RECURSION_GUARD) janet_panic("stack overflow")
|
|
|
|
|
|
|
|
|
|
/* Marshal a function env */
|
|
|
|
|
static void marshal_one_env(MarshalState *st, JanetFuncEnv *env, int flags) {
|
|
|
|
|
if ((flags & 0xFFFF) > JANET_RECURSION_GUARD)
|
|
|
|
|
longjmp(st->err, MR_STACKOVERFLOW);
|
|
|
|
|
MARSH_STACKCHECK;
|
|
|
|
|
for (int32_t i = 0; i < janet_v_count(st->seen_envs); i++) {
|
|
|
|
|
if (st->seen_envs[i] == env) {
|
|
|
|
|
pushbyte(st, LB_FUNCENV_REF);
|
|
|
|
@@ -191,8 +171,7 @@ static void janet_func_addflags(JanetFuncDef *def) {
|
|
|
|
|
|
|
|
|
|
/* Marshal a function def */
|
|
|
|
|
static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
|
|
|
|
if ((flags & 0xFFFF) > JANET_RECURSION_GUARD)
|
|
|
|
|
longjmp(st->err, MR_STACKOVERFLOW);
|
|
|
|
|
MARSH_STACKCHECK;
|
|
|
|
|
for (int32_t i = 0; i < janet_v_count(st->seen_defs); i++) {
|
|
|
|
|
if (st->seen_defs[i] == def) {
|
|
|
|
|
pushbyte(st, LB_FUNCDEF_REF);
|
|
|
|
@@ -254,12 +233,11 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
|
|
|
|
|
|
|
|
|
/* Marshal a fiber */
|
|
|
|
|
static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
|
|
|
|
|
MARSH_STACKCHECK;
|
|
|
|
|
int32_t fflags = fiber->flags;
|
|
|
|
|
if ((flags & 0xFFFF) > JANET_RECURSION_GUARD)
|
|
|
|
|
longjmp(st->err, MR_STACKOVERFLOW);
|
|
|
|
|
if (fiber->child) fflags |= JANET_FIBER_FLAG_HASCHILD;
|
|
|
|
|
if (janet_fiber_status(fiber) == JANET_STATUS_ALIVE)
|
|
|
|
|
longjmp(st->err, MR_LIVEFIBER);
|
|
|
|
|
janet_panic("cannot marshal alive fiber");
|
|
|
|
|
pushint(st, fflags);
|
|
|
|
|
pushint(st, fiber->frame);
|
|
|
|
|
pushint(st, fiber->stackstart);
|
|
|
|
@@ -271,7 +249,7 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
|
|
|
|
|
while (i > 0) {
|
|
|
|
|
JanetStackFrame *frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
|
|
|
|
if (frame->env) frame->flags |= JANET_STACKFRAME_HASENV;
|
|
|
|
|
if (!frame->func) longjmp(st->err, MR_C_STACKFRAME);
|
|
|
|
|
if (!frame->func) janet_panic("cannot marshal fiber with c stackframe");
|
|
|
|
|
pushint(st, frame->flags);
|
|
|
|
|
pushint(st, frame->prevframe);
|
|
|
|
|
int32_t pcdiff = (int32_t)(frame->pc - frame->func->def->bytecode);
|
|
|
|
@@ -291,11 +269,8 @@ static void marshal_one_fiber(MarshalState *st, JanetFiber *fiber, int flags) {
|
|
|
|
|
/* The main body of the marshaling function. Is the main
|
|
|
|
|
* entry point for the mutually recursive functions. */
|
|
|
|
|
static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
Janet parent = st->current;
|
|
|
|
|
MARSH_STACKCHECK;
|
|
|
|
|
JanetType type = janet_type(x);
|
|
|
|
|
st->current = x;
|
|
|
|
|
if ((flags & 0xFFFF) > JANET_RECURSION_GUARD)
|
|
|
|
|
longjmp(st->err, MR_STACKOVERFLOW);
|
|
|
|
|
|
|
|
|
|
/* Check simple primitives (non reference types, no benefit from memoization) */
|
|
|
|
|
switch (type) {
|
|
|
|
@@ -305,12 +280,12 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
case JANET_FALSE:
|
|
|
|
|
case JANET_TRUE:
|
|
|
|
|
pushbyte(st, 200 + type);
|
|
|
|
|
goto done;
|
|
|
|
|
return;
|
|
|
|
|
case JANET_NUMBER: {
|
|
|
|
|
double xval = janet_unwrap_number(x);
|
|
|
|
|
if (janet_checkintrange(xval)) {
|
|
|
|
|
pushint(st, (int32_t) xval);
|
|
|
|
|
goto done;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@@ -325,7 +300,7 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
if (janet_checkint(check)) {
|
|
|
|
|
pushbyte(st, LB_REFERENCE);
|
|
|
|
|
pushint(st, janet_unwrap_integer(check));
|
|
|
|
|
goto done;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (st->rreg) {
|
|
|
|
|
check = janet_table_get(st->rreg, x);
|
|
|
|
@@ -335,7 +310,7 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
pushbyte(st, LB_REGISTRY);
|
|
|
|
|
pushint(st, janet_string_length(regname));
|
|
|
|
|
pushbytes(st, regname, janet_string_length(regname));
|
|
|
|
|
goto done;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -367,8 +342,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
pushbyte(st, LB_REAL);
|
|
|
|
|
pushbytes(st, u.bytes, 8);
|
|
|
|
|
MARK_SEEN();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_STRING:
|
|
|
|
|
case JANET_SYMBOL:
|
|
|
|
|
case JANET_KEYWORD: {
|
|
|
|
@@ -382,8 +357,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
pushbyte(st, lb);
|
|
|
|
|
pushint(st, length);
|
|
|
|
|
pushbytes(st, str, length);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_BUFFER: {
|
|
|
|
|
JanetBuffer *buffer = janet_unwrap_buffer(x);
|
|
|
|
|
/* Record reference */
|
|
|
|
@@ -391,8 +366,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
pushbyte(st, LB_BUFFER);
|
|
|
|
|
pushint(st, buffer->count);
|
|
|
|
|
pushbytes(st, buffer->data, buffer->count);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_ARRAY: {
|
|
|
|
|
int32_t i;
|
|
|
|
|
JanetArray *a = janet_unwrap_array(x);
|
|
|
|
@@ -401,8 +376,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
pushint(st, a->count);
|
|
|
|
|
for (i = 0; i < a->count; i++)
|
|
|
|
|
marshal_one(st, a->data[i], flags + 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_TUPLE: {
|
|
|
|
|
int32_t i, count, flag;
|
|
|
|
|
const Janet *tup = janet_unwrap_tuple(x);
|
|
|
|
@@ -415,8 +390,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
marshal_one(st, tup[i], flags + 1);
|
|
|
|
|
/* Mark as seen AFTER marshaling */
|
|
|
|
|
MARK_SEEN();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_TABLE: {
|
|
|
|
|
JanetTable *t = janet_unwrap_table(x);
|
|
|
|
|
MARK_SEEN();
|
|
|
|
@@ -430,8 +405,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
marshal_one(st, t->data[i].key, flags + 1);
|
|
|
|
|
marshal_one(st, t->data[i].value, flags + 1);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_STRUCT: {
|
|
|
|
|
int32_t count;
|
|
|
|
|
const JanetKV *struct_ = janet_unwrap_struct(x);
|
|
|
|
@@ -446,11 +421,8 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
}
|
|
|
|
|
/* Mark as seen AFTER marshaling */
|
|
|
|
|
MARK_SEEN();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_ABSTRACT:
|
|
|
|
|
case JANET_CFUNCTION:
|
|
|
|
|
goto noregval;
|
|
|
|
|
case JANET_FUNCTION: {
|
|
|
|
|
pushbyte(st, LB_FUNCTION);
|
|
|
|
|
JanetFunction *func = janet_unwrap_function(x);
|
|
|
|
@@ -459,56 +431,39 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|
|
|
|
MARK_SEEN();
|
|
|
|
|
for (int32_t i = 0; i < func->def->environments_length; i++)
|
|
|
|
|
marshal_one_env(st, func->envs[i], flags + 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
case JANET_FIBER: {
|
|
|
|
|
MARK_SEEN();
|
|
|
|
|
pushbyte(st, LB_FIBER);
|
|
|
|
|
marshal_one_fiber(st, janet_unwrap_fiber(x), flags + 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
janet_panicf("no registry value and cannot marshal %p", x);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto done;
|
|
|
|
|
default:
|
|
|
|
|
goto nyi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef MARK_SEEN
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
st->current = parent;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Errors */
|
|
|
|
|
|
|
|
|
|
nyi:
|
|
|
|
|
longjmp(st->err, MR_NYI);
|
|
|
|
|
|
|
|
|
|
noregval:
|
|
|
|
|
longjmp(st->err, MR_NRV);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int janet_marshal(
|
|
|
|
|
void janet_marshal(
|
|
|
|
|
JanetBuffer *buf,
|
|
|
|
|
Janet x,
|
|
|
|
|
Janet *errval,
|
|
|
|
|
JanetTable *rreg,
|
|
|
|
|
int flags) {
|
|
|
|
|
int status;
|
|
|
|
|
MarshalState st;
|
|
|
|
|
st.buf = buf;
|
|
|
|
|
st.nextid = 0;
|
|
|
|
|
st.seen_defs = NULL;
|
|
|
|
|
st.seen_envs = NULL;
|
|
|
|
|
st.rreg = rreg;
|
|
|
|
|
st.current = x;
|
|
|
|
|
janet_table_init(&st.seen, 0);
|
|
|
|
|
if (!(status = setjmp(st.err)))
|
|
|
|
|
marshal_one(&st, x, flags);
|
|
|
|
|
if (status && errval)
|
|
|
|
|
*errval = st.current;
|
|
|
|
|
marshal_one(&st, x, flags);
|
|
|
|
|
/* Clean up. See comment in janet_unmarshal about autoreleasing memory on panics.*/
|
|
|
|
|
janet_table_deinit(&st.seen);
|
|
|
|
|
janet_v_free(st.seen_envs);
|
|
|
|
|
janet_v_free(st.seen_defs);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
@@ -517,63 +472,50 @@ typedef struct {
|
|
|
|
|
JanetTable *reg;
|
|
|
|
|
JanetFuncEnv **lookup_envs;
|
|
|
|
|
JanetFuncDef **lookup_defs;
|
|
|
|
|
const uint8_t *start;
|
|
|
|
|
const uint8_t *end;
|
|
|
|
|
} UnmarshalState;
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
UMR_OK,
|
|
|
|
|
UMR_STACKOVERFLOW,
|
|
|
|
|
UMR_EOS,
|
|
|
|
|
UMR_UNKNOWN,
|
|
|
|
|
UMR_EXPECTED_INTEGER,
|
|
|
|
|
UMR_EXPECTED_TABLE,
|
|
|
|
|
UMR_EXPECTED_FIBER,
|
|
|
|
|
UMR_EXPECTED_STRING,
|
|
|
|
|
UMR_INVALID_REFERENCE,
|
|
|
|
|
UMR_INVALID_BYTECODE,
|
|
|
|
|
UMR_INVALID_FIBER
|
|
|
|
|
} UnmarshalResult;
|
|
|
|
|
|
|
|
|
|
const char *umr_strings[] = {
|
|
|
|
|
"",
|
|
|
|
|
"stack overflow",
|
|
|
|
|
"unexpected end of source",
|
|
|
|
|
"unmarshal error",
|
|
|
|
|
"expected integer",
|
|
|
|
|
"expected table",
|
|
|
|
|
"expected fiber",
|
|
|
|
|
"expected string",
|
|
|
|
|
"invalid reference",
|
|
|
|
|
"invalid bytecode",
|
|
|
|
|
"invalid fiber"
|
|
|
|
|
};
|
|
|
|
|
#define MARSH_EOS(st, data) do { \
|
|
|
|
|
if ((data) >= (st)->end) janet_panic("unexpected end of source");\
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
/* Helper to read a 32 bit integer from an unmarshal state */
|
|
|
|
|
static int32_t readint(UnmarshalState *st, const uint8_t **atdata) {
|
|
|
|
|
const uint8_t *data = *atdata;
|
|
|
|
|
int32_t ret;
|
|
|
|
|
if (data >= st->end) longjmp(st->err, UMR_EOS);
|
|
|
|
|
MARSH_EOS(st, data);
|
|
|
|
|
if (*data < 128) {
|
|
|
|
|
ret = *data++;
|
|
|
|
|
} else if (*data < 192) {
|
|
|
|
|
if (data + 2 > st->end) longjmp(st->err, UMR_EOS);
|
|
|
|
|
MARSH_EOS(st, data + 1);
|
|
|
|
|
ret = ((data[0] & 0x3F) << 8) + data[1];
|
|
|
|
|
ret = ((ret << 18) >> 18);
|
|
|
|
|
data += 2;
|
|
|
|
|
} else if (*data == LB_INTEGER) {
|
|
|
|
|
if (data + 5 > st->end) longjmp(st->err, UMR_EOS);
|
|
|
|
|
MARSH_EOS(st, data + 4);
|
|
|
|
|
ret = ((int32_t)(data[1]) << 24) |
|
|
|
|
|
((int32_t)(data[2]) << 16) |
|
|
|
|
|
((int32_t)(data[3]) << 8) |
|
|
|
|
|
(int32_t)(data[4]);
|
|
|
|
|
data += 5;
|
|
|
|
|
} else {
|
|
|
|
|
longjmp(st->err, UMR_EXPECTED_INTEGER);
|
|
|
|
|
janet_panicf("expected integer, got byte %x at index %d",
|
|
|
|
|
*data,
|
|
|
|
|
data - st->start);
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
|
|
|
|
*atdata = data;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Assert a janet type */
|
|
|
|
|
static void janet_asserttype(Janet x, JanetType t) {
|
|
|
|
|
if (!janet_checktype(x, t)) {
|
|
|
|
|
janet_panicf("expected type %T, got %v", 1 << t, x);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Forward declarations for mutual recursion */
|
|
|
|
|
static const uint8_t *unmarshal_one(
|
|
|
|
|
UnmarshalState *st,
|
|
|
|
@@ -602,13 +544,12 @@ static const uint8_t *unmarshal_one_env(
|
|
|
|
|
const uint8_t *data,
|
|
|
|
|
JanetFuncEnv **out,
|
|
|
|
|
int flags) {
|
|
|
|
|
const uint8_t *end = st->end;
|
|
|
|
|
if (data >= end) longjmp(st->err, UMR_EOS);
|
|
|
|
|
MARSH_EOS(st, data);
|
|
|
|
|
if (*data == LB_FUNCENV_REF) {
|
|
|
|
|
data++;
|
|
|
|
|
int32_t index = readint(st, &data);
|
|
|
|
|
if (index < 0 || index >= janet_v_count(st->lookup_envs))
|
|
|
|
|
longjmp(st->err, UMR_INVALID_REFERENCE);
|
|
|
|
|
janet_panicf("invalid funcenv reference %d", index);
|
|
|
|
|
*out = st->lookup_envs[index];
|
|
|
|
|
} else {
|
|
|
|
|
JanetFuncEnv *env = janet_gcalloc(JANET_MEMORY_FUNCENV, sizeof(JanetFuncEnv));
|
|
|
|
@@ -621,11 +562,13 @@ static const uint8_t *unmarshal_one_env(
|
|
|
|
|
Janet fiberv;
|
|
|
|
|
/* On stack variant */
|
|
|
|
|
data = unmarshal_one(st, data, &fiberv, flags);
|
|
|
|
|
if (!janet_checktype(fiberv, JANET_FIBER)) longjmp(st->err, UMR_EXPECTED_FIBER);
|
|
|
|
|
janet_asserttype(fiberv, JANET_FIBER);
|
|
|
|
|
env->as.fiber = janet_unwrap_fiber(fiberv);
|
|
|
|
|
/* Unmarshalling 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);
|
|
|
|
|
if (env->offset != 0 && env->offset != offset)
|
|
|
|
|
janet_panic("invalid funcenv offset");
|
|
|
|
|
if (env->length != 0 && env->length != length)
|
|
|
|
|
janet_panic("invalid funcenv length");
|
|
|
|
|
} else {
|
|
|
|
|
/* Off stack variant */
|
|
|
|
|
env->as.values = malloc(sizeof(Janet) * length);
|
|
|
|
@@ -648,13 +591,12 @@ static const uint8_t *unmarshal_one_def(
|
|
|
|
|
const uint8_t *data,
|
|
|
|
|
JanetFuncDef **out,
|
|
|
|
|
int flags) {
|
|
|
|
|
const uint8_t *end = st->end;
|
|
|
|
|
if (data >= end) longjmp(st->err, UMR_EOS);
|
|
|
|
|
MARSH_EOS(st, data);
|
|
|
|
|
if (*data == LB_FUNCDEF_REF) {
|
|
|
|
|
data++;
|
|
|
|
|
int32_t index = readint(st, &data);
|
|
|
|
|
if (index < 0 || index >= janet_v_count(st->lookup_defs))
|
|
|
|
|
longjmp(st->err, UMR_INVALID_REFERENCE);
|
|
|
|
|
janet_panicf("invalid funcdef reference %d", index);
|
|
|
|
|
*out = st->lookup_defs[index];
|
|
|
|
|
} else {
|
|
|
|
|
/* Initialize with values that will not break garbage collection
|
|
|
|
@@ -691,13 +633,13 @@ static const uint8_t *unmarshal_one_def(
|
|
|
|
|
if (def->flags & JANET_FUNCDEF_FLAG_HASNAME) {
|
|
|
|
|
Janet x;
|
|
|
|
|
data = unmarshal_one(st, data, &x, flags + 1);
|
|
|
|
|
if (!janet_checktype(x, JANET_STRING)) longjmp(st->err, UMR_EXPECTED_STRING);
|
|
|
|
|
janet_asserttype(x, JANET_STRING);
|
|
|
|
|
def->name = janet_unwrap_string(x);
|
|
|
|
|
}
|
|
|
|
|
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCE) {
|
|
|
|
|
Janet x;
|
|
|
|
|
data = unmarshal_one(st, data, &x, flags + 1);
|
|
|
|
|
if (!janet_checktype(x, JANET_STRING)) longjmp(st->err, UMR_EXPECTED_STRING);
|
|
|
|
|
janet_asserttype(x, JANET_STRING);
|
|
|
|
|
def->source = janet_unwrap_string(x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -720,7 +662,7 @@ static const uint8_t *unmarshal_one_def(
|
|
|
|
|
JANET_OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
for (int32_t i = 0; i < bytecode_length; i++) {
|
|
|
|
|
if (data + 4 > end) longjmp(st->err, UMR_EOS);
|
|
|
|
|
MARSH_EOS(st, data + 3);
|
|
|
|
|
def->bytecode[i] =
|
|
|
|
|
(uint32_t)(data[0]) |
|
|
|
|
|
((uint32_t)(data[1]) << 8) |
|
|
|
|
@@ -776,7 +718,8 @@ static const uint8_t *unmarshal_one_def(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate */
|
|
|
|
|
if (janet_verify(def)) longjmp(st->err, UMR_INVALID_BYTECODE);
|
|
|
|
|
if (janet_verify(def))
|
|
|
|
|
janet_panic("funcdef has invalid bytecode");
|
|
|
|
|
|
|
|
|
|
/* Set def */
|
|
|
|
|
*out = def;
|
|
|
|
@@ -821,7 +764,7 @@ static const uint8_t *unmarshal_one_fiber(
|
|
|
|
|
if ((int32_t)(frame + JANET_FRAME_SIZE) > fiber->stackstart ||
|
|
|
|
|
fiber->stackstart > fiber->stacktop ||
|
|
|
|
|
fiber->stacktop > fiber->maxstack) {
|
|
|
|
|
goto error;
|
|
|
|
|
janet_panic("fiber has incorrect stack setup");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate stack memory */
|
|
|
|
@@ -849,9 +792,7 @@ static const uint8_t *unmarshal_one_fiber(
|
|
|
|
|
/* Get function */
|
|
|
|
|
Janet funcv;
|
|
|
|
|
data = unmarshal_one(st, data, &funcv, flags + 1);
|
|
|
|
|
if (!janet_checktype(funcv, JANET_FUNCTION)) {
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
janet_asserttype(funcv, JANET_FUNCTION);
|
|
|
|
|
func = janet_unwrap_function(funcv);
|
|
|
|
|
def = func->def;
|
|
|
|
|
|
|
|
|
@@ -861,17 +802,25 @@ static const uint8_t *unmarshal_one_fiber(
|
|
|
|
|
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;
|
|
|
|
|
if (env->offset != 0 && env->offset != offset)
|
|
|
|
|
janet_panic("funcenv offset does not match fiber frame");
|
|
|
|
|
if (env->length != 0 && env->length != offset)
|
|
|
|
|
janet_panic("funcenv length does not match fiber frame");
|
|
|
|
|
env->offset = offset;
|
|
|
|
|
env->length = length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Error checking */
|
|
|
|
|
int32_t expected_framesize = def->slotcount;
|
|
|
|
|
if (expected_framesize != stacktop - stack) goto error;
|
|
|
|
|
if (pcdiff < 0 || pcdiff >= def->bytecode_length) goto error;
|
|
|
|
|
if ((int32_t)(prevframe + JANET_FRAME_SIZE) > stack) goto error;
|
|
|
|
|
if (expected_framesize != stacktop - stack) {
|
|
|
|
|
janet_panic("fiber stackframe size mismatch");
|
|
|
|
|
}
|
|
|
|
|
if (pcdiff < 0 || pcdiff >= def->bytecode_length) {
|
|
|
|
|
janet_panic("fiber stackframe has invalid pc");
|
|
|
|
|
}
|
|
|
|
|
if ((int32_t)(prevframe + JANET_FRAME_SIZE) > stack) {
|
|
|
|
|
janet_panic("fibre stackframe does not align with previous frame");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get stack items */
|
|
|
|
|
for (int32_t i = stack; i < stacktop; i++)
|
|
|
|
@@ -888,14 +837,16 @@ static const uint8_t *unmarshal_one_fiber(
|
|
|
|
|
stacktop = stack - JANET_FRAME_SIZE;
|
|
|
|
|
stack = prevframe;
|
|
|
|
|
}
|
|
|
|
|
if (stack < 0) goto error;
|
|
|
|
|
if (stack < 0) {
|
|
|
|
|
janet_panic("fiber has too many stackframes");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for child fiber */
|
|
|
|
|
if (fiber->flags & JANET_FIBER_FLAG_HASCHILD) {
|
|
|
|
|
Janet fiberv;
|
|
|
|
|
fiber->flags &= ~JANET_FIBER_FLAG_HASCHILD;
|
|
|
|
|
data = unmarshal_one(st, data, &fiberv, flags + 1);
|
|
|
|
|
if (!janet_checktype(fiberv, JANET_FIBER)) longjmp(st->err, UMR_EXPECTED_FIBER);
|
|
|
|
|
janet_asserttype(fiberv, JANET_FIBER);
|
|
|
|
|
fiber->child = janet_unwrap_fiber(fiberv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -903,10 +854,6 @@ static const uint8_t *unmarshal_one_fiber(
|
|
|
|
|
fiber->frame = frame;
|
|
|
|
|
*out = fiber;
|
|
|
|
|
return data;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
longjmp(st->err, UMR_INVALID_FIBER);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const uint8_t *unmarshal_one(
|
|
|
|
@@ -914,13 +861,9 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
const uint8_t *data,
|
|
|
|
|
Janet *out,
|
|
|
|
|
int flags) {
|
|
|
|
|
const uint8_t *end = st->end;
|
|
|
|
|
uint8_t lead;
|
|
|
|
|
if ((flags & 0xFFFF) > JANET_RECURSION_GUARD) {
|
|
|
|
|
longjmp(st->err, UMR_STACKOVERFLOW);
|
|
|
|
|
}
|
|
|
|
|
#define EXTRA(N) if (data + N > end) longjmp(st->err, UMR_EOS)
|
|
|
|
|
EXTRA(1);
|
|
|
|
|
MARSH_STACKCHECK;
|
|
|
|
|
MARSH_EOS(st, data);
|
|
|
|
|
lead = data[0];
|
|
|
|
|
if (lead < 200) {
|
|
|
|
|
*out = janet_wrap_integer(readint(st, &data));
|
|
|
|
@@ -938,7 +881,7 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
return data + 1;
|
|
|
|
|
case LB_INTEGER:
|
|
|
|
|
/* Long integer */
|
|
|
|
|
EXTRA(5);
|
|
|
|
|
MARSH_EOS(st, data + 4);
|
|
|
|
|
*out = janet_wrap_integer(
|
|
|
|
|
(data[4]) |
|
|
|
|
|
(data[3] << 8) |
|
|
|
|
@@ -952,7 +895,7 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
double d;
|
|
|
|
|
uint8_t bytes[8];
|
|
|
|
|
} u;
|
|
|
|
|
EXTRA(9);
|
|
|
|
|
MARSH_EOS(st, data + 8);
|
|
|
|
|
#ifdef JANET_BIG_ENDIAN
|
|
|
|
|
u.bytes[0] = data[8];
|
|
|
|
|
u.bytes[1] = data[7];
|
|
|
|
@@ -976,7 +919,7 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
case LB_REGISTRY: {
|
|
|
|
|
data++;
|
|
|
|
|
int32_t len = readint(st, &data);
|
|
|
|
|
EXTRA(len);
|
|
|
|
|
MARSH_EOS(st, data - 1 + len);
|
|
|
|
|
if (lead == LB_STRING) {
|
|
|
|
|
const uint8_t *str = janet_string(data, len);
|
|
|
|
|
*out = janet_wrap_string(str);
|
|
|
|
@@ -1064,7 +1007,7 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
janet_array_push(&st->lookup, *out);
|
|
|
|
|
} else if (lead == LB_REFERENCE) {
|
|
|
|
|
if (len < 0 || len >= st->lookup.count)
|
|
|
|
|
longjmp(st->err, UMR_INVALID_REFERENCE);
|
|
|
|
|
janet_panicf("invalid reference %d", len);
|
|
|
|
|
*out = st->lookup.data[len];
|
|
|
|
|
} else {
|
|
|
|
|
/* Table */
|
|
|
|
@@ -1074,7 +1017,7 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
if (lead == LB_TABLE_PROTO) {
|
|
|
|
|
Janet proto;
|
|
|
|
|
data = unmarshal_one(st, data, &proto, flags + 1);
|
|
|
|
|
if (!janet_checktype(proto, JANET_TABLE)) longjmp(st->err, UMR_EXPECTED_TABLE);
|
|
|
|
|
janet_asserttype(proto, JANET_TABLE);
|
|
|
|
|
t->proto = janet_unwrap_table(proto);
|
|
|
|
|
}
|
|
|
|
|
for (int32_t i = 0; i < len; i++) {
|
|
|
|
@@ -1086,36 +1029,39 @@ static const uint8_t *unmarshal_one(
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
longjmp(st->err, UMR_UNKNOWN);
|
|
|
|
|
default: {
|
|
|
|
|
janet_panicf("unknown byte %x at index %d",
|
|
|
|
|
*data,
|
|
|
|
|
(int)(data - st->start));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#undef EXTRA
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int janet_unmarshal(
|
|
|
|
|
Janet janet_unmarshal(
|
|
|
|
|
const uint8_t *bytes,
|
|
|
|
|
size_t len,
|
|
|
|
|
int flags,
|
|
|
|
|
Janet *out,
|
|
|
|
|
JanetTable *reg,
|
|
|
|
|
const uint8_t **next) {
|
|
|
|
|
int status;
|
|
|
|
|
/* Avoid longjmp clobber warning in GCC */
|
|
|
|
|
UnmarshalState st;
|
|
|
|
|
st.start = bytes;
|
|
|
|
|
st.end = bytes + len;
|
|
|
|
|
st.lookup_defs = NULL;
|
|
|
|
|
st.lookup_envs = NULL;
|
|
|
|
|
st.reg = reg;
|
|
|
|
|
janet_array_init(&st.lookup, 0);
|
|
|
|
|
if (!(status = setjmp(st.err))) {
|
|
|
|
|
const uint8_t *nextbytes = unmarshal_one(&st, bytes, out, flags);
|
|
|
|
|
if (next) *next = nextbytes;
|
|
|
|
|
}
|
|
|
|
|
Janet out;
|
|
|
|
|
const uint8_t *nextbytes = unmarshal_one(&st, bytes, &out, flags);
|
|
|
|
|
if (next) *next = nextbytes;
|
|
|
|
|
/* Clean up - this should be auto released on panics, TODO. We should
|
|
|
|
|
* change the vector implementation to track allocations for auto release, and
|
|
|
|
|
* make st.lookup auto release as well, or move to heap. */
|
|
|
|
|
janet_array_deinit(&st.lookup);
|
|
|
|
|
janet_v_free(st.lookup_defs);
|
|
|
|
|
janet_v_free(st.lookup_envs);
|
|
|
|
|
return status;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* C functions */
|
|
|
|
@@ -1130,8 +1076,6 @@ static Janet cfun_marshal(int32_t argc, Janet *argv) {
|
|
|
|
|
janet_arity(argc, 1, 2);
|
|
|
|
|
JanetBuffer *buffer;
|
|
|
|
|
JanetTable *rreg = NULL;
|
|
|
|
|
Janet err_param = janet_wrap_nil();
|
|
|
|
|
int status;
|
|
|
|
|
if (argc > 1) {
|
|
|
|
|
rreg = janet_gettable(argv, 1);
|
|
|
|
|
}
|
|
|
|
@@ -1140,9 +1084,7 @@ static Janet cfun_marshal(int32_t argc, Janet *argv) {
|
|
|
|
|
} else {
|
|
|
|
|
buffer = janet_buffer(10);
|
|
|
|
|
}
|
|
|
|
|
status = janet_marshal(buffer, argv[0], &err_param, rreg, 0);
|
|
|
|
|
if (status)
|
|
|
|
|
janet_panicf("%s for %V", mr_strings[status], err_param);
|
|
|
|
|
janet_marshal(buffer, argv[0], rreg, 0);
|
|
|
|
|
return janet_wrap_buffer(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1150,16 +1092,10 @@ static Janet cfun_unmarshal(int32_t argc, Janet *argv) {
|
|
|
|
|
janet_arity(argc, 1, 2);
|
|
|
|
|
JanetByteView view = janet_getbytes(argv, 0);
|
|
|
|
|
JanetTable *reg = NULL;
|
|
|
|
|
Janet ret;
|
|
|
|
|
int status;
|
|
|
|
|
if (argc > 1) {
|
|
|
|
|
reg = janet_gettable(argv, 1);
|
|
|
|
|
}
|
|
|
|
|
status = janet_unmarshal(view.bytes, (size_t) view.len, 0, &ret, reg, NULL);
|
|
|
|
|
if (status) {
|
|
|
|
|
janet_panic(umr_strings[status]);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
return janet_unmarshal(view.bytes, (size_t) view.len, 0, reg, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const JanetReg marsh_cfuns[] = {
|
|
|
|
|