All the source codes can be found in the ./impl/src/main/java/net/burningtnt/bcidemos directory.
In this project, we will make a program that prints "Hello BCIG!" on the console.
In the beginning, let's make the structure.
package net.burningtnt.bcidemos.demo0;
import net.burningtnt.bcigenerator.api.BytecodeImpl;
import net.burningtnt.bcigenerator.api.BytecodeImplError;
public final class Demo0 {
private Demo0() {
}
@BytecodeImpl({
// BCIIs
})
private static void method() {
throw new BytecodeImplError();
}
public static void main(String[] args) {
method();
}
}
In general, our BCIIs should be coded in following steps:
- Load the static field of
java.lang.System#out
into the JVM runtime stack. - Load a String type constant into the JVM runtime stack.
- Invoke the virtual method of
java.io.PrintStream::println(java.lang.String)
, which consumes the upper objects. - Return our bytecode implemented method.
So, these are the BCIIs.
GETSTATIC Ljava/lang/System;out:Ljava/io/PrintStream;
LDC (STRING "Hello BCIG!")
INVOKEVIRTUAL Ljava/io/PrintStream;println(Ljava/lang/String;)V
RETURN
In order to make this method legal in VM Class Format, we should insert these BCIIs.
+LABEL METHOD_HEAD
GETSTATIC Ljava/lang/System;out:Ljava/io/PrintStream;
LDC (STRING "Hello BCIG!")
INVOKEVIRTUAL Ljava/io/PrintStream;println(Ljava/lang/String;)V
+LABEL METHOD_TAIL
RETURN
+MAXS 2 0
LABEL METHOD_HEAD
: The start label of this method.LABEL METHOD_TAIL
: The tail label of this method.MAXS 2 0
: Declare the max stack number and max local number.
What many people can't understand is how the max stacks and max locals are calculated.
Here, let's imagine how JVM run our bytecodes. When JVM run till line INVOKEVIRTUAL Ljava/io/PrintStream;println(Ljava/lang/String;)V
,
there are two element in the JVM runtime stack: Ljava/io/PrintStream
and Ljava/lang/String
. Both of the two element required 1 stack space.
So the max stack number is 2.
In this method, no local variable is required. So the max local number is 0.
In this project, we will create a method that invokes java.nio.file.Path::of(java.lang.String, java.lang.String...)
with bytecode.
In the beginning, let's make the structure.
package net.burningtnt.bcidemos.demo0;
import net.burningtnt.bcigenerator.api.BytecodeImpl;
import net.burningtnt.bcigenerator.api.BytecodeImplError;
import java.nio.file.Path;
public final class Demo1 {
private Demo1() {
}
@BytecodeImpl({
// BCIIs
})
private static Path getPath(String first, String... further) {
throw new BytecodeImplError();
}
public static void main(String[] args) {
System.out.println(getPath("First", "Second", "Third").toString());
}
}
Here we declared a method called getPath
with two parameters and a return value.
In general, our BCIIs should be coded in following steps:
- Load the first parameter into the JVM runtime stack.
- Load the second parameter into the JVM runtime stack.
- Invoke the static method of
java.nio.file.Path::of(java.lang.String, java.lang.String...)
, which consumes the upper objects and return ajava.nio.file.Path
object. - Return our bytecode implemented method with an object.
So, these are the BCIIs.
ALOAD 0
ALOAD 1
INVOKEINTERFACESTATIC Ljava/nio/file/Path;of(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;
ARETURN
Note that here we invoked a static method in an interface, so we need to use the INVOKEINTERFACESTATIC
operator.
In order to make this method legal in VM Class Format, we should insert these BCIIs.
+LABEL METHOD_HEAD
ALOAD 0
ALOAD 1
INVOKEINTERFACESTATIC Ljava/nio/file/Path;of(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;
+LABEL METHOD_TAIL
ARETURN
+LOCALVARIABLE first Ljava/lang/String; METHOD_HEAD METHOD_TAIL 0
+LOCALVARIABLE further [Ljava/lang/String; METHOD_HEAD METHOD_TAIL 1
+MAXS 2 2
Here, we have two local variable. So, we need to declare them in the BCII. LOCALVARIABLE operator should be after codes, and MAXS operator should always in the last.
Notice: The Label ID in operators must be defined by using LABEL XXX
before or after. Which means, You can use GOTO XXX
before this Label ID is really defined.