Skip to content

Commit

Permalink
Adds an opcode count stat to the disassembler
Browse files Browse the repository at this point in the history
  • Loading branch information
ike709 committed Dec 12, 2024
1 parent 82693c1 commit 1ed2925
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
34 changes: 20 additions & 14 deletions DMDisassembler/DMProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace DMDisassembler;

internal class DMProc(ProcDefinitionJson json) {
private class DecompiledOpcode(int position, string text) {
internal struct DecompiledOpcode(int position, string text) {
public readonly int Position = position;
public readonly string Text = text;
}
Expand All @@ -21,19 +21,7 @@ private class DecompiledOpcode(int position, string text) {
public Exception exception;

public string Decompile() {
List<DecompiledOpcode> decompiled = new();
HashSet<int> labeledPositions = new();

try {
foreach (var (position, instruction) in new ProcDecoder(Program.CompiledJson.Strings, Bytecode).Disassemble()) {
decompiled.Add(new DecompiledOpcode(position, ProcDecoder.Format(instruction, type => Program.CompiledJson.Types[type].Path)));
if (ProcDecoder.GetJumpDestination(instruction) is int jumpPosition) {
labeledPositions.Add(jumpPosition);
}
}
} catch (Exception ex) {
exception = ex;
}
List<DecompiledOpcode> decompiled = GetDecompiledOpcodes(out var labeledPositions);

StringBuilder result = new StringBuilder();
foreach (DecompiledOpcode decompiledOpcode in decompiled) {
Expand All @@ -59,6 +47,24 @@ public string Decompile() {
return result.ToString();
}

public List<DecompiledOpcode> GetDecompiledOpcodes(out HashSet<int> labeledPositions) {
List<DecompiledOpcode> decompiled = new();
labeledPositions = new();

try {
foreach (var (position, instruction) in new ProcDecoder(Program.CompiledJson.Strings, Bytecode).Disassemble()) {
decompiled.Add(new DecompiledOpcode(position, ProcDecoder.Format(instruction, type => Program.CompiledJson.Types[type].Path)));
if (ProcDecoder.GetJumpDestination(instruction) is int jumpPosition) {
labeledPositions.Add(jumpPosition);
}
}
} catch (Exception ex) {
exception = ex;
}

return decompiled;
}

[CanBeNull]
public string[] GetArguments() {
if (json.Arguments is null || json.Arguments.Count == 0) return null;
Expand Down
34 changes: 31 additions & 3 deletions DMDisassembler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using System.Text.Json;
using DMCompiler.Bytecode;
using DMCompiler.Json;
using JetBrains.Annotations;

Expand Down Expand Up @@ -118,6 +119,7 @@ private static void PrintHelp([CanBeNull] string command) {
Console.WriteLine("Prints various statistics. Usage: stats [type]");
Console.WriteLine("Options for [type]:");
Console.WriteLine("procs-by-type : Prints the number of proc declarations (not overrides) on each type in descending order");
Console.WriteLine("opcode-count : Prints the number of occurrences for each opcode in descending order");
break;
}
default: {
Expand Down Expand Up @@ -153,6 +155,10 @@ private static void Stats([CanBeNull] string statType) {
ProcsByType();
return;
}
case "opcode-count": {
OpcodeCount();
return;
}
default: {
Console.WriteLine($"Unknown stat \"{statType}\"");
PrintHelp("stats");
Expand All @@ -174,15 +180,37 @@ void ProcsByType() {

Console.WriteLine("Type: Proc Declarations");
foreach (var pair in typeIdToProcCount.OrderByDescending(kvp => kvp.Value)) {

var type = TypesById[pair.Key];
if (pair.Key == 0) {
Console.WriteLine($"<global>: {pair.Value}");
Console.WriteLine($"<global>: {pair.Value:n0}");
} else {
Console.WriteLine($"{type.Path}: {pair.Value}");
Console.WriteLine($"{type.Path}: {pair.Value:n0}");
}
}
}

void OpcodeCount() {
Console.WriteLine("Counting all opcode occurrences. This may take a moment.");
Dictionary<string, int> opcodeToCount = new Dictionary<string, int>();

// We need to fill the dict first in case there's any opcodes with 0 occurrences in the bytecode
foreach (string opcodeName in Enum.GetNames(typeof(DreamProcOpcode))) {
opcodeToCount.Add(opcodeName, 0);
}

foreach (DMProc proc in Procs) {
var decompiledOpcodes = proc.GetDecompiledOpcodes(out _);
foreach (var opcode in decompiledOpcodes) {
var name = opcode.Text.Split(' ')[0];
opcodeToCount[name] += 1;
}
}

Console.WriteLine("Opcode: Count");
foreach (var pair in opcodeToCount.OrderByDescending(kvp => kvp.Value)) {
Console.WriteLine($"{pair.Key}: {pair.Value:n0}");
}
}
}

private static void Search(string[] args) {
Expand Down

0 comments on commit 1ed2925

Please sign in to comment.