14 Aug 2012

Java Virtual Machine


Java Virtual Machine



  •  Java Development kit contains Java Runtime Environment and java tools,
  • JRE contains java virtual machine and java api.
  • Jdk = jre + tools .
  • Jre = jvm + java Api.


Java Virtual Machine:

Java code is written in .java file. This code contains one or more Java language attributes like Classes, Methods, Variable, Objects etc. Javac is used to compile this code and to generate .class file. Class file is also known as "byte code".




  • Java is plotform independent and jvm is plotform dependent.
  • JVM is the main component of Java architecture and it is the part of the JRE (Java Runtime Enviroment) . It provides the cross platform functionality to java. 
  • JVM is a software process that converts the compiled Java byte code to machine code. Byte code is an intermediary language between Java source and the host system.
  •  Most programming language like C and Pascal converts the source code into machine code for one specific type of machine as the machine language vary from system to system . 
  • Mostly compiler produce code for a particular system but Java compiler produce code for a virtual machine . JVM provides security to java.
  • The programs written in Java or the source code translated by Java compiler into byte code and after that the JVM converts the byte code into machine code for the computer one wants to run. 
  • JVM is a part of Java Run Time Environment that is required by every operating system requires a different JRE .  




  • Each operating system and CPU architecture requires a JRE. JRE consists of a set of base classes i.e. an implementation of the base Java API as well as a JVM. 
  • The byte code format is same on all platforms as it runs in the same JVM and it is totally independent from the Operating System and the CPU architecture.
  • JRE consists of a number of classes based on JavaAPI and JVM, and without JRE, it is impossible to run Java. So its portability really made it possible in developing write once and run anywhere software.


The Lifetime of a Java Virtual Machine:


  • A runtime instance of the Java virtual machine has a clear mission in life: to run one Java application. When a Java application starts, a runtime instance is born. 
  • When the application completes, the instance dies. If you start three Java applications at the same time, on the same computer, using the same concrete implementation, 
  • you'll get three Java virtual machine instances. Each Java application runs inside its own Java virtual machine.
  • A Java virtual machine instance starts running its solitary application by invoking the main() method of some initial class. 
  • The main() method must be public, static, return void, and accept one parameter: a String array.
  • Any class with such a main()method can be used as the starting point for a Java application.  

Ex:1-

class Krish {

    public static void main(String[] k) {
        int len = k.length;
        for (int i = 0; i < len; ++i) {
            System.out.print(k[i] + " ");
        }
        System.out.println();
    }
}

  • java Krish Greetings, Planet.
  • "java," indicates that the Java virtual machine from Sun's Java 2 SDK should be run by the operating system. 
  • "Krish," is the name of the initial class. Krish must have a public static method named main() that returns void and takes a String array as its only parameter. 
  • The subsequent words, "Greetings, Planet.," are the command line arguments for the application. These are passed to the main() method in the String array in the order in which they appear on the command line.
  • So, for the previous example, the contents of the String array passed to main in Krish are: k[0] is "Greetings," k[1] is "Planet."
  • The main() method of an application's initial class serves as the starting point for that application's initial thread. The initial thread can in turn fire off other threads.
  • Inside the Java virtual machine, threads come in two flavors: daemon and non- daemon. 
  • A daemon thread is ordinarily a thread used by the virtual machine itself, such as a thread that performs garbage collection. The application, however, can mark any threads it creates as daemon threads. 
  • The initial thread of an application--the one that begins at main()--is a non- daemon thread.
  • A Java application continues to execute (the virtual machine instance continues to live) as long as any non-daemon threads are still running. When all non-daemon threads of a Java application terminate, the virtual machine instance will exit. If permitted by the security manager, the application can also cause its own demise by invoking the exit() method of class Runtime orSystem.
  • In the Echo application previous, the main() method doesn't invoke any other threads. After it prints out the command line arguments, main() returns. This terminates the application's only non-daemon thread, which causes the virtual machine instance to exit.


