From 2e5e4a6c88ab15bf894c3a407e5ab68569b88901 Mon Sep 17 00:00:00 2001 From: Mohamed Ibrahim <mibrahim@mibrahim.net> Date: Sat, 29 Aug 2015 08:32:24 -0400 Subject: [PATCH] Fixing tabs --- doc/ConvertingBytecodeToOpenCL.md | 286 +++++++++++++++--------------- 1 file changed, 144 insertions(+), 142 deletions(-) diff --git a/doc/ConvertingBytecodeToOpenCL.md b/doc/ConvertingBytecodeToOpenCL.md index 85c703c6..74210bb1 100644 --- a/doc/ConvertingBytecodeToOpenCL.md +++ b/doc/ConvertingBytecodeToOpenCL.md @@ -1,4 +1,4 @@ -#ConvertingBytecodeToOpenCL +#ConvertingBytecodeToOpenCL *How Aparapi converts bytecode to OpenCL Updated Aug 23, 2012 by frost.g...@gmail.com* @@ -12,7 +12,7 @@ In this page we will try to describe the process used to perform this conversion The command - javac Source.java + javac Source.java Will compile the java source file Source.java to Source.class @@ -20,90 +20,92 @@ The classfile format is well documented here and we will not go into too much de Lets start with a simple Kernel. - import com.amd.aparapi.Kernel; + import com.amd.aparapi.Kernel; - public class Squarer extends Kernel{ - int[] in; - int[] out; - @Override public void run(){ - int gid = getGlobalId(0); - out[gid] = in[gid] * in[gid]; - } - } + public class Squarer extends Kernel{ + int[] in; + int[] out; + @Override public void run(){ + int gid = getGlobalId(0); + out[gid] = in[gid] * in[gid]; + } + } We will compile this - javac -g -cp path/to/aparapi/aparapi.jar Squarer.java + javac -g -cp path/to/aparapi/aparapi.jar Squarer.java and then we can look at the bytecode using javap - javap -c -classpath path/to/aparapi/aparapi.jar;. Squarer + javap -c -classpath path/to/aparapi/aparapi.jar;. Squarer + Compiled from "Squarer.java" - public class Squarer extends com.amd.aparapi.Kernel - SourceFile: "Squarer.java" - minor version: 0 - major version: 50 - Constant pool: - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V - const #2 = Method #5.#18; // Squarer.getGlobalId:(I)I - const #3 = Field #5.#19; // Squarer.out:[I - const #4 = Field #5.#20; // Squarer.in:[I - const #5 = class #21; // Squarer - const #6 = class #22; // com/amd/aparapi/Kernel - const #7 = Asciz in; - const #8 = Asciz [I; - const #9 = Asciz out; - const #10 = Asciz <init>; - const #11 = Asciz ()V; - const #12 = Asciz Code; - const #13 = Asciz LineNumberTable; - const #14 = Asciz run; - const #15 = Asciz SourceFile; - const #16 = Asciz Squarer.java; - const #17 = NameAndType #10:#11;// "<init>":()V - const #18 = NameAndType #23:#24;// getGlobalId:(I)I - const #19 = NameAndType #9:#8;// out:[I - const #20 = NameAndType #7:#8;// in:[I - const #21 = Asciz Squarer; - const #22 = Asciz com/amd/aparapi/Kernel; - const #23 = Asciz getGlobalId; - const #24 = Asciz (I)I; - - { - int[] in; - - int[] out; - - public Squarer(); - Code: - Stack=1, Locals=1, Args_size=1 - 0: aload_0 - 1: invokespecial #1; //Method com/amd/aparapi/Kernel."<init>":()V - 4: return - - - public void run(); - Code: - Stack=5, Locals=2, Args_size=1 - 0: aload_0 - 1: iconst_0 - 2: invokevirtual #2; //Method getGlobalId:(I)I - 5: istore_1 - 6: aload_0 - 7: getfield #3; //Field out:[I - 10: iload_1 - 11: aload_0 - 12: getfield #4; //Field in:[I - 15: iload_1 - 16: iaload - 17: aload_0 - 18: getfield #4; //Field in:[I - 21: iload_1 - 22: iaload - 23: imul - 24: iastore - 25: return - } + + public class Squarer extends com.amd.aparapi.Kernel + SourceFile: "Squarer.java" + minor version: 0 + major version: 50 + Constant pool: + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #2 = Method #5.#18; // Squarer.getGlobalId:(I)I + const #3 = Field #5.#19; // Squarer.out:[I + const #4 = Field #5.#20; // Squarer.in:[I + const #5 = class #21; // Squarer + const #6 = class #22; // com/amd/aparapi/Kernel + const #7 = Asciz in; + const #8 = Asciz [I; + const #9 = Asciz out; + const #10 = Asciz <init>; + const #11 = Asciz ()V; + const #12 = Asciz Code; + const #13 = Asciz LineNumberTable; + const #14 = Asciz run; + const #15 = Asciz SourceFile; + const #16 = Asciz Squarer.java; + const #17 = NameAndType #10:#11;// "<init>":()V + const #18 = NameAndType #23:#24;// getGlobalId:(I)I + const #19 = NameAndType #9:#8;// out:[I + const #20 = NameAndType #7:#8;// in:[I + const #21 = Asciz Squarer; + const #22 = Asciz com/amd/aparapi/Kernel; + const #23 = Asciz getGlobalId; + const #24 = Asciz (I)I; + + { + int[] in; + + int[] out; + + public Squarer(); + Code: + Stack=1, Locals=1, Args_size=1 + 0: aload_0 + 1: invokespecial #1; //Method com/amd/aparapi/Kernel."<init>":()V + 4: return + + + public void run(); + Code: + Stack=5, Locals=2, Args_size=1 + 0: aload_0 + 1: iconst_0 + 2: invokevirtual #2; //Method getGlobalId:(I)I + 5: istore_1 + 6: aload_0 + 7: getfield #3; //Field out:[I + 10: iload_1 + 11: aload_0 + 12: getfield #4; //Field in:[I + 15: iload_1 + 16: iaload + 17: aload_0 + 18: getfield #4; //Field in:[I + 21: iload_1 + 22: iaload + 23: imul + 24: iastore + 25: return + } Here we see constant pool of the class and the disassembled bytecode of the default constructor Squarer() and the Squarer.run() method. @@ -111,60 +113,60 @@ The constant pool is a table of constant values that can be accessed from the by For example constant pool entry #1 is - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V So entry #1 defines a method. The class containing the method is defined in constant pool entry #6. So lets look at constant pool entry #6. - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V - const #6 = class #22; // com/amd/aparapi/Kernel + const #6 = class #22; // com/amd/aparapi/Kernel At constant pool entry #6 we find a class definition which refers to entry #22 - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V - const #6 = class #22; // com/amd/aparapi/Kernel + const #6 = class #22; // com/amd/aparapi/Kernel - const #22 = Asciz com/amd/aparapi/Kernel; + const #22 = Asciz com/amd/aparapi/Kernel; Which just contains the String (Ascii) name of the class. Looking back at entry #1 again, we note that the Method also references entry #17 which contains a NameAndType entry for determining the method name and the signature. - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V - const #6 = class #22; // com/amd/aparapi/Kernel + const #6 = class #22; // com/amd/aparapi/Kernel - const #17 = NameAndType #10:#11;// "<init>":()V + const #17 = NameAndType #10:#11;// "<init>":()V - const #22 = Asciz com/amd/aparapi/Kernel; + const #22 = Asciz com/amd/aparapi/Kernel; - Entry #17's "NameAndType" references #10 for the method name. +Entry #17's "NameAndType" references #10 for the method name. - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V - const #6 = class #22; // com/amd/aparapi/Kernel + const #6 = class #22; // com/amd/aparapi/Kernel - const #10 = Asciz <init>; + const #10 = Asciz <init>; - const #17 = NameAndType #10:#11;// "<init>":()V + const #17 = NameAndType #10:#11;// "<init>":()V - const #22 = Asciz com/amd/aparapi/Kernel; + const #22 = Asciz com/amd/aparapi/Kernel; And then references #11 to get the signature. - const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V + const #1 = Method #6.#17; // com/amd/aparapi/Kernel."<init>":()V - const #6 = class #22; // com/amd/aparapi/Kernel + const #6 = class #22; // com/amd/aparapi/Kernel - const #10 = Asciz <init>; + const #10 = Asciz <init>; - const #11 = Asciz ()V; + const #11 = Asciz ()V; - const #17 = NameAndType #10:#11;// "<init>":()V + const #17 = NameAndType #10:#11;// "<init>":()V - const #22 = Asciz com/amd/aparapi/Kernel; + const #22 = Asciz com/amd/aparapi/Kernel; So from constant pool #1 we ended up using slots 1,6,10,11,17 and 22 to fully resolve the method. @@ -186,7 +188,7 @@ Some instructions can only handle specific types (int, float, double, and object So lets look at the first instruction. - 0: aload_0 + 0: aload_0 This instruction loads an object (a is the first character) from variable slot 0 (we'll come back to the variable slots in a moment) and pushes it on the stack. @@ -194,37 +196,37 @@ Variables are held in 'slots' that are reserved at compiled time. Consider this static method. -static int squareMe(int value){ - value += value; - return(value); -} + static int squareMe(int value){ + value += value; + return(value); + } This method requires one variable slot. At any one time there is only one variable that is live, it just happens to be an argument to the method. The following method also contains one slot. -static int squareMe(){ - int value=4; - value += value; - return(value); -} + static int squareMe(){ + int value=4; + value += value; + return(value); + } Here we need two slots -static int squareMe(int arg){ - int value=arg*arg; - return(value); -} + static int squareMe(int arg){ + int value=arg*arg; + return(value); + } Suprisingly the following also only requires two slots. -static int squareMe(int arg){ - { - int temp = arg*arg; - } - int value=arg*arg; - return(value); -} + static int squareMe(int arg){ + { + int temp = arg*arg; + } + int value=arg*arg; + return(value); + } Note that in the above example the temp variable loses scope before the local variable value is used. So only two slots are required. Both temp and value can share a slot. @@ -232,49 +234,49 @@ If we have an instance method we always require one extra slot (always slot 0) f So -int squareMe(int arg){ - int value=arg*arg; - return(value); -} + int squareMe(int arg){ + int value=arg*arg; + return(value); + } Requires three slots. Anyway back to our bytecode - 0: aload_0 + 0: aload_0 This loads the object instance in slot 0 (this) and pushes it on the stack. Next we have - 1: iconst_0 + 1: iconst_0 Which pushes the int constant 0 on the stack. So the stack contains {this,0} Next we have - 2: invokevirtual #2; //Method getGlobalId:(I)I + 2: invokevirtual #2; //Method getGlobalId:(I)I -This is the bytecode for calling a method. Basically the instruction itself references the constant pool (we'll come back to this ;) ) and pulls the method description in constantPool2 which happens to be the description for a method called getGlobalId() which takes an integer and returns an int. +This is the bytecode for calling a method. Basically the instruction itself references the constant pool (we'll come back to this ;) ) and pulls the method description in `constantPool2` which happens to be the description for a method called `getGlobalId()` which takes an integer and returns an `int`. -So the VM will pop the top value (int - const 0) as the method arg, and then will pop an object reference (this!) and will call the method this.getGlobalId(0) and will push the result (an int) back on the stack. +So the VM will pop the top value `(int - const 0)` as the method arg, and then will pop an object reference (this!) and will call the method `this.getGlobalId(0)` and will push the result (an int) back on the stack. -So our stack which contains {this,0} now contains the result of this.getGlobalId(0), lets assume it is {0}. We describe this invoke instruction as consuming two operands from the stack and producing one. +So our stack which contains `{this,0}` now contains the result of this.getGlobalId(0), lets assume it is {0}. We describe this invoke instruction as consuming two operands from the stack and producing one. Before we start executing our stack is empty {}, the slots are initialized with 'this' (if an instance method) and any arguments passed to the method. - 0 1 - slots=[this, ? ] stack={} + 0 1 + slots=[this, ? ] stack={} - 0 1 - 0: aload_0 slots=[this, ? ] stack={this} - 0 1 - 1: iconst_0 slots=[this, ? ] stack={this, 0} - 0 1 - 2: invokevirtual #2; Method getGlobalId:(I)I slots=[this, ? ] stack={result of this.getGlobalId(0) lets say 0} + 0 1 + 0: aload_0 slots=[this, ? ] stack={this} + 0 1 + 1: iconst_0 slots=[this, ? ] stack={this, 0} + 0 1 + 2: invokevirtual #2; Method getGlobalId:(I)I slots=[this, ? ] stack={result of this.getGlobalId(0) lets say 0} - 5: istore_1 slots=[this, 0 ] stack={} + 5: istore_1 slots=[this, 0 ] stack={} - 6: aload_0 slots=[this, 0 ] stack={this} + 6: aload_0 slots=[this, 0 ] stack={this} - 7: getfield #3; //Field out:[I + 7: getfield #3; //Field out:[I -- GitLab