Better working panic implementation and more cleanup in main vm loop.

This commit is contained in:
Calvin Rose 2019-01-05 00:33:20 -05:00
parent cd6a7793e8
commit 5b62c8e6db
5 changed files with 115 additions and 206 deletions

View File

@ -681,7 +681,7 @@ const uint8_t *janet_formatc(const char *format, ...) {
number_to_string_b(bufp, va_arg(args, double));
break;
case 'd':
integer_to_string_b(bufp, va_arg(args, int32_t));
integer_to_string_b(bufp, va_arg(args, long));
break;
case 'S':
{
@ -708,7 +708,7 @@ const uint8_t *janet_formatc(const char *format, ...) {
}
case 'T':
{
int types = va_arg(args, int32_t);
int types = va_arg(args, long);
pushtypes(bufp, types);
break;
}

View File

@ -145,13 +145,14 @@ int janet_compare(Janet x, Janet y) {
return (janet_type(x) < janet_type(y)) ? -1 : 1;
}
/* Gets a value and returns. If successful, return 0. If there is an error,
* returns -1 for bad ds, -2 for bad key */
int janet_get(Janet ds, Janet key, Janet *out) {
/* Gets a value and returns. Can panic. */
Janet janet_get(Janet ds, Janet key) {
Janet value;
switch (janet_type(ds)) {
default:
return -1;
janet_panicf("get: expected %T, got %v", JANET_TFLAG_LENGTHABLE, ds);
value = janet_wrap_nil();
break;
case JANET_STRUCT:
value = janet_struct_get(janet_unwrap_struct(ds), key);
break;
@ -162,7 +163,8 @@ int janet_get(Janet ds, Janet key, Janet *out) {
{
JanetArray *array = janet_unwrap_array(ds);
int32_t index;
if (!janet_checkint(key)) return -2;
if (!janet_checkint(key))
janet_panic("expected integer key");
index = janet_unwrap_integer(key);
if (index < 0 || index >= array->count) {
value = janet_wrap_nil();
@ -175,10 +177,10 @@ int janet_get(Janet ds, Janet key, Janet *out) {
{
const Janet *tuple = janet_unwrap_tuple(ds);
int32_t index;
if (!janet_checkint(key)) return -2;
if (!janet_checkint(key))
janet_panic("expected integer key");
index = janet_unwrap_integer(key);
if (index < 0 || index >= janet_tuple_length(tuple)) {
/*vm_throw("index out of bounds");*/
value = janet_wrap_nil();
} else {
value = tuple[index];
@ -189,7 +191,8 @@ int janet_get(Janet ds, Janet key, Janet *out) {
{
JanetBuffer *buffer = janet_unwrap_buffer(ds);
int32_t index;
if (!janet_checkint(key)) return -2;
if (!janet_checkint(key))
janet_panic("expected integer key");
index = janet_unwrap_integer(key);
if (index < 0 || index >= buffer->count) {
value = janet_wrap_nil();
@ -204,7 +207,8 @@ int janet_get(Janet ds, Janet key, Janet *out) {
{
const uint8_t *str = janet_unwrap_string(ds);
int32_t index;
if (!janet_checkint(key)) return -2;
if (!janet_checkint(key))
janet_panic("expected integer key");
index = janet_unwrap_integer(key);
if (index < 0 || index >= janet_string_length(str)) {
value = janet_wrap_nil();
@ -214,17 +218,17 @@ int janet_get(Janet ds, Janet key, Janet *out) {
break;
}
}
*out = value;
return 0;
return value;
}
int janet_getindex(Janet ds, int32_t index, Janet *out) {
Janet janet_getindex(Janet ds, int32_t index) {
Janet value;
if (index < 0)
return -2;
if (index < 0) janet_panic("expected non-negative index");
switch (janet_type(ds)) {
default:
return -1;
janet_panicf("get: expected %T, got %v", JANET_TFLAG_LENGTHABLE, ds);
value = janet_wrap_nil();
break;
case JANET_STRING:
case JANET_SYMBOL:
case JANET_KEYWORD:
@ -262,44 +266,37 @@ int janet_getindex(Janet ds, int32_t index, Janet *out) {
value = janet_struct_get(janet_unwrap_struct(ds), janet_wrap_integer(index));
break;
}
*out = value;
return 0;
return value;
}
int janet_length(Janet x, int32_t *out) {
int32_t len;
int32_t janet_length(Janet x) {
switch (janet_type(x)) {
default:
return -1;
janet_panicf("expected %T, got %v", JANET_TFLAG_LENGTHABLE, x);
return 0;
case JANET_STRING:
case JANET_SYMBOL:
case JANET_KEYWORD:
len = janet_string_length(janet_unwrap_string(x));
break;
return janet_string_length(janet_unwrap_string(x));
case JANET_ARRAY:
len = janet_unwrap_array(x)->count;
break;
return janet_unwrap_array(x)->count;
case JANET_BUFFER:
len = janet_unwrap_buffer(x)->count;
break;
return janet_unwrap_buffer(x)->count;
case JANET_TUPLE:
len = janet_tuple_length(janet_unwrap_tuple(x));
break;
return janet_tuple_length(janet_unwrap_tuple(x));
case JANET_STRUCT:
len = janet_struct_length(janet_unwrap_struct(x));
break;
return janet_struct_length(janet_unwrap_struct(x));
case JANET_TABLE:
len = janet_unwrap_table(x)->count;
break;
return janet_unwrap_table(x)->count;
}
*out = len;
return 0;
}
int janet_putindex(Janet ds, int32_t index, Janet value) {
void janet_putindex(Janet ds, int32_t index, Janet value) {
switch (janet_type(ds)) {
default:
return -1;
janet_panicf("expected %T, got %v",
JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE, ds);
break;
case JANET_ARRAY:
{
JanetArray *array = janet_unwrap_array(ds);
@ -313,7 +310,8 @@ int janet_putindex(Janet ds, int32_t index, Janet value) {
case JANET_BUFFER:
{
JanetBuffer *buffer = janet_unwrap_buffer(ds);
if (!janet_checkint(value)) return -3;
if (!janet_checkint(value))
janet_panicf("can only put integers in buffers, got %v", value);
if (index >= buffer->count) {
janet_buffer_ensure(buffer, index + 1, 2);
buffer->count = index + 1;
@ -328,20 +326,21 @@ int janet_putindex(Janet ds, int32_t index, Janet value) {
break;
}
}
return 0;
}
int janet_put(Janet ds, Janet key, Janet value) {
void janet_put(Janet ds, Janet key, Janet value) {
switch (janet_type(ds)) {
default:
return -1;
janet_panicf("expected %T, got %v",
JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE, ds);
break;
case JANET_ARRAY:
{
int32_t index;
JanetArray *array = janet_unwrap_array(ds);
if (!janet_checkint(key)) return -2;
if (!janet_checkint(key)) janet_panicf("expected integer key, got %v", key);
index = janet_unwrap_integer(key);
if (index < 0 || index == INT32_MAX) return -2;
if (index < 0 || index == INT32_MAX) janet_panicf("bad integer key, got %v", key);
if (index >= array->count) {
janet_array_setcount(array, index + 1);
}
@ -352,10 +351,11 @@ int janet_put(Janet ds, Janet key, Janet value) {
{
int32_t index;
JanetBuffer *buffer = janet_unwrap_buffer(ds);
if (!janet_checkint(key)) return -2;
if (!janet_checkint(key)) janet_panicf("expected integer key, got %v", key);
index = janet_unwrap_integer(key);
if (index < 0 || index == INT32_MAX) return -2;
if (!janet_checkint(value)) return -3;
if (index < 0 || index == INT32_MAX) janet_panicf("bad integer key, got %v", key);
if (!janet_checkint(value))
janet_panicf("can only put integers in buffers, got %v", value);
if (index >= buffer->count) {
janet_buffer_setcount(buffer, index + 1);
}
@ -366,5 +366,4 @@ int janet_put(Janet ds, Janet key, Janet value) {
janet_table_put(janet_unwrap_table(ds), key, value);
break;
}
return 0;
}

View File

@ -162,16 +162,14 @@ static void *op_lookup[255] = {
#define vm_assert(cond, e) do {if (!(cond)) vm_throw((e)); } while (0)
#define vm_assert_type(X, T) do { \
if (!(janet_checktype((X), (T)))) { \
expected_types = 1 << (T); \
retreg = (X); \
goto vm_type_error; \
vm_commit(); \
janet_panicf("expected %T, got %t", (1 << (T)), (X)); \
} \
} while (0)
#define vm_assert_types(X, TS) do { \
if (!(janet_checktypes((X), (TS)))) { \
expected_types = (TS); \
retreg = (X); \
goto vm_type_error; \
vm_commit(); \
janet_panicf("expected %T, got %t", (TS), (X)); \
} \
} while (0)
@ -223,14 +221,13 @@ static void *op_lookup[255] = {
/* Call a non function type */
static Janet call_nonfn(JanetFiber *fiber, Janet callee) {
int status;
int32_t argn = fiber->stacktop - fiber->stackstart;
Janet ds, key, ret;
Janet ds, key;
if (!janet_checktypes(callee, JANET_TFLAG_FUNCLIKE)) {
janet_panicf("attempted to called %v, expected %t", callee,
janet_panicf("attempted to call %v, expected %T", callee,
JANET_TFLAG_CALLABLE);
}
if (argn != 1) janet_panicf("%v called with arity %d, expected 1", argn);
if (argn != 1) janet_panicf("%v called with arity %d, expected 1", callee, argn);
if (janet_checktypes(callee, JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY)) {
ds = callee;
key = fiber->data[fiber->stackstart];
@ -239,13 +236,7 @@ static Janet call_nonfn(JanetFiber *fiber, Janet callee) {
key = callee;
}
fiber->stacktop = fiber->stackstart;
status = janet_get(ds, key, &ret);
if (status == -2) {
janet_panic("expected integer key");
} else if (status == -1) {
janet_panic("expected table or struct");
}
return ret;
return janet_get(ds, key);
}
/* Interpreter main loop */
@ -256,13 +247,6 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
register uint32_t *pc;
register JanetFunction *func;
vm_restore();
/* Keep in mind the garbage collector cannot see this value.
* Values stored here should be used immediately */
Janet retreg;
/* Expected types on type error */
uint16_t expected_types;
/* Only should be hit if the fiber is either waiting for a child, or
* waiting to be resumed. In those cases, use input and increment pc. We
@ -292,22 +276,31 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
vm_pcnext();
VM_OP(JOP_ERROR)
janet_panicv(stack[A]);
vm_next(); /* pacify compiler warnings */
vm_return(JANET_SIGNAL_ERROR, stack[A]);
VM_OP(JOP_TYPECHECK)
if (!janet_checktypes(stack[A], E)) {
janet_panicf("expected %T, got %t", E, stack[A]);
}
vm_assert_types(stack[A], E);
vm_pcnext();
VM_OP(JOP_RETURN)
retreg = stack[D];
goto vm_handle_return;
{
Janet retval = stack[D];
janet_fiber_popframe(fiber);
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, retval);
vm_restore();
stack[A] = retval;
vm_checkgc_pcnext();
}
VM_OP(JOP_RETURN_NIL)
retreg = janet_wrap_nil();
goto vm_handle_return;
{
Janet retval = janet_wrap_nil();
janet_fiber_popframe(fiber);
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, retval);
vm_restore();
stack[A] = retval;
vm_checkgc_pcnext();
}
VM_OP(JOP_ADD_IMMEDIATE)
vm_binop_immediate(+);
@ -555,9 +548,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
if (janet_indexed_view(stack[D], &vals, &len)) {
janet_fiber_pushn(fiber, vals, len);
} else {
retreg = stack[D];
expected_types = JANET_TFLAG_INDEXED;
goto vm_type_error;
janet_panicf("expected %T, got %t", JANET_TFLAG_INDEXED, stack[D]);
}
}
stack = fiber->data + fiber->frame;
@ -582,12 +573,12 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
vm_checkgc_next();
} else if (janet_checktype(callee, JANET_CFUNCTION)) {
JanetArgs args;
Janet retreg = janet_wrap_nil();
vm_commit();
args.n = fiber->stacktop - fiber->stackstart;
janet_fiber_cframe(fiber, janet_unwrap_cfunction(callee));
retreg = janet_wrap_nil();
args.v = fiber->data + fiber->frame;
args.ret = &retreg;
vm_commit();
if (janet_unwrap_cfunction(callee)(args)) janet_panicv(retreg);
janet_fiber_popframe(fiber);
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, retreg);
@ -614,30 +605,34 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
stack = fiber->data + fiber->frame;
pc = func->def->bytecode;
vm_checkgc_next();
} else if (janet_checktype(callee, JANET_CFUNCTION)) {
JanetArgs args;
args.n = fiber->stacktop - fiber->stackstart;
janet_fiber_cframe(fiber, janet_unwrap_cfunction(callee));
retreg = janet_wrap_nil();
args.v = fiber->data + fiber->frame;
args.ret = &retreg;
vm_commit();
if (janet_unwrap_cfunction(callee)(args))
vm_return(JANET_SIGNAL_ERROR, retreg);
janet_fiber_popframe(fiber);
} else {
vm_commit();
retreg = call_nonfn(fiber, callee);
Janet retreg = janet_wrap_nil();
if (janet_checktype(callee, JANET_CFUNCTION)) {
JanetArgs args;
vm_commit();
args.n = fiber->stacktop - fiber->stackstart;
janet_fiber_cframe(fiber, janet_unwrap_cfunction(callee));
args.v = fiber->data + fiber->frame;
args.ret = &retreg;
if (janet_unwrap_cfunction(callee)(args))
vm_return(JANET_SIGNAL_ERROR, retreg);
janet_fiber_popframe(fiber);
} else {
vm_commit();
retreg = call_nonfn(fiber, callee);
}
janet_fiber_popframe(fiber);
if (fiber->frame == 0)
vm_return(JANET_SIGNAL_OK, retreg);
vm_restore();
stack[A] = retreg;
vm_checkgc_pcnext();
}
/* Make it a tail call */
janet_fiber_popframe(fiber);
if (fiber->frame == 0)
vm_return(JANET_SIGNAL_OK, retreg);
goto vm_reset;
}
VM_OP(JOP_RESUME)
{
Janet retreg;
vm_assert_type(stack[B], JANET_FIBER);
JanetFiber *child = janet_unwrap_fiber(stack[B]);
fiber->child = child;
@ -658,78 +653,24 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
}
VM_OP(JOP_PUT)
{
Janet ds = stack[A];
Janet key = stack[B];
Janet value = stack[C];
int status = janet_put(ds, key, value);
if (status == -1) {
expected_types = JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE;
retreg = ds;
goto vm_type_error;
} else if (status == -2) {
vm_throw("expected integer key for data structure");
} else if (status == -3) {
vm_throw("expected integer value for data structure");
}
vm_checkgc_pcnext();
}
janet_put(stack[A], stack[B], stack[C]);
vm_checkgc_pcnext();
VM_OP(JOP_PUT_INDEX)
{
Janet ds = stack[A];
Janet value = stack[B];
int32_t index = (int32_t)C;
int status = janet_putindex(ds, index, value);
if (status == -1) {
expected_types = JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE;
retreg = ds;
goto vm_type_error;
} else if (status == -3) {
vm_throw("expected integer value for data structure");
}
vm_checkgc_pcnext();
}
janet_putindex(stack[A], C, stack[B]);
vm_checkgc_pcnext();
VM_OP(JOP_GET)
{
Janet ds = stack[B];
Janet key = stack[C];
int status = janet_get(ds, key, stack + A);
if (status == -1) {
expected_types = JANET_TFLAG_LENGTHABLE;
retreg = ds;
goto vm_type_error;
} else if (status == -2) {
vm_throw("expected integer key for data structure");
}
vm_pcnext();
}
stack[A] = janet_get(stack[B], stack[C]);
vm_pcnext();
VM_OP(JOP_GET_INDEX)
{
Janet ds = stack[B];
int32_t index = C;
if (janet_getindex(ds, index, stack + A)) {
expected_types = JANET_TFLAG_LENGTHABLE;
retreg = ds;
goto vm_type_error;
}
vm_pcnext();
}
stack[A] = janet_getindex(stack[B], C);
vm_pcnext();
VM_OP(JOP_LENGTH)
{
Janet x = stack[E];
int32_t len;
if (janet_length(x, &len)) {
expected_types = JANET_TFLAG_LENGTHABLE;
retreg = x;
goto vm_type_error;
}
stack[A] = janet_wrap_integer(len);
vm_pcnext();
}
stack[A] = janet_wrap_integer(janet_length(stack[E]));
vm_pcnext();
VM_OP(JOP_MAKE_ARRAY)
{
@ -803,38 +744,6 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
vm_checkgc_pcnext();
}
/* Handle returning from stack frame. Expect return value in retreg */
vm_handle_return:
{
janet_fiber_popframe(fiber);
if (fiber->frame == 0) vm_return(JANET_SIGNAL_OK, retreg);
goto vm_reset;
}
/* Handle type errors. The found type is the type of retreg,
* the expected types are in the expected_types field. */
vm_type_error:
{
JanetBuffer errbuf;
const uint8_t *message;
janet_buffer_init(&errbuf, 10);
janet_buffer_push_cstring(&errbuf, "expected ");
janet_buffer_push_types(&errbuf, expected_types);
janet_buffer_push_cstring(&errbuf, ", got ");
janet_buffer_push_cstring(&errbuf, janet_type_names[janet_type(retreg)]);
message = janet_string(errbuf.data, errbuf.count);
janet_buffer_deinit(&errbuf);
janet_panics(message);
}
/* Reset state of machine */
vm_reset:
{
vm_restore();
stack[A] = retreg;
vm_checkgc_pcnext();
}
VM_END()
}

View File

@ -1094,11 +1094,11 @@ JANET_API int32_t janet_hash(Janet x);
JANET_API int janet_compare(Janet x, Janet y);
JANET_API int janet_cstrcmp(const uint8_t *str, const char *other);
JANET_API JanetBuffer *janet_pretty(JanetBuffer *buffer, int depth, Janet x);
JANET_API int janet_get(Janet ds, Janet key, Janet *out);
JANET_API int janet_getindex(Janet ds, int32_t index, Janet *out);
JANET_API int janet_length(Janet x, int32_t *out);
JANET_API int janet_put(Janet ds, Janet key, Janet value);
JANET_API int janet_putindex(Janet ds, int32_t index, Janet value);
JANET_API Janet janet_get(Janet ds, Janet key);
JANET_API Janet janet_getindex(Janet ds, int32_t index);
JANET_API int32_t janet_length(Janet x);
JANET_API void janet_put(Janet ds, Janet key, Janet value);
JANET_API void janet_putindex(Janet ds, int32_t index, Janet value);
JANET_API void janet_inspect(Janet x);
/* VM functions */
@ -1132,7 +1132,7 @@ JANET_API int janet_typeabstract_err(JanetArgs args, int32_t n, const JanetAbstr
JANET_API void janet_panicv(Janet message);
JANET_API void janet_panic(const char *message);
JANET_API void janet_panics(const uint8_t *message);
#define janet_panicf(message, ...) janet_panics(janet_formatc(message, __VA_ARGS__))
#define janet_panicf(...) janet_panics(janet_formatc(__VA_ARGS__))
JANET_API void janet_panic_type(Janet x, int32_t n, int expected);
/* Helpers for writing modules */

View File

@ -110,5 +110,6 @@
(assert (= 2 (@{:ok 2} :ok)) "calling table")
(assert (= :bad (try (@{:ok 2} :ok :no) ([err] :bad))) "calling table too many arguments")
(assert (= :bad (try (:ok @{:ok 2} :no) ([err] :bad))) "calling keyword too many arguments")
(assert (= :oops (try (1 1) ([err] :oops))) "calling number fails")
(end-suite)