The Architecture of the Java Virtual Machine


  • In the Java virtual machine specification, the behavior of a virtual machine instance is described in terms of subsystems, memory areas, data types, and instructions. 
  • These components describe an abstract inner architecture for the abstract Java virtual machine. 
  • The purpose of these components is not so much to dictate an inner architecture for implementations. 
  • It is more to provide a way to strictly define the external behavior of implementations. 
  • The specification defines the required behavior of any Java virtual machine implementation in terms of these abstract components and their interactions.

  • Above shows a block diagram of the Java virtual machine that includes the major subsystems and memory areas described in the specification.
  • Each Java virtual machine has a class loader subsystem: a mechanism for loading types (classes and interfaces) given fully qualified names. 
  • Each Java virtual machine also has an execution engine: a mechanism responsible for executing the instructions contained in the methods of loaded classes.
  • When a Java virtual machine runs a program, it needs memory to store many things, including byte codes and other information it extracts from loaded class files, objects the program instantiates, parameters to methods, return values, local variables, and intermediate results of computations.
  • The Java virtual machine organizes the memory it needs to execute a program into several runtime data areas. 
  • Each instance of the Java virtual machine has one method area and one heap. These areas are shared by all threads running inside the virtual machine. 
  • When the virtual machine loads a class file, it parses information about a type from the binary data contained in the class file. 
  • It places this type information into the method area. As the program runs, the virtual machine places all objects the program instantiates onto the heap. 
  • As each new thread comes into existence, it gets its own pc register (program counter) and Java stack. 
  • If the thread is executing a Java method (not a native method), the value of the pc register indicates the next instruction to execute. A thread's Java stack stores the state of Java (not native) method invocations for the thread. 
  • The state of a Java method invocation includes its local variables, the parameters with which it was invoked, its return value (if any), and intermediate calculations. 
  • The state of native method invocations is stored in an implementation-dependent way in native method stacks, as well as possibly in registers or other implementation-dependent memory areas.
  • The Java stack is composed of stack frames (or frames). A stack frame contains the state of one Java method invocation. 
  • When a thread invokes a method, the Java virtual machine pushes a new frame onto that thread's Java stack. When the method completes, the virtual machine pops and discards the frame for that method.
  • The Java virtual machine has no registers to hold intermediate data values. The instruction set uses the Java stack for storage of intermediate data values.
  • This approach was taken by Java's designers to keep the Java virtual machine's instruction set compact and to facilitate implementation on architectures with few or irregular general purpose registers. In addition, the stack-based architecture of the Java virtual machine's instruction set facilitates the code optimization work done by just-in-time and dynamic compilers that operate at run-time in some virtual machine implementations.
  • Above Diagram shows a snapshot of a virtual machine instance in which three threads are executing. At the instant of the snapshot, threads one and two are executing Java methods. Thread three is executing a native method.
  • In Above Diagram, as in all graphical depictions of the Java stack in this book, the stacks are shown growing downwards. The "top" of each stack is shown at the bottom of the figure. 
  • Stack frames for currently executing methods are shown in a lighter shade. For threads that are currently executing a Java method, the pc register indicates the next instruction to execute. In Diagram, such pc registers (the ones for threads one and two) are shown in a lighter shade. Because thread three is currently executing a native method, 
  • The contents of its pc register-- the one shown in dark gray--is undefined.
  • The Java virtual machine contains two kinds of class loaders: a bootstrap class loader and user-defined class loaders. 
  • The bootstrap class loader is a part of the virtual machine implementation, and user-defined class loaders are part of the running Java application. 
  • Classes loaded by different class loaders are placed into separate name spaces inside the Java virtual machine.
  • The class loader subsystem involves many other parts of the Java virtual machine and several classes from the java.langlibrary. 
  • For example, user-defined class loaders are regular Java objects whose class descends fromjava.lang.ClassLoader. 
  • The methods of class ClassLoader allow Java applications to access the virtual machine's class loading machinery. Also, for every type a Java virtual machine loads, it creates an instance of class java.lang.Class to represent that type. 
  • Like all objects, user-defined class loaders and instances of class Class reside on the heap. Data for loaded types resides in the method area.

The Bootstrap Class Loader:

  • Java virtual machine implementations must be able to recognize and load classes and interfaces stored in binary files that conform to the Java class file format. 
  • An implementation is free to recognize other binary forms besides class files, but it must recognize class files.
  • Every Java virtual machine implementation has a bootstrap class loader, which knows how to load trusted classes, including the classes of the Java API. 
  • The Java virtual machine specification doesn't define how the bootstrap loader should locate classes. That is another decision the specification leaves to implementation designers

  • First of all , loads the . class file into memory. Then it verifies wether all byte code instruction are proper or not. 
  • If it finds any instruction suspicious, the execution is rejected immediately . 
  • If the byte instructions are proper, then it allocates necessary memory to execute the program. This memory is divided into five parts called runtime data areas. Which contain the data and results while running the programe.

The Method Area:

  • The method is the memory block, which stores the class code, code of the variables and code of the methods in the java program
  • Simple in method area stored class data members(static members) and byte code of the class.
  • Method area can also be garbage collected.

Heap Area:

  • Whenever a class instance or array is created in a running Java application, 
  • The memory for the new object is allocated from a single heap. As there is only one heap inside a Java virtual machine instance, all threads share it. Because a Java application runs inside its "own" exclusive Java virtual machine instance, there is a separate heap for every individual running application. 
  • There is no way two different Java applications could trample on each other's heap data. 
  • Two different threads of the same application, however, could trample on each other's heap data. 
  • This is why you must be concerned about proper synchronization of multi-threaded access to objects (heap data) in your Java programs.
  • The Java virtual machine has an instruction that allocates memory on the heap for a new object, but has no instruction for freeing that memory. 
  • Just as you can't explicitly free an object in Java source code, you can't explicitly free an object in Java bytecodes. 
  • The virtual machine itself is responsible for deciding whether and when to free memory occupied by objects that are no longer referenced by the running application. 
  • Usually, a Java virtual machine implementation uses a garbage collector to manage the heap.

Object Representaion:

  • The Java virtual machine specification is silent on how objects should be represented on the heap. Object representation--an integral aspect of the overall design of the heap and garbage collector--is a decision of implementation designers
  • The primary data that must in some way be represented for each object is the instance variables declared in the object's class and all its superclasses. Given an object reference, the virtual machine must be able to quickly locate the instance data for the object. In addition, there must be some way to access an object's class data (stored in the method area) given a reference to the object. For this reason, the memory allocated for an object usually includes some kind of pointer into the method area.
  • One possible heap design divides the heap into two parts: a handle pool and an object pool. An object reference is a native pointer to a handle pool entry. 
  • A handle pool entry has two components: a pointer to instance data in the object pool and a pointer to class data in the method area. 
  • The advantage of this scheme is that it makes it easy for the virtual machine to combat heap fragmentation. When the virtual machine moves an object in the object pool, it need only update one pointer with the object's new address: the relevant pointer in the handle pool. 
  • The disadvantage of this approach is that every access to an object's instance data requires dereferencing two pointers. This approach to object representation is shown graphically in above diagram. 
  • This figure shows that the pointer kept with the instance data for each object points to a special structure.
  • A pointer to the full the class data for the object
  • The method table for the object The method table is an array of pointers to the data for each instance method that can be invoked on objects of that class. The method data pointed to by method table includes:
  • The sizes of the operand stack and local variables sections of the method's stack
  • The method's bytecodes
  • An exception table       

Array Representation:

  • In Java, arrays are full-fledged objects. Like objects, arrays are always stored on the heap. Also like objects, implementation designers can decide how they want to represent arrays on the heap.
  • Arrays have a Class instance associated with their class, just like any other object. All arrays of the same dimension and type have the same class. 
  • The length of an array (or the lengths of each dimension of a multidimensional array) does not play any role in establishing the array's class.
  •  For example, an array of three ints has the same class as an array of three hundredints. The length of an array is considered part of its instance data.
  • The name of an array's class has one open square bracket for each dimension plus a letter or string representing the array's type. 
  • For example, the class name for an array of ints is "[I". The class name for a three-dimensional array of bytes is "[[[B". 
  • The class name for a two-dimensional array of Objects is "[[Ljava.lang.Object". 
  • The full details of this naming convention for array classes is given in Chapter 6, "The Java Class File."
  • Multi-dimensional arrays are represented as arrays of arrays. A two dimensional array of ints, 
  • For example, would be represented by a one dimensional array of references to several one dimensional arrays of ints. This is shown graphically in figure.


  • array data, and some kind of reference to the array's class data. 
  • Given a reference to an array, the virtual machine must be able to determine the array's length, to get and set its elements by index (checking to make sure the array bounds are not exceeded), and to invoke any methods declared byObject, the direct superclass of all arrays.
  • Simple: heap area is the area where objects are creaed. Whenever jvm loads a class, a method and a heap area are immediately created.

