Skip to content

Commit

Permalink
chore: throttled decode
Browse files Browse the repository at this point in the history
  • Loading branch information
ErnestThePoet committed Mar 24, 2024
1 parent 17af0e5 commit 8ad4f7d
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 54 deletions.
56 changes: 35 additions & 21 deletions src/modules/vm/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ export class Vm {
return this.memory.text[this.registers.eip].lineNumber;
}

get instructions(): string[]{
get instructions(): string[] {
return this.memory.instructions;
}

Expand Down Expand Up @@ -554,6 +554,16 @@ export class Vm {
loadNewInstructions(instructions: string[]) {
this.reset();
this.memory.instructions = instructions;
}

/**
* Reset rest of the VM to initial state, load new instructions into memory and
* decode them.
* @param instructions - The new IR instructions.
* @public
*/
loadAndDecodeNewInstructions(instructions: string[]) {
this.loadNewInstructions(instructions);
this.decodeInstructions(true);
}

Expand All @@ -569,7 +579,7 @@ export class Vm {
*
* Note that runtime errors are not examined here.
* @param writeErrorItemsOnly - Write error items to `staticErrors` only,
* won't set VM execution state or write error messages.
* won't set decoded result, set VM execution state or write error messages.
* @public
*/
decodeInstructions(writeErrorItemsOnly?: boolean) {
Expand Down Expand Up @@ -619,27 +629,31 @@ export class Vm {
continue;
}

switch (decoded.type) {
case InstructionType.LABEL:
this.tables.labelTable[(<DecodedLabel>decoded.value!).id] =
{
if (!writeErrorItemsOnly) {
switch (decoded.type) {
case InstructionType.LABEL:
this.tables.labelTable[
(<DecodedLabel>decoded.value!).id
] = {
addressBefore: i32(this.memory.text.length - 1)
};
break;
case InstructionType.FUNCTION:
this.tables.functionTable[
(<DecodedFunction>decoded.value!).id
] = {
addressBefore: i32(this.memory.text.length - 1)
};
break;
default:
this.memory.text.push({
...(decoded as unknown as DecodedExecutableInstruction),
lineNumber: i + 1,
instructionLength: this.memory.instructions[i].length
});
break;
break;
case InstructionType.FUNCTION:
this.tables.functionTable[
(<DecodedFunction>decoded.value!).id
] = {
addressBefore: i32(this.memory.text.length - 1)
};
break;
default:
this.memory.text.push({
...(decoded as unknown as DecodedExecutableInstruction),
lineNumber: i + 1,
instructionLength:
this.memory.instructions[i].length
});
break;
}
}
}

Expand Down
52 changes: 38 additions & 14 deletions src/pages/Home/components/IrEditor/IrEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ interface IrEditorProps {
vm: SingleVmPageState;
}

const DECODE_INTERVAL_MS = 100;

const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
const intl = useIntl();

Expand All @@ -33,12 +35,19 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
null
);

const runtimeErrorDecorationsRef =
const runtimeErrorDecorations =
useRef<monacoEditor.editor.IEditorDecorationsCollection | null>(null);

const currentLineDecorationsRef =
const currentLineDecorations =
useRef<monacoEditor.editor.IEditorDecorationsCollection | null>(null);

const pendingDecode = useRef<{
time: number;
timeoutId: ReturnType<typeof setTimeout>;
} | null>(null);

const irLines = useRef<string[]>([]);

const dispatch = useAppDispatch();

const currentVm = vmContainer.at(props.vmIndex);
Expand Down Expand Up @@ -70,8 +79,8 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
}, [props.vm.staticErrors, intl.messages]);

useEffectDeep(() => {
if (runtimeErrorDecorationsRef.current !== null) {
runtimeErrorDecorationsRef.current.clear();
if (runtimeErrorDecorations.current !== null) {
runtimeErrorDecorations.current.clear();
}

if (
Expand All @@ -82,7 +91,7 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
editorRef.current.revealLineInCenterIfOutsideViewport(
props.vm.currentLineNumber
);
runtimeErrorDecorationsRef.current =
runtimeErrorDecorations.current =
editorRef.current.createDecorationsCollection(
props.vm.runtimeErrors.map(x => ({
range: new monacoRef.current!.Range(
Expand All @@ -108,8 +117,8 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
}, [props.vm.runtimeErrors, intl.messages]);

useEffect(() => {
if (currentLineDecorationsRef.current !== null) {
currentLineDecorationsRef.current.clear();
if (currentLineDecorations.current !== null) {
currentLineDecorations.current.clear();
}

if (
Expand All @@ -123,7 +132,7 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
editorRef.current.revealLineInCenterIfOutsideViewport(
props.vm.currentLineNumber
);
currentLineDecorationsRef.current =
currentLineDecorations.current =
editorRef.current.createDecorationsCollection([
{
range: new monacoRef.current.Range(
Expand All @@ -149,9 +158,26 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
return;
}

console.time("lni");
currentVm.loadNewInstructions(splitLines(newIr));
console.timeEnd("lni");
const nowTimeMs = new Date().getTime();
if (
pendingDecode.current === null ||
pendingDecode.current.time < nowTimeMs
) {
pendingDecode.current = {
time: nowTimeMs + DECODE_INTERVAL_MS,
timeoutId: setTimeout(() => {
currentVm.decodeInstructions(true);
syncVmState(dispatch, props.vm.id);
}, DECODE_INTERVAL_MS)
};
}

const newIrLines = splitLines(newIr);

irLines.current = newIrLines;

currentVm.loadNewInstructions(newIrLines);

dispatch(setShouldIndicateCurrentLineNumber(false));
dispatch(setConsoleInputPrompt([]));
dispatch(setConsoleInput(""));
Expand All @@ -163,9 +189,7 @@ const IrEditor: React.FC<IrEditorProps> = (props: IrEditorProps) => {
};

return (
<div
className={styles.divMonacoEditorWrapper}
>
<div className={styles.divMonacoEditorWrapper}>
<Editor
language="ir"
beforeMount={monaco => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Home/components/SideBar/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const importIr = (
vmContainer.add(newVm);

const irLines = splitLines(irString);
vmContainer.at(vmContainer.length - 1).loadNewInstructions(irLines);
vmContainer.at(vmContainer.length - 1).loadAndDecodeNewInstructions(irLines);

dispatch(
addVmPageState({
Expand Down
27 changes: 12 additions & 15 deletions src/pages/Home/components/VmConsole/VmConsole.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ const VmConsole: React.FC<VmConsoleProps> = (props: VmConsoleProps) => {

const isContinuousExecution = useRef<boolean>(false);

const currentVm = vmContainer.at(props.vmIndex);

useEffect(() => {
vmContainer.at(props.vmIndex).setReadConsoleFn(prompt => {
currentVm.setReadConsoleFn(prompt => {
dispatch(setConsoleInputPrompt(prompt));

// When we encounter a read during continuous run or
Expand Down Expand Up @@ -65,11 +67,8 @@ const VmConsole: React.FC<VmConsoleProps> = (props: VmConsoleProps) => {
<div className={styles.divVmConsoleWrapper}>
<ControlPanel
onRunClick={async () => {
if (!vmContainer.at(props.vmIndex).canContinueExecution) {
if (
vmContainer.at(props.vmIndex).state ===
VmExecutionState.WAIT_INPUT
) {
if (!currentVm.canContinueExecution) {
if (currentVm.state === VmExecutionState.WAIT_INPUT) {
inVmInput.current?.focus();
}
return;
Expand All @@ -78,24 +77,21 @@ const VmConsole: React.FC<VmConsoleProps> = (props: VmConsoleProps) => {
isContinuousExecution.current = true;

dispatch(setShouldIndicateCurrentLineNumber(false));
await vmContainer.at(props.vmIndex).execute();
await currentVm.execute();
syncVmState(dispatch, props.vm.id);
}}
onRunStepClick={async () => {
if (!vmContainer.at(props.vmIndex).canContinueExecution) {
if (
vmContainer.at(props.vmIndex).state ===
VmExecutionState.WAIT_INPUT
) {
if (!currentVm.canContinueExecution) {
if (currentVm.state === VmExecutionState.WAIT_INPUT) {
inVmInput.current?.focus();
}
return;
}

isContinuousExecution.current = false;

await vmContainer.at(props.vmIndex).executeSingleStep();
switch (vmContainer.at(props.vmIndex).state) {
await currentVm.executeSingleStep();
switch (currentVm.state) {
case VmExecutionState.FREE:
dispatch(setShouldIndicateCurrentLineNumber(true));
break;
Expand All @@ -111,7 +107,8 @@ const VmConsole: React.FC<VmConsoleProps> = (props: VmConsoleProps) => {
dispatch(setConsoleInputPrompt([]));
dispatch(setConsoleInput(""));
dispatch(setLocalVariableTablePageIndex(1));
vmContainer.at(props.vmIndex).reset();
currentVm.reset();
currentVm.decodeInstructions(true);
syncVmState(dispatch, props.vm.id);
}}
onClearClick={() => {
Expand Down
8 changes: 5 additions & 3 deletions src/pages/Home/components/VmInspector/VmInspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const VmInspector: React.FC<VmInspectorProps> = (props: VmInspectorProps) => {

const divVmInspectorWrapper = useRef<HTMLDivElement>(null);

const currentVm = vmContainer.at(props.vmIndex);

return (
<div
ref={divVmInspectorWrapper}
Expand Down Expand Up @@ -127,7 +129,7 @@ const VmInspector: React.FC<VmInspectorProps> = (props: VmInspectorProps) => {
max={vmOptionLimits.maxExecutionStepCount.max}
value={props.vm.options.maxExecutionStepCount}
onChange={e => {
vmContainer.at(props.vmIndex).configure({
currentVm.configure({
maxExecutionStepCount: e ?? undefined
});
syncVmState(dispatch, props.vm.id);
Expand All @@ -146,7 +148,7 @@ const VmInspector: React.FC<VmInspectorProps> = (props: VmInspectorProps) => {
max={vmOptionLimits.memorySize.max}
value={props.vm.options.memorySize}
onChange={e => {
vmContainer.at(props.vmIndex).configure({
currentVm.configure({
memorySize: e ?? undefined
});
syncVmState(dispatch, props.vm.id);
Expand All @@ -165,7 +167,7 @@ const VmInspector: React.FC<VmInspectorProps> = (props: VmInspectorProps) => {
max={vmOptionLimits.stackSize.max}
value={props.vm.options.stackSize}
onChange={e => {
vmContainer.at(props.vmIndex).configure({
currentVm.configure({
stackSize: e ?? undefined
});
syncVmState(dispatch, props.vm.id);
Expand Down

0 comments on commit 8ad4f7d

Please sign in to comment.