mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +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:
		| @@ -2767,12 +2767,6 @@ | ||||
|   (put nextenv :debug-level level) | ||||
|   (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) | ||||
|   (defn debugger-chunks [buf p] | ||||
|     (def status (:state p :delimiters)) | ||||
| @@ -3381,11 +3375,16 @@ | ||||
|   (print)) | ||||
|  | ||||
| (defn .frame | ||||
|   "Show a stack frame." | ||||
|   "Show a stack frame" | ||||
|   [&opt n] | ||||
|   (def stack (debug/stack (.fiber))) | ||||
|   (in stack (or n 0))) | ||||
|  | ||||
| (defn .locals | ||||
|   "Show local bindings" | ||||
|   [&opt n] | ||||
|   (get (.frame n) :locals)) | ||||
|  | ||||
| (defn .fn | ||||
|   "Get the current function." | ||||
|   [&opt n] | ||||
|   | ||||
| @@ -928,10 +928,15 @@ static Janet janet_disasm_symbolslots(JanetFuncDef *def) { | ||||
|         return janet_wrap_nil(); | ||||
|     } | ||||
|     JanetArray *symbolslots = janet_array(def->symbolmap_length); | ||||
|     Janet upvaluekw = janet_ckeywordv("upvalue"); | ||||
|     for (int32_t i = 0; i < def->symbolmap_length; i++) { | ||||
|         JanetSymbolMap ss = def->symbolmap[i]; | ||||
|         Janet *t = janet_tuple_begin(4); | ||||
|         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[2] = janet_wrap_integer(ss.slot_index); | ||||
|         t[3] = janet_wrap_symbol(ss.symbol); | ||||
|   | ||||
| @@ -344,6 +344,7 @@ found: | ||||
|     } | ||||
|  | ||||
|     /* non-local scope needs to expose its environment */ | ||||
|     JanetScope *original_scope = scope; | ||||
|     pair->keep = 1; | ||||
|     while (scope && !(scope->flags & JANET_SCOPE_FUNCTION)) | ||||
|         scope = scope->parent; | ||||
| @@ -365,7 +366,7 @@ found: | ||||
|             /* Check if scope already has env. If so, break */ | ||||
|             len = janet_v_count(scope->envs); | ||||
|             for (j = 0; j < len; j++) { | ||||
|                 if (scope->envs[j] == envindex) { | ||||
|                 if (scope->envs[j].envindex == envindex) { | ||||
|                     scopefound = 1; | ||||
|                     envindex = j; | ||||
|                     break; | ||||
| @@ -374,7 +375,10 @@ found: | ||||
|             /* Add the environment if it is not already referenced */ | ||||
|             if (!scopefound) { | ||||
|                 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; | ||||
|             } | ||||
|         } | ||||
| @@ -878,7 +882,10 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) { | ||||
|  | ||||
|     /* Copy 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 = janet_v_flatten(scope->consts); | ||||
| @@ -935,6 +942,30 @@ JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) { | ||||
|  | ||||
|     /* Capture symbol to local mapping */ | ||||
|     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++) { | ||||
|         SymPair pair = scope->syms[i]; | ||||
|         if (pair.sym2) { | ||||
|   | ||||
| @@ -117,6 +117,11 @@ typedef struct SymPair { | ||||
|     uint32_t death_pc; | ||||
| } SymPair; | ||||
|  | ||||
| typedef struct JanetEnvRef { | ||||
|     int32_t envindex; | ||||
|     JanetScope *scope; | ||||
| } JanetEnvRef; | ||||
|  | ||||
| /* A lexical scope during compilation */ | ||||
| struct JanetScope { | ||||
|  | ||||
| @@ -145,7 +150,7 @@ struct JanetScope { | ||||
|     /* Referenced closure environments. The values at each index correspond | ||||
|      * 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. */ | ||||
|     int32_t *envs; | ||||
|     JanetEnvRef *envs; | ||||
|  | ||||
|     int32_t bytecode_start; | ||||
|     int flags; | ||||
|   | ||||
| @@ -334,10 +334,19 @@ static Janet doframe(JanetStackFrame *frame) { | ||||
|             JanetTable *local_bindings = janet_table(0); | ||||
|             for (int32_t i = def->symbolmap_length - 1; i >= 0; i--) { | ||||
|                 JanetSymbolMap jsm = def->symbolmap[i]; | ||||
|                 Janet value = janet_wrap_nil(); | ||||
|                 uint32_t pc = (uint32_t)(frame->pc - def->bytecode); | ||||
|                 if (pc >= jsm.birth_pc && pc < jsm.death_pc) { | ||||
|                     janet_table_put(local_bindings, janet_wrap_symbol(jsm.symbol), stack[jsm.slot_index]); | ||||
|                 if (jsm.birth_pc == UINT32_MAX) { | ||||
|                     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)); | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose