1
0
mirror of https://github.com/janet-lang/janet synced 2025-02-24 12:10:00 +00:00

Add support for debugging upvalues.

Upvalues are stored in the symbol slots structure as well, but
since they are always live, we repurpose the death_pc field to
refer to the environment index that we want to look at at runtime.
This commit is contained in:
Calvin Rose 2023-02-05 15:27:39 -06:00
parent c7fb7b4451
commit 7a1c9c7798
5 changed files with 63 additions and 14 deletions

View File

@ -2767,12 +2767,6 @@
(put nextenv :debug-level level) (put nextenv :debug-level level)
(put nextenv :signal (fiber/last-value fiber)) (put nextenv :signal (fiber/last-value fiber))
# define variables available at breakpoint
(def frame ((debug/stack fiber) 0))
(def pc (frame :pc))
(eachp [local value] (get frame :locals)
(put nextenv local @{:value value}))
(merge-into nextenv debugger-env) (merge-into nextenv debugger-env)
(defn debugger-chunks [buf p] (defn debugger-chunks [buf p]
(def status (:state p :delimiters)) (def status (:state p :delimiters))
@ -3381,11 +3375,16 @@
(print)) (print))
(defn .frame (defn .frame
"Show a stack frame." "Show a stack frame"
[&opt n] [&opt n]
(def stack (debug/stack (.fiber))) (def stack (debug/stack (.fiber)))
(in stack (or n 0))) (in stack (or n 0)))
(defn .locals
"Show local bindings"
[&opt n]
(get (.frame n) :locals))
(defn .fn (defn .fn
"Get the current function." "Get the current function."
[&opt n] [&opt n]

View File

@ -928,10 +928,15 @@ static Janet janet_disasm_symbolslots(JanetFuncDef *def) {
return janet_wrap_nil(); return janet_wrap_nil();
} }
JanetArray *symbolslots = janet_array(def->symbolmap_length); JanetArray *symbolslots = janet_array(def->symbolmap_length);
Janet upvaluekw = janet_ckeywordv("upvalue");
for (int32_t i = 0; i < def->symbolmap_length; i++) { for (int32_t i = 0; i < def->symbolmap_length; i++) {
JanetSymbolMap ss = def->symbolmap[i]; JanetSymbolMap ss = def->symbolmap[i];
Janet *t = janet_tuple_begin(4); Janet *t = janet_tuple_begin(4);
t[0] = janet_wrap_integer(ss.birth_pc); if (ss.birth_pc == UINT32_MAX) {
t[0] = upvaluekw;
} else {
t[0] = janet_wrap_integer(ss.birth_pc);
}
t[1] = janet_wrap_integer(ss.death_pc); t[1] = janet_wrap_integer(ss.death_pc);
t[2] = janet_wrap_integer(ss.slot_index); t[2] = janet_wrap_integer(ss.slot_index);
t[3] = janet_wrap_symbol(ss.symbol); t[3] = janet_wrap_symbol(ss.symbol);

View File

@ -344,6 +344,7 @@ found:
} }
/* non-local scope needs to expose its environment */ /* non-local scope needs to expose its environment */
JanetScope *original_scope = scope;
pair->keep = 1; pair->keep = 1;
while (scope && !(scope->flags & JANET_SCOPE_FUNCTION)) while (scope && !(scope->flags & JANET_SCOPE_FUNCTION))
scope = scope->parent; scope = scope->parent;
@ -365,7 +366,7 @@ found:
/* Check if scope already has env. If so, break */ /* Check if scope already has env. If so, break */
len = janet_v_count(scope->envs); len = janet_v_count(scope->envs);
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
if (scope->envs[j] == envindex) { if (scope->envs[j].envindex == envindex) {
scopefound = 1; scopefound = 1;
envindex = j; envindex = j;
break; break;
@ -374,7 +375,10 @@ found:
/* Add the environment if it is not already referenced */ /* Add the environment if it is not already referenced */
if (!scopefound) { if (!scopefound) {
len = janet_v_count(scope->envs); len = janet_v_count(scope->envs);
janet_v_push(scope->envs, envindex); JanetEnvRef ref;
ref.envindex = envindex;
ref.scope = original_scope;
janet_v_push(scope->envs, ref);
envindex = len; envindex = len;
} }
} }
@ -878,7 +882,10 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
/* Copy envs */ /* Copy envs */
def->environments_length = janet_v_count(scope->envs); def->environments_length = janet_v_count(scope->envs);
def->environments = janet_v_flatten(scope->envs); def->environments = janet_malloc(sizeof(int32_t) * def->environments_length);
for (int32_t i = 0; i < def->environments_length; i++) {
def->environments[i] = scope->envs[i].envindex;
}
def->constants_length = janet_v_count(scope->consts); def->constants_length = janet_v_count(scope->consts);
def->constants = janet_v_flatten(scope->consts); def->constants = janet_v_flatten(scope->consts);
@ -935,6 +942,30 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
/* Capture symbol to local mapping */ /* Capture symbol to local mapping */
JanetSymbolMap *locals = NULL; JanetSymbolMap *locals = NULL;
/* Symbol -> upvalue mapping */
JanetScope *top = c->scope;
while (top->parent) top = top->parent;
for (JanetScope *s = top; s != NULL; s = s->child) {
for (int32_t j = 0; j < janet_v_count(scope->envs); j++) {
JanetEnvRef ref = scope->envs[j];
JanetScope *upscope = ref.scope;
if (upscope != s) continue;
for (int32_t i = 0; i < janet_v_count(upscope->syms); i++) {
SymPair pair = upscope->syms[i];
if (pair.sym2) {
JanetSymbolMap jsm;
jsm.birth_pc = UINT32_MAX;
jsm.death_pc = j;
jsm.slot_index = pair.slot.index;
jsm.symbol = pair.sym2;
janet_v_push(locals, jsm);
}
}
}
}
/* Symbol -> slot mapping */
for (int32_t i = 0; i < janet_v_count(scope->syms); i++) { for (int32_t i = 0; i < janet_v_count(scope->syms); i++) {
SymPair pair = scope->syms[i]; SymPair pair = scope->syms[i];
if (pair.sym2) { if (pair.sym2) {

View File

@ -117,6 +117,11 @@ typedef struct SymPair {
uint32_t death_pc; uint32_t death_pc;
} SymPair; } SymPair;
typedef struct JanetEnvRef {
int32_t envindex;
JanetScope *scope;
} JanetEnvRef;
/* A lexical scope during compilation */ /* A lexical scope during compilation */
struct JanetScope { struct JanetScope {
@ -145,7 +150,7 @@ struct JanetScope {
/* Referenced closure environments. The values at each index correspond /* Referenced closure environments. The values at each index correspond
* to which index to get the environment from in the parent. The environment * to which index to get the environment from in the parent. The environment
* that corresponds to the direct parent's stack will always have value 0. */ * that corresponds to the direct parent's stack will always have value 0. */
int32_t *envs; JanetEnvRef *envs;
int32_t bytecode_start; int32_t bytecode_start;
int flags; int flags;

View File

@ -334,10 +334,19 @@ static Janet doframe(JanetStackFrame *frame) {
JanetTable *local_bindings = janet_table(0); JanetTable *local_bindings = janet_table(0);
for (int32_t i = def->symbolmap_length - 1; i >= 0; i--) { for (int32_t i = def->symbolmap_length - 1; i >= 0; i--) {
JanetSymbolMap jsm = def->symbolmap[i]; JanetSymbolMap jsm = def->symbolmap[i];
Janet value = janet_wrap_nil();
uint32_t pc = (uint32_t)(frame->pc - def->bytecode); uint32_t pc = (uint32_t)(frame->pc - def->bytecode);
if (pc >= jsm.birth_pc && pc < jsm.death_pc) { if (jsm.birth_pc == UINT32_MAX) {
janet_table_put(local_bindings, janet_wrap_symbol(jsm.symbol), stack[jsm.slot_index]); JanetFuncEnv *env = frame->func->envs[jsm.death_pc];
if (env->offset > 0) {
value = env->as.fiber->data[env->offset + jsm.slot_index];
} else {
value = env->as.values[jsm.slot_index];
}
} else if (pc >= jsm.birth_pc && pc < jsm.death_pc) {
value = stack[jsm.slot_index];
} }
janet_table_put(local_bindings, janet_wrap_symbol(jsm.symbol), value);
} }
janet_table_put(t, janet_ckeywordv("locals"), janet_wrap_table(local_bindings)); janet_table_put(t, janet_ckeywordv("locals"), janet_wrap_table(local_bindings));
} }