Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Click Here!
Click Here!
ITKnowledge
Find:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


The nameIndex() and CodeAttribute() methods are the same ones that you saw in the preceding chapter. The readCode() method is a big lookup table that returns the next opcode mnemonic and its arguments from the code array. Some instructions take one or more of their arguments from the bytes that follow them in the code array. Therefore, you can’t just blindly convert each byte to a mnemonic. Some bytes must remain bytes. Opcodes 170, 171, and 196 (tableswitch, lookupswitch, and wide) can take a varying number of arguments, so extra logic is required to handle them. I describe this logic later in this chapter, when I discuss those instructions.

Armed with this information, you should now have a better idea of what’s going on inside the methods when you disassemble a program. For example, disassembling HelloWorld, you get the output shown in Listing 5-2.

Listing 5-2 HelloWorld disassembled into byte code mnemonics

  import java.io.PrintStream;

  class HelloWorld extends java.lang.Object  {


   public static void main() {

  0   getstatic 7
  3   ldc 1
  5   invokevirtual 8
  8   return

   }


   void <init>() {

  0   aload_0
  1   invokespecial 6
  4   return

   }

  }

  /*
  1:  String         18
  2:  ClassInfo      19
  3:  ClassInfo      25
  4:  ClassInfo      26
  5:  ClassInfo      27
  6:  MethodRef         ClassIndex: 4;   NameAndTypeIndex: 9
  7:  FieldRef          ClassIndex: 5;   NameAndTypeIndex: 10
  8:  MethodRef         ClassIndex: 3;   NameAndTypeIndex: 11
  9:  NameAndType       NameIndex: 14;   DescriptorIndex: 12
  10:  NameAndType      NameIndex: 29;   DescriptorIndex: 22
  11:  NameAndType      NameIndex: 30;   DescriptorIndex: 13
  12:  UTF8          ()V
  13:  UTF8          (Ljava/lang/String;)V
  14:  UTF8          <init>
  15:  UTF8          Code
  16:  UTF8          ConstantValue
  17:  UTF8          Exceptions
  18:  UTF8          Hello World
  19:  UTF8          HelloWorld
  20:  UTF8          HelloWorld.java
  21:  UTF8          LineNumberTable
  22:  UTF8          Ljava/io/PrintStream;
  23:  UTF8          LocalVariables
  24:  UTF8          SourceFile
  25:  UTF8          java/io/PrintStream
  26:  UTF8          java/lang/Object
  27:  UTF8          java/lang/System
  28:  UTF8          main
  29:  UTF8          out
  30:  UTF8          print

  */

Listing 5-2 is the most intelligible disassembly yet. The rest of this chapter describes the various opcodes, so you can really understand what’s going on inside the file.

Stacks, Frames, and Pools

Instructions require data on which to operate. You can take this data from five places: the method stack, the heap, the constant pool, the local variable array, and the byte code itself. The method stack, the local variable array, and the byte code are specific to the method. The constant pool and the heap are shared by all other threads and methods executing in the same virtual machine.

All of the operations in a method such as addition or subtraction take place on the stack. For example, to add two integers, the integers are first pushed onto the stack, then they’re popped off of the stack, and then their sum is pushed back onto the stack.

The local variable array is a temporary holding area for local variables declared in the method and arguments passed to the method. You have to copy those local variables onto the stack before you can do anything with them.

Instructions that access the heap get references to items in the heap from the stack. You learned about the constant pool in the last chapter. Operations that access the constant pool also use indices into the pool placed on the heap.

When the Java virtual machine is running, each thread has a stack of frames. (This is related neither to HTML frames nor to the java.util.Stack class.) A frame holds the local variables and arguments for a method and a working area for the method called the operand stack. When a method is called, the virtual machine creates a new frame for the method with space for its local variables and its local stack. This frame is placed on top of the thread’s stack. When the method completes, this frame is popped from the thread’s stack, and the method’s return value (if any) is pushed onto the top of the calling method’s stack.

Each method operates on the values contained in its local variable array and on its method stack. You can think of the local variable array as an array of 32-bit words, and the method stack as a stack of 32-bit words.

Let’s look at a simple example. Consider the following method, which adds two to four and returns the sum:

     public int six() {

       int a = 4;
       int b = 2;
       int c = a + b;
       return c;
 
     }

Here’s the same method as disassembled byte code:

     public int six() {

    0   iconst_4
    1   istore_1
    2   iconst_2
    3   istore_2
    4   iload_1
    5   iload_2
    6   iadd
    7   istore_3
    8   iload_3
    9   ireturn

     }

Let’s investigate this byte code instruction by instruction, to see what effect each one has on the array of local variables and the stack.

You first need to look at the number of different locations referenced by load and store instructions to determine how many local variables are used.

Instruction 0 pushes the constant 4 onto the stack. That doesn’t affect the local variable array at all.

Instruction 1 stores a value into position 1 in the local variable array. The local variable array therefore must have at least one entry.

Instruction 2 pushes the constant value 2 onto the method stack. Again, this has no effect on the local variable array.

Instruction 3 stores a variable into position 2 in the local variable array. Therefore, there are at least positions 1 and 2 in the local variable array, so that array has to be at least 2 entries long.

Instructions 4 and 5 move values from the local variable array at positions 1 and 2 onto the stack. However, you’ve already seen variables 1 and 2, so that’s nothing new. Instruction 6 adds the two variables onto the top of the stack and puts the result back on the stack. Again, the local variable array is not changed.

Instructions 7 and 8 store something into the third position in the local variable array and then load it onto the stack. So there now have to be at least 3 entries in the local variable array.

Finally, instruction 9 returns and completes the method.


Previous Table of Contents Next
HomeAbout UsSearchSubscribeAdvertising InfoContact UsFAQs
Use of this site is subject to certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.