I was trying to process some text files approximately simulating a deterministic finite state automaton. This worked well but the performance was absolutely horrible.
I started investigating and found that the "code size" has a weird and very large effect on the performance. I created a dummy program to illustrate the effect. The following is acceptably fast on my computer (~0.250s):
package com.foo.bar;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
public class DummyFileProcessor {
    public static void main(String[] args) throws IOException {
        // `args[0]` is the path to the "citylots.json" file from here:
        // https://github.com/zemirco/sf-city-lots-json (181 MB).
        
        final long startTime = System.currentTimeMillis();
        
        final short stateAlwaysZero = 0; // always 0 in this demo
        
        try (Reader reader = Files.newBufferedReader(Paths.get(args[0]))) {
            final char[] chunk = new char[4096];
            
            for (int chunkLength = reader.read(chunk); chunkLength != -1; chunkLength = reader.read(chunk)) {
                for (int i = 0; i < chunkLength; ++i) {
                    final short triggerAlwaysZero = 0; // always 0 in this demo
                    
                    switch (stateAlwaysZero) {
                    case 0: {
                        switch (triggerAlwaysZero) {
                        case 0: { break; }
                        case 1: { break; }
                        case 2: { break; }
                        case 3: { break; }
                        case 4: { break; }
                        case 5: { break; }
                        case 6: { break; }
                        case 7: { break; }
                        case 8: { break; }
                        case 9: { break; }
                        case 10: { break; }
                        case 11: { break; }
                        case 12: { break; }
                        case 13: { break; }
                        case 14: { break; }
                        case 15: { break; }
                        case 16: { break; }
                        case 17: { break; }
                        case 18: { break; }
                        case 19: { break; }
                        case 20: { break; }
                        case 21: { break; }
                        case 22: { break; }
                        case 23: { break; }
                        case 24: { break; }
                        case 25: { break; }
                        case 26: { break; }
                        case 27: { break; }
                        case 28: { break; }
                        case 29: { break; }
                        }
                        break;
                    }
                    case 1: { break; }
                    case 2: { break; }
                    case 3: { break; }
                    case 4: { break; }
                    case 5: { break; }
                    case 6: { break; }
                    case 7: { break; }
                    case 8: { break; }
                    case 9: { break; }
                    case 10: { break; }
                    case 11: { break; }
                    case 12: { break; }
                    case 13: { break; }
                    case 14: { break; }
                    case 15: { break; }
                    case 16: { break; }
                    case 17: { break; }
                    case 18: { break; }
                    case 19: { break; }
                    case 20: { break; }
                    case 21: { break; }
                    case 22: { break; }
                    case 23: { break; }
                    case 24: { break; }
                    case 25: { break; }
                    case 26: { break; }
                    case 27: { break; }
                    case 28: { break; }
                    case 29: { break; }
                    case 30: { break; }
                    case 31: { break; }
                    case 32: { break; }
                    case 33: { break; }
                    case 34: { break; }
                    case 35: { break; }
                    case 36: { break; }
                    case 37: { break; }
                    case 38: { break; }
                    case 39: { break; }
                    }
                }
            }
        }
        
        final long endTime = System.currentTimeMillis();
        System.out.println("done after " + (((double) (endTime - startTime)) / 1000) + "s");
    }
}
Now I just copy the switch (triggerAlwaysZero) { ... } part into the other cases (1, 2, ...) of switch (stateAlwaysZero) (these cases are never chosen). This makes the code large but it does not have a big impact when done only to the cases 0 to 33. But when I also paste this switch (triggerAlwaysZero) { ... } part to case 34, the processing time suddenly jumps from around 0.250s to around 3.7 seconds.
Does anyone have an idea what is going on here?
$ java -version
openjdk version "11.0.9.1" 2020-11-04
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9.1+1)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.9.1+1, mixed mode)
