KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > bytecode > ByteCodeParser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.bytecode;
31
32 import com.caucho.log.Log;
33 import com.caucho.util.CharBuffer;
34 import com.caucho.util.L10N;
35
36 import java.io.IOException JavaDoc;
37 import java.io.InputStream JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40
41 /**
42  * Interface to the bytecode parser.
43  */

44 public class ByteCodeParser {
45   private static final Logger JavaDoc log = Log.open(ByteCode.class);
46   private static final L10N L = new L10N(ByteCode.class);
47
48   static final int CP_CLASS = 7;
49   static final int CP_FIELD_REF = 9;
50   static final int CP_METHOD_REF = 10;
51   static final int CP_INTERFACE_METHOD_REF = 11;
52   static final int CP_STRING = 8;
53   static final int CP_INTEGER = 3;
54   static final int CP_FLOAT = 4;
55   static final int CP_LONG = 5;
56   static final int CP_DOUBLE = 6;
57   static final int CP_NAME_AND_TYPE = 12;
58   static final int CP_UTF8 = 1;
59
60   private JavaClassLoader _loader;
61   private InputStream JavaDoc _is;
62   private JavaClass _class;
63   private ConstantPool _cp;
64
65   /**
66    * Sets the JClassLoader
67    */

68   public void setClassLoader(JavaClassLoader loader)
69   {
70     _loader = loader;
71   }
72
73   /**
74    * Sets the class.
75    */

76   public void setJavaClass(JavaClass javaClass)
77   {
78     _class = javaClass;
79   }
80   
81   /**
82    * Parses the .class file.
83    */

84   public JavaClass parse(InputStream JavaDoc is)
85     throws IOException JavaDoc
86   {
87     _is = is;
88
89     if (_loader == null)
90       _loader = new JavaClassLoader();
91     
92     if (_class == null)
93       _class = new JavaClass(_loader);
94
95     _cp = _class.getConstantPool();
96     
97     parseClass();
98
99     return _class;
100   }
101
102   /**
103    * Returns the constant pool.
104    */

105   public ConstantPool getConstantPool()
106   {
107     return _cp;
108   }
109
110   /**
111    * Returns a UTF8 String from the constant pool.
112    */

113   public String JavaDoc getUTF8(int index)
114   {
115     return getConstantPool().getUtf8AsString(index);
116   }
117
118   /**
119    * Parses the ClassFile construct
120    */

121   private void parseClass()
122     throws IOException JavaDoc
123   {
124     int magic = readInt();
125
126     if (magic != JavaClass.MAGIC)
127       throw error(L.l("bad magic number in class file"));
128
129     int minor = readShort();
130     int major = readShort();
131
132     _class.setMajor(major);
133     _class.setMinor(minor);
134
135     parseConstantPool();
136
137     int accessFlags = readShort();
138     _class.setAccessFlags(accessFlags);
139
140     int thisClassIndex = readShort();
141     _class.setThisClass(_cp.getClass(thisClassIndex).getName());
142     
143     int superClassIndex = readShort();
144     if (superClassIndex > 0)
145       _class.setSuperClass(_cp.getClass(superClassIndex).getName());
146
147     int interfaceCount = readShort();
148     for (int i = 0; i < interfaceCount; i++) {
149       int classIndex = readShort();
150
151       _class.addInterface(_cp.getClass(classIndex).getName());
152     }
153
154     int fieldCount = readShort();
155     for (int i = 0; i < fieldCount; i++) {
156       parseField();
157     }
158
159     int methodCount = readShort();
160     for (int i = 0; i < methodCount; i++)
161       parseMethod();
162
163     int attrCount = readShort();
164     for (int i = 0; i < attrCount; i++) {
165       Attribute attr = parseAttribute();
166
167       _class.addAttribute(attr);
168     }
169   }
170
171   /**
172    * Parses the constant pool.
173    */

174   public void parseConstantPool()
175     throws IOException JavaDoc
176   {
177     int count = readShort();
178
179     for (int i = 1; i < count; i++) {
180       ConstantPoolEntry entry = parseConstantPoolEntry(i);
181
182       _cp.addConstant(entry);
183       
184       if (entry instanceof DoubleConstant ||
185       entry instanceof LongConstant) {
186     i++;
187     _cp.addConstant(null);
188       }
189     }
190   }
191
192   /**
193    * Parses a constant pool entry.
194    */

195   private ConstantPoolEntry parseConstantPoolEntry(int index)
196     throws IOException JavaDoc
197   {
198     int tag = read();
199
200     switch (tag) {
201     case CP_CLASS:
202       return parseClassConstant(index);
203       
204     case CP_FIELD_REF:
205       return parseFieldRefConstant(index);
206       
207     case CP_METHOD_REF:
208       return parseMethodRefConstant(index);
209       
210     case CP_INTERFACE_METHOD_REF:
211       return parseInterfaceMethodRefConstant(index);
212       
213     case CP_STRING:
214       return parseStringConstant(index);
215       
216     case CP_INTEGER:
217       return parseIntegerConstant(index);
218       
219     case CP_FLOAT:
220       return parseFloatConstant(index);
221       
222     case CP_LONG:
223       return parseLongConstant(index);
224       
225     case CP_DOUBLE:
226       return parseDoubleConstant(index);
227       
228     case CP_NAME_AND_TYPE:
229       return parseNameAndTypeConstant(index);
230       
231     case CP_UTF8:
232       return parseUtf8Constant(index);
233
234     default:
235       throw error(L.l("'{0}' is an unknown constant pool type.",
236               tag));
237     }
238   }
239
240   /**
241    * Parses a class constant pool entry.
242    */

243   private ClassConstant parseClassConstant(int index)
244     throws IOException JavaDoc
245   {
246     int nameIndex = readShort();
247
248     return new ClassConstant(_class.getConstantPool(), index, nameIndex);
249   }
250
251   /**
252    * Parses a field ref constant pool entry.
253    */

254   private FieldRefConstant parseFieldRefConstant(int index)
255     throws IOException JavaDoc
256   {
257     int classIndex = readShort();
258     int nameAndTypeIndex = readShort();
259
260     return new FieldRefConstant(_class.getConstantPool(), index,
261                 classIndex, nameAndTypeIndex);
262   }
263
264   /**
265    * Parses a method ref constant pool entry.
266    */

267   private MethodRefConstant parseMethodRefConstant(int index)
268     throws IOException JavaDoc
269   {
270     int classIndex = readShort();
271     int nameAndTypeIndex = readShort();
272
273     return new MethodRefConstant(_class.getConstantPool(), index,
274                  classIndex, nameAndTypeIndex);
275   }
276
277   /**
278    * Parses an interface method ref constant pool entry.
279    */

280   private InterfaceMethodRefConstant parseInterfaceMethodRefConstant(int index)
281     throws IOException JavaDoc
282   {
283     int classIndex = readShort();
284     int nameAndTypeIndex = readShort();
285
286     return new InterfaceMethodRefConstant(_class.getConstantPool(), index,
287                       classIndex, nameAndTypeIndex);
288   }
289
290   /**
291    * Parses a string constant pool entry.
292    */

293   private StringConstant parseStringConstant(int index)
294     throws IOException JavaDoc
295   {
296     int stringIndex = readShort();
297
298     return new StringConstant(_class.getConstantPool(), index, stringIndex);
299   }
300
301   /**
302    * Parses an integer constant pool entry.
303    */

304   private IntegerConstant parseIntegerConstant(int index)
305     throws IOException JavaDoc
306   {
307     int value = readInt();
308
309     return new IntegerConstant(_class.getConstantPool(), index, value);
310   }
311
312   /**
313    * Parses a float constant pool entry.
314    */

315   private FloatConstant parseFloatConstant(int index)
316     throws IOException JavaDoc
317   {
318     int bits = readInt();
319
320     float value = Float.intBitsToFloat(bits);
321
322     return new FloatConstant(_class.getConstantPool(), index, value);
323   }
324
325   /**
326    * Parses a long constant pool entry.
327    */

328   private LongConstant parseLongConstant(int index)
329     throws IOException JavaDoc
330   {
331     long value = readLong();
332
333     return new LongConstant(_class.getConstantPool(), index, value);
334   }
335
336   /**
337    * Parses a double constant pool entry.
338    */

339   private DoubleConstant parseDoubleConstant(int index)
340     throws IOException JavaDoc
341   {
342     long bits = readLong();
343
344     double value = Double.longBitsToDouble(bits);
345
346     return new DoubleConstant(_class.getConstantPool(), index, value);
347   }
348
349   /**
350    * Parses a name and type pool entry.
351    */

352   private NameAndTypeConstant parseNameAndTypeConstant(int index)
353     throws IOException JavaDoc
354   {
355     int nameIndex = readShort();
356     int descriptorIndex = readShort();
357
358     return new NameAndTypeConstant(_class.getConstantPool(), index,
359                    nameIndex, descriptorIndex);
360   }
361
362   /**
363    * Parses a utf-8 constant pool entry.
364    */

365   private Utf8Constant parseUtf8Constant(int index)
366     throws IOException JavaDoc
367   {
368     int length = readShort();
369     
370     CharBuffer cb = CharBuffer.allocate();
371
372     for (int i = 0; i < length; i++) {
373       int ch = read();
374
375       if (ch < 0x80) {
376     cb.append((char) ch);
377       }
378       else if ((ch & 0xe0) == 0xc0) {
379     int ch2 = read();
380     i++;
381
382     cb.append((char) (((ch & 0x1f) << 6)+
383               (ch2 & 0x3f)));
384       }
385       else {
386     int ch2 = read();
387     int ch3 = read();
388     i += 2;
389       
390     cb.append((char) (((ch & 0xf) << 12)+
391               ((ch2 & 0x3f) << 6) +
392               ((ch3 & 0x3f))));
393       }
394     }
395
396     return new Utf8Constant(_class.getConstantPool(), index, cb.close());
397   }
398
399   /**
400    * Parses a field entry.
401    */

402   private void parseField()
403     throws IOException JavaDoc
404   {
405     int accessFlags = readShort();
406     int nameIndex = readShort();
407     int descriptorIndex = readShort();
408
409     JavaField field = new JavaField();
410     field.setJavaClass(_class);
411     field.setName(_cp.getUtf8(nameIndex).getValue());
412     field.setDescriptor(_cp.getUtf8(descriptorIndex).getValue());
413     field.setAccessFlags(accessFlags);
414
415     int attributesCount = readShort();
416
417     for (int i = 0; i < attributesCount; i++) {
418       Attribute attr = parseAttribute();
419
420       field.addAttribute(attr);
421     }
422
423     _class.addField(field);
424   }
425
426   /**
427    * Parses a method entry.
428    */

429   private void parseMethod()
430     throws IOException JavaDoc
431   {
432     int accessFlags = readShort();
433     int nameIndex = readShort();
434     int descriptorIndex = readShort();
435
436     JavaMethod method = new JavaMethod(_loader);
437     method.setJavaClass(_class);
438     method.setName(_cp.getUtf8(nameIndex).getValue());
439     method.setDescriptor(_cp.getUtf8(descriptorIndex).getValue());
440     method.setAccessFlags(accessFlags);
441
442     int attributesCount = readShort();
443
444     for (int i = 0; i < attributesCount; i++) {
445       Attribute attr = parseAttribute();
446
447       method.addAttribute(attr);
448       
449       if (attr instanceof ExceptionsAttribute) {
450     ExceptionsAttribute exn = (ExceptionsAttribute) attr;
451
452     ArrayList JavaDoc<String JavaDoc> exnNames = exn.getExceptionList();
453
454     if (exnNames.size() > 0) {
455       JClass []exnClasses = new JClass[exnNames.size()];
456
457       for (int j = 0; j < exnNames.size(); j++) {
458         String JavaDoc exnName = exnNames.get(j).replace('/', '.');
459       
460         exnClasses[j] = _loader.forName(exnName);
461       }
462
463       method.setExceptionTypes(exnClasses);
464     }
465       }
466     }
467
468     _class.addMethod(method);
469   }
470
471   /**
472    * Parses an attribute.
473    */

474   Attribute parseAttribute()
475     throws IOException JavaDoc
476   {
477     int nameIndex = readShort();
478
479     String JavaDoc name = _cp.getUtf8(nameIndex).getValue();
480
481     if (name.equals("Code")) {
482       CodeAttribute code = new CodeAttribute(name);
483       code.read(this);
484       return code;
485     }
486     else if (name.equals("Exceptions")) {
487       ExceptionsAttribute code = new ExceptionsAttribute(name);
488       code.read(this);
489       return code;
490     }
491     else if (name.equals("Signature")) {
492       SignatureAttribute code = new SignatureAttribute();
493       code.read(this);
494       return code;
495     }
496     
497     OpaqueAttribute attr = new OpaqueAttribute(name);
498     
499     int length = readInt();
500
501     byte []bytes = new byte[length];
502     
503     read(bytes, 0, bytes.length);
504
505     attr.setValue(bytes);
506
507     return attr;
508   }
509
510   /**
511    * Parses a 64-bit int.
512    */

513   long readLong()
514     throws IOException JavaDoc
515   {
516     return (((long) _is.read() << 56) |
517         ((long) _is.read() << 48) |
518         ((long) _is.read() << 40) |
519         ((long) _is.read() << 32) |
520         ((long) _is.read() << 24) |
521         ((long) _is.read() << 16) |
522         ((long) _is.read() << 8) |
523         ((long) _is.read()));
524   }
525
526   /**
527    * Parses a 32-bit int.
528    */

529   int readInt()
530     throws IOException JavaDoc
531   {
532     return ((_is.read() << 24) |
533         (_is.read() << 16) |
534         (_is.read() << 8) |
535         (_is.read()));
536   }
537
538   /**
539    * Parses a 16-bit int.
540    */

541   int readShort()
542     throws IOException JavaDoc
543   {
544     int c1 = _is.read();
545     int c2 = _is.read();
546
547     return ((c1 << 8) | c2);
548   }
549
550   /**
551    * Parses a byte
552    */

553   int read()
554     throws IOException JavaDoc
555   {
556     return _is.read();
557   }
558
559   /**
560    * Reads a chunk
561    */

562   int read(byte []buffer, int offset, int length)
563     throws IOException JavaDoc
564   {
565     int readLength = 0;
566     
567     while (length > 0) {
568       int sublen = _is.read(buffer, offset, length);
569
570       if (sublen < 0)
571     return readLength == 0 ? -1 : readLength;
572
573       offset += sublen;
574       length -= sublen;
575       readLength += sublen;
576     }
577
578     return readLength;
579   }
580
581   /**
582    * Returns an error message.
583    */

584   private IOException JavaDoc error(String JavaDoc message)
585   {
586     return new IOException JavaDoc(message);
587   }
588 }
589
Popular Tags