Search code examples
javajvmjvm-bytecode

Loading large amount of binary data into a `[B` in raw JVM bytecode


I am generating JVM bytecode in Krakatau syntax to load a large binary blob into a [B. The point is to have all the actual data stored in the .class file instead of reading it at runtime from an external source.

The code I have generated looks like this:

.method public static loadImage : ([B)V
  .code stack 6 locals 1
    aload_0
    iconst_0
    iconst_1
    iadd
    dup2
    bipush 71
    bastore
    iconst_1
    iadd
    dup2
    bipush 108
    bastore
    ...
    iconst_1
    iadd
    dup2
    bipush 0
    bastore
    return
  .end code
.end method

However, at runtime this method fails because it's too long:

Exception in thread "main" java.lang.ClassFormatError: 
Invalid method Code length 572931 in class file Image

Is there a better way to load a large binary blob into a byte array? I guess one workaround would be to keep my current code, but split it into several methods, but that is quite horrible...


Solution

  • Put a static field on your class, which is statically initialised by reading a resource. I use Guava ByteStreams below, use any io utils you like though...

    class MyClass {
        static byte[] theData; 
        static {
            try { 
                theData = ByteStreams.toByteArray(MyClass.class.getClassLoader().getResourceAsStream('/myBigResource.dat'))
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
         ...
    }
    

    You incur the cost of reading the secondary resource exactly once, at class loading time, but you would get that anyway even if you had the byte data embedded in your .class file. The only real extra cost you get is locating and opening that one extra resource, plus whatever object-interactions are involved in that.

    The only real problem is the exception handling. If reading the resource throws an IOException that will appear in your program as a ClassNotFound exception, which can be confusing.

    You also need to be aware that this is going to search your classpath for the resource file. Somebody could put a 'similarly' named file somewhere and create havoc. Particularly if it's a VeryLarge file.