NOTE: Instance members stored in heap area.

The Program Counter:

Each thread of a running program has its own pc register, or program counter, which is created when the thread is started. 
The pc register is one word in size, so it can hold both a native pointer and a returnAddress. 
As a thread executes a Java method, the pc register contains the address of the current instruction being executed by the thread. 
An "address" can be a native pointer or an offset from the beginning of a method's byte codes. 
If a thread is executing a native method, the value of the pc register is undefined.

Simple: these are the registers(memory area)which contain memory address of the instructions of the methods if there are 3 methods,3 pc registers will be used to track the instructions of the methods.

Java stacks:

  • When a new thread is launched, the Java virtual machine creates a new Java stack for the thread. As mentioned earlier, a Java stack stores a thread's state in discrete frames. 
  • The Java virtual machine only performs two operations directly on Java Stacks: it pushes and pops frames.
  • The method that is currently being executed by a thread is the thread's current method. The stack frame for the current method is the current frame. 
  • The class in which the current method is defined is called the current class, and the current class's constant pool is the current constant pool. 
  • As it executes a method, the Java virtual machine keeps track of the current class and current constant pool. 
  • When the virtual machine encounters instructions that operate on data stored in the stack frame, it performs those operations on the current frame.
  • When a thread invokes a Java method, the virtual machine creates and pushes a new frame onto the thread's Java stack. 
  • This new frame then becomes the current frame. As the method executes, it uses the frame to store parameters, local variables, intermediate computations, and other data.
  • A method can complete in either of two ways. If a method completes by returning, it is said to have normal completion. 
  • If it completes by throwing an exception, it is said to have abrupt completion. When a method completes, whether normally or abruptly, the Java virtual machine pops and discards the method's stack frame. The frame for the previous method then becomes the current frame.
  • All the data on a thread's Java stack is private to that thread. There is no way for a thread to access or alter the Java stack of another thread. Because of this, 
  • you need never worry about synchronizing multi- threaded access to local variables in your Java programs. When a thread invokes a method, the method's local variables are stored in a frame on the invoking thread's Java stack. 
  • Only one thread can ever access those local variables: the thread that invoked the method.
  • Like the method area and heap, the Java stack and stack frames need not be contiguous in memory. Frames could be allocated on a contiguous stack, or they could be allocated on a heap, or some combination of both. 
  • The actual data structures used to represent the Java stack and stack frames is a decision of implementation designers. Implementations may allow users or programmers to specify an initial size for Java stacks, as well as a maximum or minimum size.
  • The Stack Frame:
  • The stack frame has three parts: local variables, operand stack, and frame data. 
  • The sizes of the local variables and operand stack, which are measured in words, depend upon the needs of each individual method. 
  • These sizes are determined at compile time and included in the class file data for each method. The size of the frame data is implementation dependent.
  • When the Java virtual machine invokes a Java method, it checks the class data to determine the number of words required by the method in the local variables and operand stack. 
  • It creates a stack frame of the proper size for the method and pushes it onto the Java stack.
  • Local Variables:
  • The local variables section of the Java stack frame is organized as a zero-based array of words. 
  • Instructions that use a value from the local variables section provide an index into the zero-based array. Values of type int, float, reference, andreturnAddress occupy one entry in the local variables array. Values of type byte, short, and char are converted to intbefore being stored into the local variables. Values of type long and double occupy two consecutive entries in the array.
  • To refer to a long or double in the local variables, instructions provide the index of the first of the two consecutive entries occupied by the value. 
  • For example, if a long occupies array entries three and four, instructions would refer to that long by index three. All values in the local variables are word-aligned. Dual-entry longs and doubles can start at any index.
  • The local variables section contains a method's parameters and local variables. Compilers place the parameters into the local variable array first, in the order in which they are declared. Figure below  shows the local variables section for the following two methods:

// On CD-ROM in file jvm/ex3/Krish.java

class Krish {

    public static int runClassMethod(int i, long l, float f,
        double d, Object o, byte b) {

        return 0;
    }

    public int runInstanceMethod(char c, double d, short s,
        boolean b) {

        return 0;
    }
}

