Skip to content

Commit

Permalink
[trace-debug] Added support for global locations
Browse files Browse the repository at this point in the history
  • Loading branch information
awelc committed Jan 8, 2025
1 parent 80955a5 commit 0778785
Show file tree
Hide file tree
Showing 28 changed files with 2,009 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
Runtime,
RuntimeEvents,
RuntimeValueType,
IRuntimeVariableLoc,
IRuntimeGlobalLoc,
IRuntimeVariableScope,
CompoundType,
IRuntimeRefValue,
Expand Down Expand Up @@ -296,32 +298,48 @@ export class MoveDebugSession extends LoggingDebugSession {
name: string,
type?: string
): DebugProtocol.Variable {
const frameID = value.loc.frameID;
const localIndex = value.loc.localIndex;
const indexedLoc = value.indexedLoc;
const runtimeStack = this.runtime.stack();
const frame = runtimeStack.frames.find(frame => frame.id === frameID);
if (!frame) {
throw new Error('No frame found for id '
+ frameID
+ ' when converting ref value for local index '
+ localIndex);
}
// a local will be in one of the scopes at a position corresponding to its local index
let local = undefined;
for (const scope of frame.locals) {
local = scope[localIndex];
if (local) {
break;
if ('globalIndex' in indexedLoc.loc) {
// global location
const globalValue = runtimeStack.globals.get(indexedLoc.loc.globalIndex);
if (!globalValue) {
throw new Error('No global found for index '
+ indexedLoc.loc.globalIndex
+ ' when converting ref value ');
}
const indexPath = [...indexedLoc.indexPath];
return this.convertRuntimeValue(globalValue, name, indexPath, type);
} else if ('frameID' in indexedLoc.loc && 'localIndex' in indexedLoc.loc) {
// local variable
const frameID = indexedLoc.loc.frameID;
const localIndex = indexedLoc.loc.localIndex;
const frame = runtimeStack.frames.find(frame => frame.id === frameID);
if (!frame) {
throw new Error('No frame found for id '
+ frameID
+ ' when converting ref value for local index '
+ localIndex);
}
// a local will be in one of the scopes at a position corresponding to its local index
let local = undefined;
for (const scope of frame.locals) {
local = scope[localIndex];
if (local) {
break;
}
}
if (!local) {
throw new Error('No local found for index '
+ localIndex
+ ' when converting ref value for frame id '
+ frameID);
}
const indexPath = [...indexedLoc.indexPath];
return this.convertRuntimeValue(local.value, name, indexPath, type);
} else {
throw new Error('Invalid runtime location');
}
if (!local) {
throw new Error('No local found for index '
+ localIndex
+ ' when converting ref value for frame id '
+ frameID);
}
const indexPath = [...value.loc.indexPath];
return this.convertRuntimeValue(local.value, name, indexPath, type);
}

/**
Expand Down
122 changes: 88 additions & 34 deletions external-crates/move/crates/move-analyzer/trace-adapter/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ export type RuntimeValueType = string | CompoundType | IRuntimeRefValue;
export interface IRuntimeVariableLoc {
frameID: number;
localIndex: number;
}

/**
* Global location (typically used for values
* computed in native functions)
*/
export interface IRuntimeGlobalLoc {
globalIndex: number;
}

/**
* Location where a runtime value is stored.
*/
export interface IRuntimeLoc {
loc: IRuntimeVariableLoc | IRuntimeGlobalLoc;
indexPath: number[];
}

Expand All @@ -51,7 +66,7 @@ export interface IRuntimeVariableLoc {
*/
export interface IRuntimeRefValue {
mutable: boolean;
loc: IRuntimeVariableLoc
indexedLoc: IRuntimeLoc;
}

/**
Expand Down Expand Up @@ -128,6 +143,7 @@ interface IRuntimeStackFrame {
*/
export interface IRuntimeStack {
frames: IRuntimeStackFrame[];
globals: Map<number, RuntimeValueType>;
}

/**
Expand Down Expand Up @@ -185,7 +201,10 @@ export class Runtime extends EventEmitter {
/**
* Current frame stack.
*/
private frameStack = { frames: [] as IRuntimeStackFrame[] };
private frameStack = {
frames: [] as IRuntimeStackFrame[],
globals: new Map<number, RuntimeValueType>()
};

/**
* Map of file hashes to file info.
Expand Down Expand Up @@ -257,7 +276,8 @@ export class Runtime extends EventEmitter {
currentEvent.optimizedLines
);
this.frameStack = {
frames: [newFrame]
frames: [newFrame],
globals: new Map<number, RuntimeValueType>()
};
this.step(/* next */ false, /* stopAtCloseFrame */ false);
}
Expand Down Expand Up @@ -409,11 +429,19 @@ export class Runtime extends EventEmitter {
return ExecutionResult.Exception;
}
}
// if native function executed successfully, then the next event
// should be CloseFrame
if (this.trace.events.length <= this.eventIndex + 1 ||
this.trace.events[this.eventIndex + 1].type !== TraceEventKind.CloseFrame) {
throw new Error('Expected an CloseFrame event after native OpenFrame event');
// process optional effects until reaching CloseFrame for the native function
while (true) {
const executionResult = this.step(/* next */ false, /* stopAtCloseFrame */ true);
if (executionResult === ExecutionResult.Exception) {
return executionResult;
}
if (executionResult === ExecutionResult.TraceEnd) {
throw new Error('Cannot find CloseFrame event for native function');
}
const currentEvent = this.trace.events[this.eventIndex];
if (currentEvent.type === TraceEventKind.CloseFrame) {
break;
}
}
// skip over CloseFrame as there is no frame to pop
this.eventIndex++;
Expand Down Expand Up @@ -449,10 +477,19 @@ export class Runtime extends EventEmitter {
return ExecutionResult.Ok;
} else {
// pop the top frame from the stack
if (this.frameStack.frames.length <= 0) {
const framesLength = this.frameStack.frames.length;
if (framesLength <= 0) {
throw new Error('No frame to pop at CloseFrame event with ID: '
+ currentEvent.id);
}
const currentFrameID = this.frameStack.frames[framesLength - 1].id;
if (currentFrameID !== currentEvent.id) {
throw new Error('Frame ID mismatch at CloseFrame event with ID: '
+ currentEvent.id
+ ' (current frame ID: '
+ currentFrameID
+ ')');
}
this.frameStack.frames.pop();
return this.step(next, stopAtCloseFrame);
}
Expand All @@ -463,18 +500,23 @@ export class Runtime extends EventEmitter {
return ExecutionResult.Exception;
}
if (effect.type === TraceEffectKind.Write) {
const traceLocation = effect.loc;
const traceValue = effect.value;
const frame = this.frameStack.frames.find(
frame => frame.id === traceLocation.frameID
);
if (!frame) {
throw new Error('Cannot find frame with ID: '
+ traceLocation.frameID
+ ' when processing Write effect for local variable at index: '
+ traceLocation.localIndex);
const traceLocation = effect.indexedLoc.loc;
if ('globalIndex' in traceLocation) {
const globalValue = effect.value;
this.frameStack.globals.set(traceLocation.globalIndex, globalValue);
} else if ('frameID' in traceLocation && 'localIndex' in traceLocation) {
const traceValue = effect.value;
const frame = this.frameStack.frames.find(
frame => frame.id === traceLocation.frameID
);
if (!frame) {
throw new Error('Cannot find frame with ID: '
+ traceLocation.frameID
+ ' when processing Write effect for local variable at index: '
+ traceLocation.localIndex);
}
localWrite(frame, traceLocation.localIndex, traceValue);
}
localWrite(frame, traceLocation.localIndex, traceValue);
}
return this.step(next, stopAtCloseFrame);
} else {
Expand Down Expand Up @@ -825,23 +867,35 @@ export class Runtime extends EventEmitter {
name: string,
type?: string
): string {
const indexedLoc = refValue.indexedLoc;
let res = '';
const frame = this.frameStack.frames.find(frame => frame.id === refValue.loc.frameID);
let local = undefined;
if (!frame) {
return res;
}
for (const scope of frame.locals) {
local = scope[refValue.loc.localIndex];
if (local) {
break;
if ('globalIndex' in indexedLoc.loc) {
// global location
const globalValue = this.frameStack.globals.get(indexedLoc.loc.globalIndex);
if (globalValue) {
const indexPath = [...indexedLoc.indexPath];
return this.valueToString(tabs, globalValue, name, indexPath, type);
}
} else if ('frameID' in indexedLoc.loc && 'localIndex' in indexedLoc.loc) {
const frameID = indexedLoc.loc.frameID;
const frame = this.frameStack.frames.find(frame => frame.id === frameID);
let local = undefined;
if (!frame) {
return res;
}
for (const scope of frame.locals) {
local = scope[indexedLoc.loc.localIndex];
if (local) {
break;
}
}
if (!local) {
return res;
}
const indexPath = [...indexedLoc.indexPath];
return this.valueToString(tabs, local.value, name, indexPath, type);
}
if (!local) {
return res;
}
const indexPath = [...refValue.loc.indexPath];
return this.valueToString(tabs, local.value, name, indexPath, type);
return res;
}

/**
Expand Down
Loading

0 comments on commit 0778785

Please sign in to comment.