• 沒有找到結果。

Chapter 2 Background

2.1 Java Technology

Although generally used to refer to a computer language, Java is a rather a complete architecture in reality. It consists of four distinct but interrelated components [8].

• Java programming language

• Java class file format

• Java Application Programming Interface (Java API)

• Java Virtual Machine (JVM)

A Java program is written in Java programming language, and then compiled into Java class files by Java source compiler. Java class files can be executed on any environment that equips a JVM. Also, the Java program can access predefined libraries or system resources (such as I/O, for example) by calling methods in the classes that implement the Java API. During program execution, JVM loads and executes user-written class files as well as these system classes that Java API defines.

2.1.1 JVM Benefits

Java Virtual Machine is definitely the key component among the all. It is responsible for the well-known advantages that Java possesses over traditional native execution sys-tem. Those advantages include:

• Cross-Platform Portabilty

Each type of processor has its unique instruction set. For example, the instruction set of x86 is not compatible with that of MIPS. Moreover, each operating system (OS) has its own application interface or system calls to upper application programs. As a result, programs compiled to run on one platform (combination of processor and OS) cannot be executed on others without recompilation. Java overcomes this limitation by inserting JVM between the application programs and the real environment. If JVM has been ported to the environment, Java programs can be first compiled to Java bytecode in the form of class files and then be executed over the JVM without any porting efforts. This encourages software reuse and alleviates great pains from programmers.

• Security of the Execution Environment

One of Java’s original intention is its integration into the network environment. In this environment, class files can be automatically downloaded from network and be locally exe-cuted. They might be malicious and might do dangerous operations to the local execution system. To deal with this important issue, Java build up its own security model - the sand-box [9][10]. As a brief explanation, Java verifies every class file from untrusted resources.

The verification process mainly involves two steps in JVM. First, class file verification checks the layout and the contents of the class file. Second, bytecode verification checks if the bytecode within a method adheres to predefined rules. For example, one basic rule is that all goto and branch instructions refer to valid bytecode addresses.

• Small Size of the Compiled Code

Due to the rich semantics and the stack-based operations, Java bytecode, the instruction set of JVM, is more compact space-wise than a statically compiled program. In other words, Java has high code density. According to [11], the dynamic average instruction size is 1.8 bytes. Compared with typical RISC instruction requiring 4 bytes, this result is satis-factory. For a speed-limited network environment or a memory constrained embedded

environment, small code size is undoubtedly favorable.

2.1.2 JVM Internals

Figure 2-1. JVM Runtime Environment

To realize the JVM, an implementation must provide the functionality of a real proces-sor and also adhere to the JVM specification [12]. The specification defines a homogeneous run-time environment, as Figure 2-1 illustrates, by providing a detailed description of the following items:

• Instruction Set (Java Bytecode)

• Register Set

• Java Stack

• Execution Environment

• Constant Pool

• Method Area

• Java Heap

• Object Management and Garbage Collection Java Heap

Constant Pool

Method Area

Register Set

Java Stack

Frame per

class

per thread global

Since the JVM is a stack-based architecture, the registers of its register set are not used for storing operands or passing arguments as in most register-based machine. They only hold the state of the JVM and are updated after every bytecode instruction is executed.

The operands of a bytecode instruction must be pushed onto the Java stack before the instruction is executed. An executing instruction consumes its operands from the stack and then places results on the stack when it completes.

The execution environment is maintained within the Java stack as a data set and is used to deal with dynamic linkage, method invocation/return and exception handling. It handles dynamic linkage by maintaining symbolic references to methods and variables for the cur-rent method and curcur-rent class. A symbol table is used to translate these references to actual calls.

The JVM maintains a special table for each class, known as a constant pool. The con-stant pool contains string literals, class names, field names and other concon-stant data objects that are referred to by the class structure or by the executing program. These constants do not change, and are created at compile-time. Items in the constant pool encode all names used by any method in a particular class. The information included in a class is the number of constants and the offset that specifies where a particular list of constants begin in the class description.

The method area is equivalent to the compiled code areas in the run-time environment used by other programming language. It contains bytecode instructions that are associated with the methods in the compiled code and the symbol table needed for dynamic linkage.

The Java heap is the dynamic memory of JVM, and it usually contains a collection of objects. When an object is created with the “new” bytecode instruction, an reference to that object is returned. This reference can be used subsequently, or stored in the current frame.

An object persists in Java heap until there are no references to it in any frame of the frame stack or in the constant pool of any visible object. When there are no such references, an object becomes garbage, and a special garbage collector will reclaim its resources.

2.1.3 JVM Implementation Alternatives

The JVM is not restricted to software interpreter implementation. In fact, there are three common approaches, as depicted in Figure 2-2, to implement the JVM.

Figure 2-2. Three Alternatives to Executing Java Programs (extracted and modified from [13])

Interpreting the bytecode, the standard way to implement the JVM, has the advantage of fast JVM porting but makes the execution of Java programs relatively slow. One solution to improve speed performance is to replace an interpreter with a bytecode compiler. The bytecode compiler is responsible for translating bytecode into native machine code. While ahead-of-time (AOT) compilers performs offline compilation statically as conventional compilers, just-in-time (JIT) compilers performs on-the-fly compilation dynamically. Both of them have pros and cons, but JIT compilers seem to be more appealing to most research-ers. Another solution is to implement the JVM directly on silicon. For example, picoJava is a Java processor that supports bytecode execution completely.

As discussed in Section 1.2, an interpreter can still coexist and cooperate with a JIT compiler in the JVM. Recently, a mixed software/hardware approach also comes to exist.

ARM has introduced its own Java instruction extension - Jazelle [14]. A subset of bytecode Java Program

instructions can be directly executed when the ARM processor is operated in Java mode, and the remaining bytecode instructions are still handled in software (interpreted or com-piled).

相關文件