private void updateTable() {
		stackTable.setDisable(false);
		varTable.setDisable(false);

		// Compute what instruction index the caret is at.
		int insnIndex = -1;
		findIndex:
		{
			for (ASTElement astElement : astElements) {
				if (astElement instanceof ASTMethod astMethod) {
					int index = getSelectedInsnIndexOfMethod(astMethod);
					if (index >= 0) {
						insnIndex = index;
						break;
					}
				} else if (astElement instanceof ASTClass astClass) {
					for (ASTElement child : astClass.children()) {
						if (child instanceof ASTMethod astMethod) {
							int index = getSelectedInsnIndexOfMethod(astMethod);
							if (index >= 0) {
								insnIndex = index;
								break findIndex;
							}
						}
					}
				}
			}
		}

		// If we've not moved, no need to update the table.
		if (lastInsnIndex == insnIndex)
			return;
		lastInsnIndex = insnIndex;

		// Skip for invalid index.
		if (insnIndex < 0)
			return;

		// Skip of no method analysis for the current method.
		AnalysisResults analysisResults = analysisLookup.results(currentMethod.getName(), currentMethod.getDescriptor());
		if (analysisResults == null)
			return;

		// Skip if no frames.
		NavigableMap<Integer, Frame> frames = analysisResults.frames();
		if (frames.isEmpty())
			return;

		// Compute variable/stack states.
		List<JvmVariableState> varItems = new ArrayList<>();
		List<JvmStackState> stackItems = new ArrayList<>();
		var entry = frames.floorEntry(insnIndex);
		var entryKey = entry.getKey();
		Frame thisFrame = entry.getValue();
		if (thisFrame instanceof TypedFrame typedFrame) {
			// Type-only analysis is basic
			for (ClassType classType : typedFrame.getStack())
				stackItems.add(new JvmStackState(classType, Values.valueOf(classType), null));
			for (Local local : typedFrame.getLocals().values())
				varItems.add(new JvmVariableState(local.name(), local.safeType(), Values.valueOf(local.safeType()), null));
		} else if (thisFrame instanceof ValuedFrame valuedFrame) {
			// Value analysis will not only track values in a frame, but also let us see if values change across frames
			ValuedFrame lastFrame = entryKey == 0 ? null : (ValuedFrame) frames.floorEntry(entryKey - 1).getValue();

			// Fill out stack.
			Value[] lastStack = lastFrame == null ? new Value[0] : lastFrame.getStack().toArray(Value[]::new);
			Value[] stack = valuedFrame.getStack().toArray(Value[]::new);
			for (int i = 0; i < stack.length; i++) {
				Value lastValue = i <= lastStack.length - 1 ? lastStack[i] : null;
				Value value = stack[i];
				stackItems.add(new JvmStackState(Objects.requireNonNullElse(value.type(), Types.OBJECT), value, lastValue));
			}

			// And fill out the variables.
			Map<Integer, ValuedLocal> lastLocals = lastFrame == null ? Collections.emptyMap() : lastFrame.getLocals();
			Map<Integer, ValuedLocal> locals = valuedFrame.getLocals();
			for (ValuedLocal local : locals.values()) {
				ValuedLocal lastLocal = lastLocals.get(local.index());
				varItems.add(new JvmVariableState(local.name(), local.safeType(), local.value(),
						lastLocal == null ? null : lastLocal.value()));
			}
		}
		varTable.getItems().setAll(varItems);
		stackTable.getItems().setAll(stackItems);
	}
Component panel for the assembler which shows the data from stack analysis of the currently selected method.

@author Matt Coley
recaf-ui/src/main/java/software/coley/recaf/ui/pane/editing/assembler/JvmStackAnalysisPane.java