Skip to content

Add custom column and custom size #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 119 additions & 29 deletions src/view/memview/dual-view-doc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DebugSessionStatusSimple,
ICmdClientState,
ICmdGetStartAddress,
ICmdGetMaxBytes,
UnknownDocId,
EndianType,
RowFormatType,
Expand Down Expand Up @@ -50,18 +51,13 @@ export interface IDualViewDocGlobalEventArg {
type: DualViewDocGlobalEventType;
sessionStatus?: DocDebuggerStatus;
baseAddress: bigint;
maxBytes: bigint;
docId: string;
sessionId?: string;
}

export const DummyByte: IMemValue = { cur: -1, orig: -1, stale: true, inRange: false };
export class DualViewDoc {
// DO NOT CHANGE PageSize w/o adjusting getPageEventId to make sure we don't create too
// many event listeners to an address change SubPageSize so that we result in less than 10
// listeners per SubPageSize
public static readonly PageSize = 512;
public static readonly SubPageSize = 64;

public static globalEventEmitter = new events.EventEmitter();
public static currentDoc: DualViewDoc | undefined;
public static currentDocStack: string[] = [];
Expand All @@ -78,8 +74,12 @@ export class DualViewDoc {
public maxAddress = 0n;
public displayName: string;
public expr: string;
public size: string;
public endian: EndianType;
public format: RowFormatType;
public column: string;
public bytesPerRow: number;
public maxBytes = 4n * 1024n * 1024n;
public isReadonly: boolean;
public readonly docId: string;
public sessionId: string;
Expand All @@ -89,24 +89,37 @@ export class DualViewDoc {
private clientState: { [key: string]: any };
public sessionStatus: DocDebuggerStatus = DocDebuggerStatus.Default;
private startAddressStale = true;
private maxBytesStale = true;

// DO NOT CHANGE PageSize w/o adjusting getPageEventId to make sure we don't create too
// many event listeners to an address change SubPageSize so that we result in less than 10
// listeners per SubPageSize
public PageSize: number;
public SubPageSize: number;

// This part is serialized/deserialized on demand
private memory: MemPages;
public isReady = false;

constructor(info: IWebviewDocXfer) {
this.docId = info.docId;
this.setAddresses(BigInt(info.startAddress));
this.setAddresses(BigInt(info.startAddress), BigInt(info.maxBytes));
this.displayName = info.displayName;
this.expr = info.expr;
this.size = info.size;
this.endian = info.endian ?? 'little';
this.format = info.format ?? '1-byte';
this.column = info.column ?? '16';
this.bytesPerRow = this.getBytesPerCell(this.format) * Number(this.column),
this.wsFolder = info.wsFolder;
this.sessionId = info.sessionId;
this.sessionName = info.sessionName;
this.isReadonly = info.isReadOnly;
this.inWebview = DualViewDoc.InWebview();
this.startAddressStale = info.baseAddressStale;
this.maxBytesStale = info.maxBytesStale;
this.PageSize = 16 * this.bytesPerRow;
this.SubPageSize = this.PageSize / 8;
if (info.modifiedMap) {
// This map can contain values are are not actually yet in our memory
for (const [key, value] of Object.entries(info.modifiedMap)) {
Expand Down Expand Up @@ -148,20 +161,52 @@ export class DualViewDoc {
return !!myGlobals.vscode;
}

setAddresses(startAddress: bigint) {
getBytesPerCell(format : RowFormatType): 1 | 2 | 4 | 8 {
switch (format) {
case '1-byte': {
return 1;
break;
}
case '2-byte': {
return 2;
break;
}
case '4-byte': {
return 4;
break;
}
case '8-byte': {
return 8;
break;
}
default: {
console.error('Invalid format');
return 1;
break;
}
}
}

setAddresses(startAddress: bigint, maxBytes: bigint) {
this.startAddress = startAddress;
this.baseAddress = (this.startAddress / 16n) * 16n;
this.maxAddress = this.baseAddress + BigInt(1024 * 1024);
this.maxBytes = maxBytes;
this.baseAddress = this.startAddress;
this.maxAddress = this.baseAddress + this.maxBytes;
}

updateSettings(settings: IModifiableProps) {
if (this.expr !== settings.expr) {
if ((this.expr !== settings.expr) || (this.size !== settings.size)) {
this.expr = settings.expr;
this.size = settings.size;
this.markAsStale();
}
this.displayName = settings.displayName;
this.endian = settings.endian;
this.format = settings.format;
this.column = settings.column;
this.bytesPerRow = this.getBytesPerCell(this.format) * Number(this.column);
this.PageSize = 16 * this.bytesPerRow;
this.SubPageSize = this.PageSize / 8;
// Now everything is out of sync. Requires a total re-render it is the callers responsibility to do that
}

Expand Down Expand Up @@ -206,7 +251,7 @@ export class DualViewDoc {
const str = await DualViewDoc.memoryIF.getStartAddress(arg);
const newVal = BigInt(str);
if (newVal != this.startAddress) {
this.setAddresses(newVal);
this.setAddresses(newVal, this.maxBytes);
this.memory.markAllStale();
this.emitGlobalEvent(DualViewDocGlobalEventType.BaseAddress);
}
Expand All @@ -215,6 +260,33 @@ export class DualViewDoc {
return Promise.resolve(this.startAddress);
}

async getMaxBytes(): Promise<bigint> {
if (!this.maxBytesStale) {
return Promise.resolve(this.maxBytes);
}
if (this.sessionStatus !== DocDebuggerStatus.Stopped) {
return Promise.resolve(this.maxBytes);
}
const arg: ICmdGetMaxBytes = {
expr: this.size,
def: this.maxBytes.toString(),
type: CmdType.GetMaxBytes,
sessionId: this.sessionId,
docId: this.docId
};
try {
const str = await DualViewDoc.memoryIF.getMaxBytes(arg);
const newVal = BigInt(str);
if (newVal != this.maxBytes) {
this.setAddresses(this.startAddress, newVal);
this.memory.markAllStale();
this.emitGlobalEvent(DualViewDocGlobalEventType.BaseAddress);
}
} catch {}
this.maxBytesStale = false;
return Promise.resolve(this.maxBytes);
}

async getMemoryPage(addr: bigint, nBytes: number): Promise<Uint8Array> {
let ary = !this.inWebview && !this.isReady ? this.memory.getPage(addr) : this.memory.getPageIfFresh(addr);
if (ary) {
Expand Down Expand Up @@ -291,6 +363,7 @@ export class DualViewDoc {

public markAsStale() {
this.startAddressStale = true;
this.maxBytesStale = true;
this.memory.markAllStale();
}

Expand Down Expand Up @@ -321,6 +394,9 @@ export class DualViewDoc {
if (this.startAddressStale) {
await this.getStartAddress();
}
if (this.maxBytesStale) {
await this.getMaxBytes();
}
const ret = await DualViewDoc.memoryIF.getMemory(msg);
resolve(ret);
} catch (e) {
Expand Down Expand Up @@ -367,8 +443,9 @@ export class DualViewDoc {

static getRowUnsafe(addr: bigint): IMemValue[] {
const doc = DualViewDoc.currentDoc;
const bytesPerRow = doc?.bytesPerRow || 16;
if (doc && doc.addrInRange(addr)) {
const origRow = doc.memory.getRowSync(addr);
const origRow = doc.memory.getRowSync(addr, BigInt(bytesPerRow));
const isStale = doc.memory.isStale(addr);
const ret: IMemValue[] = [];
for (const orig of origRow) {
Expand All @@ -387,7 +464,7 @@ export class DualViewDoc {
return ret;
} else {
const ret: IMemValue[] = [];
for (let ix = 0; ix < 16; ix++) {
for (let ix = 0; ix < bytesPerRow; ix++) {
ret.push(DummyByte);
}
return ret;
Expand Down Expand Up @@ -497,7 +574,8 @@ export class DualViewDoc {
docId: this.docId,
sessionId: this.sessionId,
sessionStatus: this.sessionStatus,
baseAddress: this.baseAddress
baseAddress: this.baseAddress,
maxBytes: this.maxBytes
};
this.pendingArg = arg;
this.statusChangeTimeout = setTimeout(() => {
Expand All @@ -520,6 +598,7 @@ export class DualViewDoc {
sessionStatus: doc.sessionStatus,
baseAddress: doc.baseAddress,
startAddress: doc.startAddress,
maxBytes: doc.maxBytes,
isModified: doc.isModified(),
isCurrent: doc === DualViewDoc.currentDoc
};
Expand All @@ -545,13 +624,16 @@ export class DualViewDoc {
expr: this.expr,
endian: this.endian,
format: this.format,
column: this.column,
size: this.size,
wsFolder: this.wsFolder,
startAddress: this.startAddress.toString(),
maxBytes: Number(this.maxAddress - this.startAddress),
maxBytes: this.maxBytes.toString(),
isCurrentDoc: this === DualViewDoc.currentDoc,
modifiedMap: newMap,
clientState: this.clientState,
baseAddressStale: this.startAddressStale,
maxBytesStale: this.maxBytesStale,
isReadOnly: this.isReadonly
};
if (includeMemories) {
Expand Down Expand Up @@ -608,10 +690,13 @@ export class DualViewDoc {
startAddress: '0',
endian: 'little',
format: '1-byte',
maxBytes: initString.length,
column: '16',
size: '4 * 1024 * 1024',
maxBytes: initString.length.toString(),
isCurrentDoc: true,
clientState: {},
baseAddressStale: true,
maxBytesStale: true,
isReadOnly: true
};
const doc = new DualViewDoc(tmp);
Expand Down Expand Up @@ -641,6 +726,10 @@ class MemPages {
return this.parentDoc.baseAddress;
}

get maxAddress(): bigint {
return this.parentDoc.maxAddress;
}

public numPages(): number {
return this.pages.length;
}
Expand All @@ -655,7 +744,7 @@ class MemPages {

private getSlot(addr: bigint): number {
const offset = addr - this.baseAddress;
const slot = Math.floor(Number(offset) / DualViewDoc.PageSize);
const slot = Math.floor(Number(offset) / (DualViewDoc.currentDoc?.PageSize || 512));
return slot;
}

Expand All @@ -666,7 +755,7 @@ class MemPages {
if (page.stale) {
promises.push(this.getValue(addr));
}
addr += BigInt(DualViewDoc.PageSize);
addr += BigInt(DualViewDoc.currentDoc?.PageSize || 512);
}
return Promise.all(promises);
}
Expand All @@ -685,7 +774,7 @@ class MemPages {

public getPageEventId(addr: bigint): string {
const slot = this.getSlot(addr);
const subSlot = Math.floor(Number(addr - this.baseAddress) / DualViewDoc.SubPageSize);
const subSlot = Math.floor(Number(addr - this.baseAddress) / (DualViewDoc.currentDoc?.SubPageSize || 64));
const ret = `address-${slot}-${subSlot}`;
return ret;
}
Expand Down Expand Up @@ -726,22 +815,22 @@ class MemPages {
public getValueSync(addr: bigint): number {
const slot = this.getSlot(addr);
const page: IMemPage | undefined = slot < this.pages.length ? this.pages[slot] : undefined;
const pageAddr = this.baseAddress + BigInt(slot * DualViewDoc.PageSize);
const pageAddr = this.baseAddress + BigInt(slot * (DualViewDoc.currentDoc?.PageSize || 512));
const offset = Number(addr - pageAddr);
const buf = page ? page.current : undefined;
return buf && offset < buf.length ? buf[offset] : -1;
}

public getRowSync(addr: bigint): IByteVal[] {
addr = (addr / 16n) * 16n;
public getRowSync(addr: bigint, bytesPerRow: bigint): IByteVal[] {
addr = this.baseAddress + (((addr - this.baseAddress) / bytesPerRow) * bytesPerRow);
const slot = this.getSlot(addr);
const page: IMemPage | undefined = slot < this.pages.length ? this.pages[slot] : undefined;
const pageAddr = this.baseAddress + BigInt(slot * DualViewDoc.PageSize);
const pageAddr = this.baseAddress + BigInt(slot * (DualViewDoc.currentDoc?.PageSize || 512));
let offset = Number(addr - pageAddr);
const buf = page?.current;
const pBuf = page?.previous;
const ret: IByteVal[] = [];
for (let ix = 0; ix < 16; ix++, offset++) {
for (let ix = 0; ix < bytesPerRow; ix++, offset++) {
const current = buf && offset < buf.length ? buf[offset] : -1;
const previous = pBuf && offset < pBuf.length ? pBuf[offset] : current;
ret.push({ current: current, previous: previous });
Expand All @@ -753,7 +842,7 @@ class MemPages {
public getValue(addr: bigint): IByteVal | Promise<IByteVal> {
const slot = this.getSlot(addr);
let page: IMemPage | undefined = slot < this.pages.length ? this.pages[slot] : undefined;
const pageAddr = this.baseAddress + BigInt(slot * DualViewDoc.PageSize);
const pageAddr = this.baseAddress + BigInt(slot * (DualViewDoc.currentDoc?.PageSize || 512));
const get = (): IByteVal => {
const offset = Number(addr - pageAddr);
const buf = page ? page.current : undefined;
Expand All @@ -775,8 +864,9 @@ class MemPages {
if (!page || page.stale || !page.current.length) {
this.growPages(slot);
return new Promise((resolve) => {
// Prevent load more than the input size
this.parentDoc
.getMemoryPageFromSource(pageAddr, DualViewDoc.PageSize)
.getMemoryPageFromSource(pageAddr, Math.min((DualViewDoc.currentDoc?.PageSize || 512), Number(this.maxAddress - addr)))
.then((buf) => {
page = this.pages[slot];
if (page.stale) {
Expand Down Expand Up @@ -806,12 +896,12 @@ class MemPages {

setValue(addr: bigint, val: number /* byte actually */, useThrow = false): void {
const slot = this.getSlot(addr);
const pageAddr = this.baseAddress + BigInt(slot * DualViewDoc.PageSize);
const pageAddr = this.baseAddress + BigInt(slot * (DualViewDoc.currentDoc?.PageSize || 512));
const page: IMemPage | undefined = slot < this.pages.length ? this.pages[slot] : undefined;
const offset = Number(addr - pageAddr);
if (!page || offset < 0 || offset >= page.current.length) {
if (useThrow) {
const maxAddr = this.baseAddress + BigInt(this.pages.length * DualViewDoc.PageSize);
const maxAddr = this.baseAddress + BigInt(this.pages.length * (DualViewDoc.currentDoc?.PageSize || 512));
throw new Error(
`Requested address ${addr}. base address = ${this.baseAddress}, max address = ${maxAddr}`
);
Expand Down
Loading