Operand Stack:

  • Like the local variables, the operand stack is organized as an array of words. But unlike the local variables, which are accessed via array indices, the operand stack is accessed by pushing and popping values. 
  • If an instruction pushes a value onto the operand stack, a later instruction can pop and use that value.
  • The virtual machine stores the same data types in the operand stack that it stores in the local variables: int, long, float,double, reference, and returnType. 
  • It converts values of type byte, short, and char to int before pushing them onto the operand stack.
  • Other than the program counter, which can't be directly accessed by instructions, the Java virtual machine has no registers. 
  • The Java virtual machine is stack-based rather than register-based because its instructions take their operands from the operand stack rather than from registers. Instructions can also take operands from other places, such as immediately following the opcode (the byte representing the instruction) in the bytecode stream, or from the constant pool. 
  • The Java virtual machine instruction set's main focus of attention, however, is the operand stack.
  • The Java virtual machine uses the operand stack as a work space. Many instructions pop values from the operand stack, operate on them, and push the result. For example, the iadd instruction adds two integers by popping two ints off the top of the operand stack, adding them, and pushing the int result. 
  • Here is how a Java virtual machine would add two local variables that contain ints and store the int result in a third local variable:
iload_0    // push the int in local variable 0
iload_1    // push the int in local variable 1
    iadd       // pop two ints, add them, push result
   istore_2   // pop int, store into local variable 2
  • In this sequence of bytecodes, the first two instructions, iload_0 and iload_1, push the ints stored in local variable positions zero and one onto the operand stack. The iadd instruction pops those two int values, adds them, and pushes theint result back onto the operand stack. 
  • The fourth instruction, istore_2, pops the result of the add off the top of the operand stack and stores it into local variable position two. In Figure 5-10, you can see a graphical depiction of the state of the local variables and operand stack while executing these instructions. In this figure, unused slots of the local variables and operand stack are left blank.

Frame Data:

  • In addition to the local variables and operand stack, the Java stack frame includes data to support constant pool resolution, normal method return, and exception dispatch. 
  • This data is stored in the frame data portion of the Java stack frame.
  • Many instructions in the Java virtual machine's instruction set refer to entries in the constant pool. Some instructions merely push constant values of type int, long, float, double, or String from the constant pool onto the operand stack. Some instructions use constant pool entries to refer to classes or arrays to instantiate, fields to access, or methods to invoke. 
  • Other instructions determine whether a particular object is a descendant of a particular class or interface specified by a constant pool entry.
  • Whenever the Java virtual machine encounters any of the instructions that refer to an entry in the constant pool, it uses the frame data's pointer to the constant pool to access that information. As mentioned earlier, references to types, fields, and methods in the constant pool are initially symbolic. 
  • When the virtual machine looks up a constant pool entry that refers to a class, interface, field, or method, that reference may still be symbolic. If so, the virtual machine must resolve the reference at that time.
  • Aside from constant pool resolution, the frame data must assist the virtual machine in processing a normal or abrupt method completion. If a method completes normally (by returning), the virtual machine must restore the stack frame of the invoking method. It must set the pc register to point to the instruction in the invoking method that follows the instruction that invoked the completing method. 
  • If the completing method returns a value, the virtual machine must push that value onto the operand stack of the invoking method.
  • The frame data must also contain some kind of reference to the method's exception table, which the virtual machine uses to process any exceptions thrown during the course of execution of the method. "Exceptions," defines ranges within the byte codes of a method that are protected by catch clauses. 
  • Each entry in an exception table gives a starting and ending position of the range protected by a catch clause, an index into the constant pool that gives the exception class being caught, and a starting position of the catch clause's code.
  • When a method throws an exception, the Java virtual machine uses the exception table referred to by the frame data to determine how to handle the exception. 
  • If the virtual machine finds a matching catch clause in the method's exception table, it transfers control to the beginning of that catch clause. If the virtual machine doesn't find a matching catch clause, the method completes abruptly. 
  • The virtual machine uses the information in the frame data to restore the invoking method's frame. It then rethrows the same exception in the context of the invoking method.
  • In addition to data to support constant pool resolution, normal method return, and exception dispatch, the stack frame may also include other information that is implementation dependent, such as data to support debugging.
  • Below Figure shows snapshots of the Java stack of a different virtual machine implementation executing the same methods. 
  • Instead of allocating each frame separately from a heap, this implementation allocates frames from a contiguous stack. 
  • This approach allows the implementation to overlap the frames of adjacent methods. 
  • The portion of the invoking method's operand stack that contains the parameters to the invoked method become the base of the invoked method's local variables. 
  • In this example, addAndPrint()'s entire operand stack becomes addTwoType()'s entire local variables section.

  • This approach saves memory space because the same memory is used by the calling method to store the parameters as is used by the invoked method to access the parameters. 
  • It saves time because the Java virtual machine doesn't have to spend time copying the parameter values from one frame to another.
  • Note that the operand stack of the current frame is always at the "top" of the Java stack. Although this may be easier to visualize in the contiguous memory implementation of Above Figure, it is true no matter how the Java stack is implemented. (As mentioned earlier, in all the graphical images of the stack shown in this book, the stack grows downwards. 
  • The "top" of the stack is always shown at the bottom of the picture.) Instructions that push values onto (or pop values off of) the operand stack always operate on the current frame. Thus, pushing a value onto the operand stack can be seen as pushing a value onto the top of the entire Java stack.
  • "pushing a value onto the stack" refers to pushing a value onto the operand stack of the current frame.
  • Simple: local members stored in stack, stack frame has three parts.
     A local variable-> it is pointed to the vars register.
