Java News Brief        
                                                  February 2000 Issue                                        

Headlines: 
Java Technical Insight of the Month   -  
Inside the Java Virtual Machine
     Visit  The Java News Brief Archive for past issues of the JNB.
OCI Education Center - Open Enrollment Schedule
             
                
Java Technical Insight of the Month
 
What is the Java Virtual Machine?
By Ernest Rider, Senior Software Engineer, Object Computing, Inc.

The Java Virtual Machine (JVM), is the Sun Microsystems specification of a (emulated) virtual 32 bit processor, that directly supports the Java programming language.  The JVM executes operating system and hardware independent binary format bytecodes.  JVM's can currently execute 254 different types of "bytecodes" (virtual machine instructions).  Each bytecode is exactly one byte (8 bits). (bytecode 186 are unused)

What do bytecodes look like?

Well, they are all in binary format as we might expect.   Bytecodes exists to manipulate primitive types (byte, short, int, long, char, float, double, boolean, and JVM internal return address types) and reference types (Objects/Arrays).

All bytecodes look like this:

mnemonic <operand1>, <operand2>, ...... e.g. fadd

where mnemonic can be one of the pseudo codes in the table below:

bytecode
(Decimal)

bytecode (Hex)

Pseudo Code (Sun's Format)

bytecode
(Decimal)

bytecode (Hex)

Pseudo Code (Sun's Format)

bytecode
(Decimal)

bytecode (Hex)

Pseudo Code (Sun's Format)

0

(0x00)

nop

86

(0x56)

sastore

171

(0xab)

lookupswitch

1

(0x01)

aconst_null

87

(0x57)

pop

172

(0xac)

ireturn

2

(0x02)

iconst_m1

88

(0x58)

pop2

173

(0xad)

lreturn

3

(0x03)

iconst_0

89

(0x59)

dup

174

(0xae)

freturn

4

(0x04)

iconst_1

90

(0x5a)

dup_x1

175

(0xaf)

dreturn

5

(0x05)

iconst_2

91

(0x5b)

dup_x2

176

(0xb0)

areturn

6

(0x06)

iconst_3

92

(0x5c)

dup2

177

(0xb1)

return

7

(0x07)

iconst_4

93

(0x5d)

dup2_x1

178

(0xb2)

getstatic

8

(0x08)

iconst_5

94

(0x5e)

dup2_x2

179

(0xb3)

putstatic

9

(0x09)

lconst_0

95

(0x5f)

swap

180

(0xb4)

getfield

10

(0x0a)

lconst_1

96

(0x60)

iadd

181

(0xb5)

putfield

11

(0x0b)

fconst_0

97

(0x61)

ladd

182

(0xb6)

invokevirtual

12

(0x0c)

fconst_1

98

(0x62)

fadd

183

(0xb7)

invokespecial

13

(0x0d)

fconst_2

99

(0x63)

dadd

184

(0xb8)

invokestatic

14

(0x0e)

dconst_0

100

(0x64)

isub

185

(0xb9)

invokeinterface

15

(0x0f)

dconst_1

101

(0x65)

lsub

186

(0xba)

xxxunusedxxx

16

(0x10)

bipush

102

(0x66)

fsub

187

(0xbb)

new

17

(0x11)

sipush

103

(0x67)

dsub

188

(0xbc)

newarray

18

(0x12)

ldc

104

(0x68)

imul

189

(0xbd)

anewarray

19

(0x13)

ldc_w

105

(0x69)

lmul

190

(0xbe)

arraylength

20

(0x14)

ldc2_w

106

(0x6a)

fmul

191

(0xbf)

athrow

21

(0x15)

iload

107

(0x6b)

dmul

192

(0xc0)

checkcast

22

(0x16)

lload

108

(0x6c)

idiv

193

(0xc1)

instanceof

23

(0x17)

fload

109

(0x6d)

ldiv

194

(0xc2)

monitorenter

24

(0x18)

dload

100

(0x6e)

fdiv

195

(0xc3)

monitorexit

25

(0x19)

aload

111

(0x6f)

ddiv

196

(0xc4)

wide

26

(0x1a)

iload_0

112

(0x70)

irem

197

(0xc5)

multianewarray

27

(0x1b)

iload_1

113

(0x71)

lrem

198

(0xc6)

ifnull

28

(0x1c)

iload_2

114

(0x72)

frem

199

(0xc7)

ifnonnull

29

(0x1d)

iload_3

115

(0x73)

drem

200

(0xc8)

goto_w

30

(0x1e)

lload_0

116

(0x74)

ineg

201

(0xc9)

jsr_w

31

(0x1f)

lload_1

117

(0x75)

lneg

203

(0xcb)

ldc_quick

32

(0x20)

lload_2

118

(0x76)

fneg

204

(0xcc)

ldc_w_quick

33

(0x21)

lload_3

119

(0x77)

dneg

205

(0xcd)

ldc2_w_quick

34

(0x22)

fload_0

120

(0x78)

ishl

206

(0xce)

getfield_quick

35

(0x23)

fload_1

121

(0x79)

lshl

207

(0xcf)

putfield_quick

36

(0x24)

fload_2

122

(0x7a)

ishr

208

(0xd0)

getfield2_quick

37

(0x25)

fload_3

123

(0x7b)

lshr

209

(0xd1)

putfield2_quick

38

(0x26)

dload_0

124

(0x7c)

iushr

210

(0xd2)

getstatic_quick

39

(0x27)

dload_1

125

(0x7d)

lushr

211

(0xd3)

putstatic_quick

40

(0x28)

dload_2

126

(0x7e)

iand

212

(0xd4)

getstatic2_quick

41

(0x29)

dload_3

127

(0x7f)

land

213

(0xd5)

putstatic2_quick

42

(0x2a)

aload_0

128

(0x80)

ior

214

(0xd6)

invokevirtual_quick

43

(0x2b)

aload_1

129

(0x81)

lor

215

(0xd7)

invokenonvirtual_quick

44

(0x2c)

aload_2

130

(0x82)

ixor

216

(0xd8)

invokesuper_quick

45

(0x2d)

aload_3

131

(0x83)

lxor

217

(0xd9)

invokestatic_quick

46

(0x2e)

iaload

132

(0x84)

iinc

218

(0xda)

invokeinterface_quick

47

(0x2f)

laload

133

(0x85)

i2l

219

(0xdb)

invokevirtualobject_quick

48

(0x30)

faload

134

(0x86)

i2f

221

(0xdd)

new_quick

49

(0x31)

daload

135

(0x87)

i2d

222

(0xde)

anewarray_quick

50

(0x32)

aaload

136

(0x88)

l2i

223

(0xdf)

multianewarray_quick

51

(0x33)

baload

137

(0x89)

l2f

224

(0xe0)

checkcast_quick

52

(0x34)

caload

138

(0x8a)

l2d

225

(0xe1)

instanceof_quick

53

(0x35)

saload

139

(0x8b)

f2i

226

(0xe2)

invokevirtual_quick_w

54

(0x36)

istore

140

(0x8c)

f2l

227

(0xe3)

getfield_quick_w

55

(0x37)

lstore

141

(0x8d)

f2d

228

(0xe4)

putfield_quick_w

56

(0x38)

fstore

142

(0x8e)

d2i

202

(0xca)

breakpoint

57

(0x39)

dstore

143

(0x8f)

d2l

254

(0xfe)

impdep1

58

(0x3a)

astore

144

(0x90)

d2f

255

(0xff)

impdep2

59

(0x3b)

istore_0

145

(0x91)

i2b

 

 

 

60

(0x3c)

istore_1

146

(0x92)

i2c

 

 

 

61

(0x3d)

istore_2

147

(0x93)

i2s

 

 

 

62

(0x3e)

istore_3

148

(0x94)

lcmp

 

 

 

63

(0x3f)

lstore_0

149

(0x95)

fcmpl

 

 

 

64

(0x40)

lstore_1

150

(0x96)

fcmpg

 

 

 

65

(0x41)

lstore_2

151

(0x97)

dcmpl

 

 

 

66

(0x42)

lstore_3

152

(0x98)

dcmpg

 

 

 

67

(0x43)

fstore_0

153

(0x99)

ifeq

 

 

 

68

(0x44)

fstore_1

154

(0x9a)

ifne

 

 

 

69

(0x45)

fstore_2

155

(0x9b)

iflt

 

 

 

70

(0x46)

fstore_3

156

(0x9c)

ifge

 

 

 

71

(0x47)

dstore_0

157

(0x9d)

ifgt

 

 

 

72

(0x48)

dstore_1

158

(0x9e)

ifle

 

 

 

73

(0x49)

dstore_2

159

(0x9f)

if_icmpeq

 

 

 

74

(0x4a)

dstore_3

160

(0xa0)

if_icmpne

 

 

 

75

(0x4b)

astore_0

161

(0xa1)

if_icmplt

 

 

 

76

(0x4c)

astore_1

162

(0xa2)

if_icmpge

 

 

 

77

(0x4d)

astore_2

163

(0xa3)

if_icmpgt

 

 

 

78

(0x4e)

astore_3

164

(0xa4)

if_icmple

 

 

 

79

(0x4f)

iastore

165

(0xa5)

if_acmpeq

 

 

 

80

(0x50)

lastore

166

(0xa6)

if_acmpne

 

 

 

81

(0x51)

fastore

167

(0xa7)

goto

 

 

 

82

(0x52)

dastore

168

(0xa8)

jsr

 

 

 

83

(0x53)

aastore

169

(0xa9)

ret

 

 

 

84

(0x54)

bastore

170

(0xaa)

tableswitch

 

 

 

85

(0x55)

castore

 

 

 

 

 

 


Can other languages produce Java-byte code?

In Short.  Yes!

Does this mean we don't have to write in Java to get "bytecode" portability?   Well that's one for debate.   All I can say is that you get the wealth of a pure object orientated language in Java; some of the best minds fixing/enhancing the technology, and some really nice frameworks that other languages are struggling to match.  i.e. the Java Language embodies a design thought process,  that is conducive to good OOP Practices.


What makes up a JVM?

  1.  A fetch, decode, execute module.

    This is really the heart of a JVM implementation.  It mimics a "real" machines fetch, decode and execute cycles.  The module will usually consist of a program counter PC (32 bits).   All other registers are not stipulated by the JVM specification, since many different architectures have different register capabilities that can be best exploited without adhering to a strict architecture.
      
     
  2. A Stack per Thread. 

    The JVM Stack is a Last In-First Out (LIFO) stack that stores Frame's.  A Frame is a local block workspace, usually directly related to code that appears between "{"...."}" block specifiers.  In a REAL machine a frame is analogous to a a set of local block variables from the last Base Pointer BP to the current SP Stack Pointer.  During simulated multitasking (Single Processor) the fetch, decode, execute cycle the JVM can switch between stacks saving, and restoring the PC and any implementation registers, in some machines this is done preemptively (forced)  and in others each must yield to another.

  3. Heap 

    The Java Heap is shared across all threads.  The heap contains dynamic Object references, including dynamically constructed Objects/Methods.   

  4. Method area. 

    All compiled class/object methods are stored here. (Dynamic objects created at run time are stored in the heap and are exposed to the garbage collector.)

  5. Constant pool. 

    Holds all the constants referenced by the system.  Some constants may be propagated through the bytecode in implementations.

  6. Native method stack.

    A stack for which native methods can accept parameters from the JVM and return parameters to the JVM.  Some JVM's parse parameters using a 3rd party Native Language framework, such as RNI/COM in the Microsoft VM.

  7. Garbage Collector.

    A Thread or Process that at determines whether Heap references have lost their Parent/Creator Object and are thus marked dirty for removal.   The Garbage collector is quite efficient despite the absence of a "C++" like "delete" operator.

  8. bytecode Verifier.

    The bytecode verification process both complicated and sophisticated,  perhaps the most sophisticated part a a JVM implementation.     It addresses the concerns that bytecodes may do damage to a system by running amok on a given hardware architecture.   Sun's JVM Verifies bytecodes are well-formed before executing them.  This involves making sure all exceptions are caught,  no overflows etc.....      Some JVM's check while executing the bytecodes which can be expensive for performance.

  9. Other Advanced Features.

    As Java Compiler technology improves, the separation of the JVM and the "real" machine gets narrower and narrower.   Just In Time (JIT) Compilation has become a key technology for improving JVM performance Ten fold.   A typical JIT will pre-optimise method bytecode's into native blocks ready to run on demand.  (Some JIT's use the native method stack, to invoke native methods.) 

    Implicit parallel computing support through the Java threading model is also making positive gains.   

    It is the authors opinion that through such research and development some JVM's may be able to operate as real time systems, despite the use of bytecode binaries.

Show us a program in bytecodes!

Example:

public class Person {

	String name = "Unknown";

	public void setName(String n) {
		name = n;
	}

	public String getName() {
		return(name);
	}

	public static void main(String args[]) {
		Person p = new Person();
		p.setName(args[0]);
		System.out.println("The name of the person entered was "+p.getName()+".");
	}
}

Using the command line java decompiler tool javap we can get the bytecode in pseudo ops ("-c") and the line numbers in the heap where they are stored ("-l").

C:\>javac Person.java
C:\>javap -c -l Person


Compiled from Person.java
public synchronized class Person extends java.lang.Object 
    /* ACC_SUPER bit set */
{
    java.lang.String name;
    public void setName(java.lang.String);
    public java.lang.String getName();
    public static void main(java.lang.String[]);
    public Person();
}

Method void setName(java.lang.String)
   0 aload_0
   1 aload_1
   2 putfield #14 -Field java.lang.String name-
   5 return

Line numbers for method void setName(java.lang.String)
   line 6: 0
   line 5: 5

Method java.lang.String getName()
   0 aload_0
   1 getfield #14 -Field java.lang.String name-
   4 areturn

Line numbers for method java.lang.String getName()
   line 10: 0

Method void main(java.lang.String[])
   0 new #4 -Class Person-
   3 dup
   4 invokespecial #9 -Method Person()-
   7 astore_1
   8 aload_1
   9 aload_0
  10 iconst_0
  11 aaload
  12 invokevirtual #17 -Method void setName(java.lang.String)-
  15 getstatic #15 -Field java.io.PrintStream out-
  18 new #7 -Class java.lang.StringBuffer-
  21 dup
  22 ldc #2 -String "The name of the person entered was "-
  24 invokespecial #11 -Method java.lang.StringBuffer(java.lang.String)-
  27 aload_1
  28 invokevirtual #13 -Method java.lang.String getName()-
  31 invokevirtual #12 -Method java.lang.StringBuffer append(java.lang.String)-
  34 ldc #1 -String "."-
  36 invokevirtual #12 -Method java.lang.StringBuffer append(java.lang.String)-
  39 invokevirtual #18 -Method java.lang.String toString()-
  42 invokevirtual #16 -Method void println(java.lang.String)-
  45 return

Line numbers for method void main(java.lang.String[])
   line 14: 0
   line 15: 8
   line 16: 15
   line 13: 45

Method Person()
   0 aload_0
   1 invokespecial #10 -Method java.lang.Object()-
   4 aload_0
   5 ldc #3 -String "Unknown"-
   7 putfield #14 -Field java.lang.String name-
  10 return

Line numbers for method Person()
   line 1: 0
   line 3: 4
   line 1: 10

How safe is my Java bytecode from Reverse Engineering?

Not very safe out-of-the-box.   Many products exist to make the job of decompiling exponentially harder (closer to near impossible) through obfuscation. (obfuscate.  To make so confused or opaque as to be difficult to perceive or understand)

An interesting article about finding similarities in bytecode can be found at http://glimpse.cs.arizona.edu/javadup.html
 

How to measure the performance of a JVM?

Just like testing "real" machine performance, JVM performance is an open-ended battle. Claim and counter claim over who's has the best JVM could go on forever.  This goes to show that computer people are very passionate people when it comes to issues such as performance.

"Performance means many things to many different applications."

So how do we meaningfully test performance?  Well first you must accept that the 90/10 rule applies in general, i.e. 90% of the time is spent in 10% of the code, for a given unit.  Then we must construct applications that typify our purpose or goal. Then we do some real time analysis.  (Using a Java Thread to time ourselves is not good enough, as JVM's are for the most part, non-real time.)  Fortunately the confusion over testing JVM performance has been confronted by the Java community.  In an effort to gain a useful comparison of JVM's a set of application performance benchmarks have been adopted (sometimes to suite the implementor).  It is very important that when using these tools the results have relevance to your needs. i.e. testing Thread performance may not give you great graphics.

Some useful ones:

Name Proprietor Description
CaffieneMark 3.0 Pendragon Software

http://www.pendragon-software.com/company.html

SpecJVM98 Spec http://www.spec.org/
JMark ZDNET http://www.zdnet.com/zdbop/jmark/jmark.html
VolanoMark volano http://www.volano.com/benchmarks.html

The future of the JVM?

The future the Java Virtual Machine centers quite firmly - around increasing its performance on any given architecture. Researchers and developers will continue to peel away at its virtual'ness and add more and more real machine code while keeping the bytecode source intact.  Many different architectures, and frameworks will be added to aid industry in making open choices to technology.  Hardware architectures that are bytecode compatible are going to break performance ground earlier than software, but the holy grail is the hybrid interpreted/native compiler. This will continue to be developed and influence the ever increasing demand on performance software technology.
 

Interesting Articles on issues discussed.


OCI Education Center - Open Enrollment Schedule
Mesa, Arizona - St. Louis, Missouri

Course Title Facility Dates Hours
Using the ADAPTIVE Communication Environment C++ Framework St. Louis Mar 7-10 8:30-3:30
CORBA Programming Mesa Mar 28-31 8:30-3:30

For more information or to register, email training.

Object Computing, Inc. is a Sun Authorized Java Center in St. Louis and a Member of the Object Management Group, OMG.  OCI specializes in distributed computing using object-oriented and web-enabled technologies and provides Consulting, Education, and Product Development services to clients nation-wide.  For more information contact us at 314-579-0066 or email info.

For employment opportunities at OCI call 1-888-962-4624 or email hr.

The Java News Brief is a monthly newsletter.  The purpose and intent of this publication is to advance Java, provide technical value, and to announce available OCI Java services.  If you would prefer to not receive this newsletter or would like to subscribe please email JNB and enter SUBSCRIBE or UNSUBSCRIBE within the Subject line.

Copyright (c) 2000.  Object Computing, Inc.   All rights reserved.   Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.  Object Computing, Inc. is independent of Sun Microsystems, Inc.