How the J2ME StackMap Works
All JVMs verify the class file during linking. The mostly costly part of verification is Pass 3, where the JVM does detailed data-flow analysis on the code attribute. This analysis verifies a number of things dealing with the operand stack (the work area) and the local variable array. On J2ME classes, we do pre-verification on the class files, storing information in a stack map about the local variable array and operand stack. We only need to store information in the stack map when there is a conditional statement or exception within the byte-code. Thus, the KVM uses a lot less memory than the typical JVM during Pass 3 verification because the KVM does a linear scan of the byte-code, relying on the stack map for all of the branches.
According to the CLDC 1.0 Spec, stack item types and local variables are recorded if one or more of the following conditions hold:
1. The instruction is a target of a conditional jump (e.g., ifeq), unconditional jump (e.g., goto), tableswitch, or a lookupswitch instruction. 2. The instruction is marked by the handler_pc in the exception_table of the Code attribute. 3. The instruction immediately follows an unconditional jump (e.g., goto), tableswitch, lookupswitch, athrow, or return instructions. Unless this instruction is dead code, it must also fall into cases 1 or 2.
The stack map attribute structure is:
StackMap_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_entries; { u2 byte_code_offset; u2 number_of_locals; ty types_of_locals[number_of_locals]; u2 number_of_stack_items; ty stack_item_types[number_of_stack_items]; } entries[number_of_entries]; }
From the structure above, we see that the stack map attribute contains the byte_code_offset of the target, contents of the local variable array and contents of the operand stack.
Now let?s take a look at the following byte-code:
Offset Instruction Argument 0 aload_0 1 getfield rand Ljava/util/Random; 4 invokevirtual java.util.Random.nextInt ()I():int 7 iload_1 8 irem 9 istore_2 10 iload_2 11 ifge 18 14 iload_2 15 iload_1 16 iadd 17 istore_2 18 iload_2 19 ireturn
In the code above, the KVM cannot do a linear scan of the byte-codes. Offset 11 has a conditional jump to offset 18, thus satisfying condition (1); so we need a stack map. In offset 0, the KVM loads a reference to this into the local variable array. In offsets 7 and 10, the KVM loads Integers. The pre-verifier has already recorded the stack map attribute with the local variable array containing {object, integer, integer}. You can also find the values of the operand stack within the stack map by going through the byte-code. The getfield and invokevirtual instructions each push an object onto the operand stack and so on.
That is about all there is in regards to a stack map.
Posted by random7 [J2ME] ( June 13, 2004 08:55 PM ) Permalink | Comments[0]