Operand stack->pointed to the optop register.
                         Frame data(execution Enviornment)->pointed to frame register
  • The size of the local variables and operand stack, which are measured in words, depend upon the needs of each individual method, these sizes are determined at compile time and included in the class file data for each method.

Native Method Stacks:

  • In addition to all the runtime data areas defined by the Java virtual machine specification and described previously, a running Java application may use other data areas created by or for native methods. 
  • When a thread invokes a native method, it enters a new world in which the structures and security restrictions of the Java virtual machine no longer hamper its freedom. 
  • A native method can likely access the runtime data areas of the virtual machine (it depends upon the native method interface), but can also do anything else it wants. 
  • It may use registers inside the native processor, allocate memory on any number of native heaps, or use any kind of stack.
  • Native methods are inherently implementation dependent. Implementation designers are free to decide what mechanisms they will use to enable a Java application running on their implementation to invoke native methods.
  • Any native method interface will use some kind of native method stack. When a thread invokes a Java method, the virtual machine creates a new frame and pushes it onto the Java stack. 
  • When a thread invokes a native method, however, that thread leaves the Java stack behind. Instead of pushing a new frame onto the thread's Java stack, the Java virtual machine will simply dynamically link to and directly invoke the native method. 
  • One way to think of it is that the Java virtual machine is dynamically extending itself with native code. 
  • It is as if the Java virtual machine implementation is just calling another (dynamically linked) method within itself, at the behest of the running Java program.
  • If an implementation's native method interface uses a C-linkage model, then the native method stacks are C stacks. When a C program invokes a C function, the stack operates in a certain way. 
  • The arguments to the function are pushed onto the stack in a certain order. The return value is passed back to the invoking function in a certain way. 
  • This would be the behavior of the of native method stacks in that implementation.
  • A native method interface will likely (once again, it is up to the designers to decide) be able to call back into the Java virtual machine and invoke a Java method. In this case, the thread leaves the native method stack and enters another Java stack.
  • Below Figure shows a graphical depiction of a thread that invokes a native method that calls back into the virtual machine to invoke another Java method. 
  • This figure shows the full picture of what a thread can expect inside the Java virtual machine. 
  • A thread may spend its entire lifetime executing Java methods, working with frames on its Java stack. Or, it may jump back and forth between the Java stack and native method stacks.
  • As depicted in Above Figure, a thread first invoked two Java methods, the second of which invoked a native method. 
  • This act caused the virtual machine to use a native method stack. In this figure, the native method stack is shown as a finite amount of contiguous memory space. Assume it is a C stack. 
  • The stack area used by each C-linkage function is shown in gray and bounded by a dashed line. 
  • The first C-linkage function, which was invoked as a native method, invoked another C-linkage function. 
  • The second C-linkage function invoked a Java method through the native method interface. This Java method invoked another Java method, which is the current method shown in the figure.
  • As with the other runtime memory areas, the memory they occupied by native method stacks need not be of a fixed size. 
  • It can expand and contract as needed by the running application. Implementations may allow users or programmers to specify an initial size for the method area, as well as a maximum or minimum size.
  • Execution Engine:
  • At the core of any Java virtual machine implementation is its execution engine. In the Java virtual machine specification, the behavior of the execution engine is defined in terms of an instruction set. 
  • For each instruction, the specification describes in detail what an implementation should do when it encounters the instruction as it executes bytecodes, but says very little about how. As mentioned in previous chapters, implementation designers are free to decide how their implementations will execute bytecodes. 
  • Their implementations can interpret, just-in-time compile, execute natively in silicon, use a combination of these, or dream up some brand new technique.
  • Similar to the three senses of the term "Java virtual machine" described at the beginning of this chapter, the term "execution engine" can also be used in any of three senses: an abstract specification, a concrete implementation, or a runtime instance. 
  • The abstract specification defines the behavior of an execution engine in terms of the instruction set. Concrete implementations, which may use a variety of techniques, are either software, hardware, or a combination of both. A runtime instance of an execution engine is a thread.
  • Each thread of a running Java application is a distinct instance of the virtual machine's execution engine. From the beginning of its lifetime to the end, a thread is either executing byte codes or native methods. 
  • A thread may execute byte codes directly, by interpreting or executing natively in silicon, or indirectly, by just- in-time compiling and executing the resulting native code. A Java virtual machine implementation may use other threads invisible to the running application, such as a thread that performs garbage collection. 
  • Such threads need not be "instances" of the implementation's execution engine. All threads that belong to the running application, however, are execution engines in action.

