Skip to content

Commit

Permalink
Allow display of local variables in frames multiple levels deep.
Browse files Browse the repository at this point in the history
Remove the arbitrary separation between the variable references used
to represent scopes and those used to represent variable objects.
This implementation uses a common pool of handles to support both
variable object references as well as scope references, thus
eliminating the previous bounded numerical range used for scopes,
which was not large enough to represent stack frames multiple levels
deep, due to thread and level information being encoded in the scope
variable reference value.
  • Loading branch information
brownts committed Apr 22, 2022
1 parent 15c8714 commit 4c95251
Showing 1 changed file with 36 additions and 17 deletions.
53 changes: 36 additions & 17 deletions src/mibase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,21 @@ class ExtendedVariable {
}
}

export enum RunCommand { CONTINUE, RUN, NONE }
class VariableScope {
constructor (public readonly name: string, public readonly threadId: number, public readonly level: number) {
}

public static variableName (handle: number, name: string): string {
return `var_${handle}_${name}`;
}
}

const STACK_HANDLES_START = 1000;
const VAR_HANDLES_START = 512 * 256 + 1000;
export enum RunCommand { CONTINUE, RUN, NONE }

export class MI2DebugSession extends DebugSession {
protected variableHandles = new Handles<string | VariableObject | ExtendedVariable>(VAR_HANDLES_START);
protected variableHandles = new Handles<VariableScope | string | VariableObject | ExtendedVariable>();
protected variableHandlesReverse: { [id: string]: number } = {};
protected scopeHandlesReverse: { [key: string]: number } = {};
protected useVarObjects: boolean;
protected quit: boolean;
protected attached: boolean;
Expand Down Expand Up @@ -176,8 +183,10 @@ export class MI2DebugSession extends DebugSession {
try {
if (this.useVarObjects) {
let name = args.name;
if (args.variablesReference >= VAR_HANDLES_START) {
const parent = this.variableHandles.get(args.variablesReference) as VariableObject;
const parent = this.variableHandles.get(args.variablesReference);
if (parent instanceof VariableScope) {
name = VariableScope.variableName(args.variablesReference, name);
} else if (parent instanceof VariableObject) {
name = `${parent.name}.${name}`;
}

Expand Down Expand Up @@ -396,7 +405,23 @@ export class MI2DebugSession extends DebugSession {

protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
const scopes = new Array<Scope>();
scopes.push(new Scope("Local", STACK_HANDLES_START + (parseInt(args.frameId as any) || 0), false));
const [threadId, level] = this.frameIdToThreadAndLevel(args.frameId);

const createScope = (scopeName: string, expensive: boolean): Scope => {
const key: string = scopeName + ":" + threadId + ":" + level;
let handle: number;

if (this.scopeHandlesReverse.hasOwnProperty(key)) {
handle = this.scopeHandlesReverse[key];
} else {
handle = this.variableHandles.create(new VariableScope(scopeName, threadId, level));
this.scopeHandlesReverse[key] = handle;
}

return new Scope(scopeName, handle, expensive);
}

scopes.push(createScope("Local", false));

response.body = {
scopes: scopes
Expand All @@ -406,12 +431,7 @@ export class MI2DebugSession extends DebugSession {

protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise<void> {
const variables: DebugProtocol.Variable[] = [];
let id: number | string | VariableObject | ExtendedVariable;
if (args.variablesReference < VAR_HANDLES_START) {
id = args.variablesReference - STACK_HANDLES_START;
} else {
id = this.variableHandles.get(args.variablesReference);
}
const id: VariableScope | string | VariableObject | ExtendedVariable = this.variableHandles.get(args.variablesReference);

const createVariable = (arg, options?) => {
if (options)
Expand All @@ -431,15 +451,14 @@ export class MI2DebugSession extends DebugSession {
return varObj.isCompound() ? id : 0;
};

if (typeof id == "number") {
if (id instanceof VariableScope) {
let stack: Variable[];
try {
const [threadId, level] = this.frameIdToThreadAndLevel(id);
stack = await this.miDebugger.getStackVariables(threadId, level);
stack = await this.miDebugger.getStackVariables(id.threadId, id.level);
for (const variable of stack) {
if (this.useVarObjects) {
try {
const varObjName = `var_${id}_${variable.name}`;
const varObjName = VariableScope.variableName(args.variablesReference, variable.name);
let varObj: VariableObject;
try {
const changes = await this.miDebugger.varUpdate(varObjName);
Expand Down

0 comments on commit 4c95251

Please sign in to comment.