The Instruction Set:

  • A method's bytecode stream is a sequence of instructions for the Java virtual machine. Each instruction consists of a one-byteopcode followed by zero or more operands. 
  • The opcode indicates the operation to be performed. Operands supply extra information needed by the Java virtual machine to perform the operation specified by the opcode. The opcode itself indicates whether or not it is followed by operands, and the form the operands (if any) take. 
  • Many Java virtual machine instructions take no operands, and therefore consist only of an opcode. Depending upon the opcode, the virtual machine may refer to data stored in other areas in addition to (or instead of) operands that trail the opcode. 
  • When it executes an instruction, the virtual machine may use entries in the current constant pool, entries in the current frame's local variables, or values sitting on the top of the current frame's operand stack.
  • The abstract execution engine runs by executing bytecodes one instruction at a time. This process takes place for each thread (execution engine instance) of the application running in the Java virtual machine. 
  • An execution engine fetches an opcode and, if that opcode has operands, fetches the operands. It executes the action requested by the opcode and its operands, then fetches another opcode. 
  • Execution of byte codes continues until a thread completes either by returning from its starting method or by not catching a thrown exception.
  • From time to time, the execution engine may encounter an instruction that requests a native method invocation. 
  • On such occasions, the execution engine will dutifully attempt to invoke that native method. 
  • When the native method returns (if it completes normally, not by throwing an exception), the execution engine will continue executing the next instruction in the byte code stream.
  • One way to think of native methods, therefore, is as programmer-customized extensions to the Java virtual machine's instruction set. 
  • If an instruction requests an invocation of a native method, the execution engine invokes the native method. Running the native method is how the Java virtual machine executes the instruction. 
  • When the native method returns, the virtual machine moves on to the next instruction. If the native method completes abruptly (by throwing an exception), the virtual machine follows the same steps to handle the exception as it does when any instruction throws an exception.
  • Part of the job of executing an instruction is determining the next instruction to execute. An execution engine determines the next opcode to fetch in one of three ways. 
  • For many instructions, the next opcode to execute directly follows the current opcode and its operands, if any, in the bytecode stream. 
  • For some instructions, such as goto or return, the execution engine determines the next opcode as part of its execution of the current instruction. If an instruction throws an exception, the execution engine determines the next opcode to fetch by searching for an appropriate catch clause.
  • Several instructions can throw exceptions. The athrow instruction, for example, throws an exception explicitly. This instruction is the compiled form of the throw statement in Java source code. 
  • Every time the athrow instruction is executed, it will throw an exception. Other instructions throw exceptions only when certain conditions are encountered. For example, if the Java virtual machine discovers, to its chagrin, that the program is attempting to perform an integer divide by zero, 
  • It will throw anArithmeticException. This can occur while executing any of four instructions--idiv, ldiv, irem, and lrem--which perform divisions or calculate remainders on ints or longs.
  • Each type of opcode in the Java virtual machine's instruction set has a mnemonic. In the typical assembly language style, streams of Java bytecodes can be represented by their mnemonics followed by (optional) operand values.