001 package AST; 002 003 import java.util.HashSet; 004 import java.io.File; 005 import java.util.*; 006 import beaver.*; 007 import java.util.ArrayList; 008 import java.util.zip.*; 009 import java.io.*; 010 import java.io.FileNotFoundException; 011 import java.util.Collection; 012 /** 013 * @ast class 014 * 015 */ 016 public class BytecodeParser extends java.lang.Object implements Flags, BytecodeReader { 017 018 public CompilationUnit read(InputStream is, String fullName, Program p) throws FileNotFoundException, IOException { 019 return new BytecodeParser(is, fullName).parse(null, null, p); 020 } 021 022 023 024 public static final boolean VERBOSE = false; 025 026 027 028 private DataInputStream is; 029 030 031 public CONSTANT_Class_Info classInfo; 032 033 034 public String outerClassName; 035 036 037 public String name; 038 039 040 041 public BytecodeParser(byte[] buffer, int size, String name) { 042 //this.is = new DataInputStream(new DummyInputStream(buffer, size)); 043 this.is = new DataInputStream(new ByteArrayInputStream(buffer, 0, size)); 044 this.name = name; 045 } 046 047 048 public BytecodeParser(InputStream in, String name) { 049 //this.is = new DataInputStream(new DummyInputStream(buffer, size)); 050 this.is = new DataInputStream(new DummyInputStream(in)); 051 this.name = name; 052 } 053 054 055 056 public BytecodeParser() { 057 this(""); 058 } 059 060 061 public BytecodeParser(String name) { 062 if (!name.endsWith(".class")) { 063 //name = name.replaceAll("\\.", "/") + ".class"; 064 name = name.replace('.', '/') + ".class"; 065 } 066 this.name = name; 067 } 068 069 070 071 private static class DummyInputStream extends InputStream { 072 byte[] bytes; 073 int pos; 074 int size; 075 public DummyInputStream(byte[] buffer, int size) { 076 bytes = buffer; 077 this.size = size; 078 } 079 public DummyInputStream(InputStream is) { 080 bytes = new byte[1024]; 081 int index = 0; 082 size = 1024; 083 try { 084 int status; 085 do { 086 status = is.read(bytes, index, size - index); 087 if(status != -1) { 088 index += status; 089 if(index == size) { 090 byte[] newBytes = new byte[size*2]; 091 System.arraycopy(bytes, 0, newBytes, 0, size); 092 bytes = newBytes; 093 size *= 2; 094 } 095 } 096 } while (status != -1); 097 } catch (IOException e) { 098 System.err.println("Something went wrong trying to read " + is); 099 //System.exit(1); 100 } 101 size = index; 102 pos = 0; 103 } 104 105 public int available() { 106 return size - pos; 107 } 108 109 public void close() { 110 } 111 112 public void mark(int readlimit) { 113 } 114 115 public boolean markSupported() { 116 return false; 117 } 118 119 public int read(byte[] b) { 120 int actualLength = Math.min(b.length, size-pos); 121 System.arraycopy(bytes, pos, b, 0, actualLength); 122 pos += actualLength; 123 return actualLength; 124 } 125 126 public int read(byte[] b, int offset, int length) { 127 int actualLength = Math.min(length, size-pos); 128 System.arraycopy(bytes, pos, b, offset, actualLength); 129 pos += actualLength; 130 return actualLength; 131 } 132 133 public void reset() { 134 } 135 136 public long skip(long n) { 137 if(size == pos) 138 return -1; 139 long skipSize = Math.min(n, size-pos); 140 pos += skipSize; 141 return skipSize; 142 } 143 144 public int read() throws IOException { 145 if(pos < size) { 146 int i = bytes[pos++]; 147 if(i < 0) 148 i = 256 + i; 149 return i; 150 } 151 return -1; 152 } 153 } 154 155 156 157 public int next() { 158 try { 159 return is.read(); 160 } catch (IOException e) { 161 System.exit(1); 162 } 163 return -1; 164 } 165 166 167 168 public int u1() { 169 try { 170 return is.readUnsignedByte(); 171 } catch (IOException e) { 172 System.exit(1); 173 } 174 return -1; 175 } 176 177 178 179 public int u2() { 180 try { 181 return is.readUnsignedShort(); 182 } catch (IOException e) { 183 System.exit(1); 184 } 185 return -1; 186 } 187 188 189 190 public int u4() { 191 try { 192 return is.readInt(); 193 } catch (IOException e) { 194 System.exit(1); 195 } 196 return -1; 197 } 198 199 200 201 public int readInt() { 202 try { 203 return is.readInt(); 204 } catch (IOException e) { 205 System.exit(1); 206 } 207 return -1; 208 } 209 210 211 212 public float readFloat() { 213 try { 214 return is.readFloat(); 215 } catch (IOException e) { 216 System.exit(1); 217 } 218 return -1; 219 } 220 221 222 223 public long readLong() { 224 try { 225 return is.readLong(); 226 } catch (IOException e) { 227 System.exit(1); 228 } 229 return -1; 230 } 231 232 233 234 public double readDouble() { 235 try { 236 return is.readDouble(); 237 } catch (IOException e) { 238 System.exit(1); 239 } 240 return -1; 241 } 242 243 244 245 public String readUTF() { 246 try { 247 return is.readUTF(); 248 } catch (IOException e) { 249 System.exit(1); 250 } 251 return ""; 252 } 253 254 255 256 public void skip(int length) { 257 try { 258 is.skip(length); 259 } catch (IOException e) { 260 System.exit(1); 261 } 262 } 263 264 265 266 public void error(String s) { 267 throw new RuntimeException(s); 268 } 269 270 271 272 public void print(String s) { 273 //System.out.print(s); 274 } 275 276 277 278 public void println(String s) { 279 print(s + "\n"); 280 } 281 282 283 284 public void println() { 285 print("\n"); 286 } 287 288 289 290 public CompilationUnit parse(TypeDecl outerTypeDecl, String outerClassName, Program classPath, boolean isInner) 291 throws FileNotFoundException, IOException { 292 isInnerClass = isInner; 293 return parse(outerTypeDecl, outerClassName, classPath); 294 } 295 296 297 298 public CompilationUnit parse(TypeDecl outerTypeDecl, String outerClassName, Program program) 299 throws FileNotFoundException, IOException { 300 //InputStream file = ClassLoader.getSystemResourceAsStream(name); 301 302 if(is == null) { 303 FileInputStream file = new FileInputStream(name); 304 //System.err.println("/home/torbjorn/sandbox/jdk/" + name); 305 306 if(file == null) { 307 throw new FileNotFoundException(name); 308 } 309 310 // // Does not work without DummyInputStream. Why? 311 //is = new DataInputStream(new DummyInputStream(new BufferedInputStream(file))); 312 is = new DataInputStream(new BufferedInputStream(file)); 313 } 314 if(BytecodeParser.VERBOSE) 315 println("Parsing byte codes in " + name); 316 317 this.outerClassName = outerClassName; 318 parseMagic(); 319 parseMinor(); 320 parseMajor(); 321 parseConstantPool(); 322 CompilationUnit cu = new CompilationUnit(); 323 TypeDecl typeDecl = parseTypeDecl(); 324 cu.setPackageDecl(classInfo.packageDecl()); 325 cu.addTypeDecl(typeDecl); 326 parseFields(typeDecl); 327 parseMethods(typeDecl); 328 //parse attributes, and if we have an inner class, then execute the branch... 329 if(new Attributes.TypeAttributes(this, typeDecl, outerTypeDecl, program).isInnerClass()) { 330 //this is a workaround for the fact that JastAdd stores inner classes as members of 331 //their outer classes, even for inner classes that come from bytecode; 332 //to avoid having inner classes show up as top-level classes, we remove them here 333 //from the compilation unit again... 334 335 //first add the cu to the program, so that getTypeDecls() won't fail 336 program.addCompilationUnit(cu); 337 //then clear the cu 338 for(int i=0;i<cu.getTypeDecls().getNumChild();i++) { 339 cu.getTypeDecls().removeChild(i); 340 } 341 //and remove the cu from the program again 342 program.getCompilationUnits().removeChild(program.getCompilationUnits().getIndexOfChild(cu)); 343 } 344 345 is.close(); 346 is = null; 347 return cu; 348 } 349 350 351 352 public void parseMagic() { 353 if (next() != 0xca || next() != 0xfe || next() != 0xba || next() != 0xbe) 354 error("magic error"); 355 } 356 357 358 359 public void parseMinor() { 360 int low = u1(); 361 int high = u1(); 362 if(BytecodeParser.VERBOSE) 363 println("Minor: " + high + "." + low); 364 } 365 366 367 368 public void parseMajor() { 369 int low = u1(); 370 int high = u1(); 371 if(BytecodeParser.VERBOSE) 372 println("Major: " + high + "." + low); 373 } 374 375 376 377 public boolean isInnerClass = false; 378 379 380 381 public TypeDecl parseTypeDecl() { 382 int flags = u2(); 383 Modifiers modifiers = modifiers(flags & 0xfddf); 384 if((flags & (ACC_INTERFACE | ACC_ENUM)) == ACC_ENUM) { 385 // Modifiers <ID:String> /[SuperClassAccess:Access]/ Implements:Access* BodyDecl*; 386 EnumDecl decl = new EnumDecl(); 387 decl.setModifiers(modifiers); 388 decl.setID(parseThisClass()); 389 Access superClass = parseSuperClass(); 390 decl.setImplementsList(parseInterfaces(new List())); 391 return decl; 392 } 393 else if ((flags & ACC_INTERFACE) == 0) { 394 ClassDecl decl = new ClassDecl(); 395 decl.setModifiers(modifiers); 396 decl.setID(parseThisClass()); 397 Access superClass = parseSuperClass(); 398 decl.setSuperClassAccessOpt(superClass == null ? new Opt() 399 : new Opt(superClass)); 400 decl.setImplementsList(parseInterfaces(new List())); 401 return decl; 402 } else if((flags & ACC_ANNOTATION) == 0) { 403 InterfaceDecl decl = new InterfaceDecl(); 404 decl.setModifiers(modifiers); 405 decl.setID(parseThisClass()); 406 Access superClass = parseSuperClass(); 407 decl.setSuperInterfaceIdList( 408 parseInterfaces( 409 superClass == null ? new List() 410 : new List().add(superClass))); 411 return decl; 412 } else { 413 AnnotationDecl decl = new AnnotationDecl(); 414 decl.setModifiers(modifiers); 415 decl.setID(parseThisClass()); 416 Access superClass = parseSuperClass(); 417 parseInterfaces( 418 superClass == null ? new List() 419 : new List().add(superClass)); 420 return decl; 421 } 422 } 423 424 425 426 427 public String parseThisClass() { 428 int index = u2(); 429 CONSTANT_Class_Info info = (CONSTANT_Class_Info) constantPool[index]; 430 classInfo = info; 431 return info.simpleName(); 432 } 433 434 435 436 public Access parseSuperClass() { 437 int index = u2(); 438 if (index == 0) 439 return null; 440 CONSTANT_Class_Info info = (CONSTANT_Class_Info) constantPool[index]; 441 return info.access(); 442 } 443 444 445 446 public List parseInterfaces(List list) { 447 int count = u2(); 448 for (int i = 0; i < count; i++) { 449 CONSTANT_Class_Info info = (CONSTANT_Class_Info) constantPool[u2()]; 450 list.add(info.access()); 451 } 452 return list; 453 } 454 455 456 457 458 public Access fromClassName(String s) { 459 // Sample ClassName: a/b/c$d$e 460 // the package name ends at the last '/' 461 // after that follows a list of type names separated by '$' 462 // all except the first are nested types 463 464 String packageName = ""; 465 int index = s.lastIndexOf('/'); 466 if(index != -1) 467 packageName = s.substring(0, index).replace('/', '.'); 468 String typeName = s.substring(index + 1, s.length()); 469 if(typeName.indexOf('$') != -1) 470 return new BytecodeTypeAccess(packageName, typeName); 471 else 472 return new TypeAccess(packageName, typeName); 473 } 474 475 476 477 public static Modifiers modifiers(int flags) { 478 Modifiers m = new Modifiers(); 479 if ((flags & 0x0001) != 0) 480 m.addModifier(new Modifier("public")); 481 if ((flags & 0x0002) != 0) 482 m.addModifier(new Modifier("private")); 483 if ((flags & 0x0004) != 0) 484 m.addModifier(new Modifier("protected")); 485 if ((flags & 0x0008) != 0) 486 m.addModifier(new Modifier("static")); 487 if ((flags & 0x0010) != 0) 488 m.addModifier(new Modifier("final")); 489 if ((flags & 0x0020) != 0) 490 m.addModifier(new Modifier("synchronized")); 491 if ((flags & 0x0040) != 0) 492 m.addModifier(new Modifier("volatile")); 493 if ((flags & 0x0080) != 0) 494 m.addModifier(new Modifier("transient")); 495 if ((flags & 0x0100) != 0) 496 m.addModifier(new Modifier("native")); 497 if ((flags & 0x0400) != 0) 498 m.addModifier(new Modifier("abstract")); 499 if ((flags & 0x0800) != 0) 500 m.addModifier(new Modifier("strictfp")); 501 return m; 502 } 503 504 505 506 public void parseFields(TypeDecl typeDecl) { 507 int count = u2(); 508 if(BytecodeParser.VERBOSE) 509 println("Fields (" + count + "):"); 510 for (int i = 0; i < count; i++) { 511 if(BytecodeParser.VERBOSE) 512 print(" Field nbr " + i + " "); 513 FieldInfo fieldInfo = new FieldInfo(this); 514 if(!fieldInfo.isSynthetic()) 515 typeDecl.addBodyDecl(fieldInfo.bodyDecl()); 516 } 517 } 518 519 520 521 522 public void parseMethods(TypeDecl typeDecl) { 523 int count = u2(); 524 if(BytecodeParser.VERBOSE) 525 println("Methods (" + count + "):"); 526 for (int i = 0; i < count; i++) { 527 if(BytecodeParser.VERBOSE) 528 print(" Method nbr " + i + " "); 529 MethodInfo info = new MethodInfo(this); 530 if(!info.isSynthetic() && !info.name.equals("<clinit>")) { 531 typeDecl.addBodyDecl(info.bodyDecl()); 532 } 533 } 534 } 535 536 537 538 539 public CONSTANT_Info[] constantPool = null; 540 541 542 543 private void checkLengthAndNull(int index) { 544 if(index >= constantPool.length) { 545 throw new Error("Trying to access element " + index + " in constant pool of length " + constantPool.length); 546 } 547 if(constantPool[index] == null) 548 throw new Error("Unexpected null element in constant pool at index " + index); 549 } 550 551 552 public boolean validConstantPoolIndex(int index) { 553 return index < constantPool.length && constantPool[index] != null; 554 } 555 556 557 public CONSTANT_Info getCONSTANT_Info(int index) { 558 checkLengthAndNull(index); 559 return constantPool[index]; 560 } 561 562 563 public CONSTANT_Utf8_Info getCONSTANT_Utf8_Info(int index) { 564 checkLengthAndNull(index); 565 CONSTANT_Info info = constantPool[index]; 566 if(!(info instanceof CONSTANT_Utf8_Info)) 567 throw new Error("Expected CONSTANT_Utf8_info at " + index + " in constant pool but found " + info.getClass().getName()); 568 return (CONSTANT_Utf8_Info)info; 569 } 570 571 572 public CONSTANT_Class_Info getCONSTANT_Class_Info(int index) { 573 checkLengthAndNull(index); 574 CONSTANT_Info info = constantPool[index]; 575 if(!(info instanceof CONSTANT_Class_Info)) 576 throw new Error("Expected CONSTANT_Class_info at " + index + " in constant pool but found " + info.getClass().getName()); 577 return (CONSTANT_Class_Info)info; 578 } 579 580 581 582 public void parseConstantPool() { 583 int count = u2(); 584 if(BytecodeParser.VERBOSE) 585 println("constant_pool_count: " + count); 586 constantPool = new CONSTANT_Info[count + 1]; 587 for (int i = 1; i < count; i++) { 588 parseEntry(i); 589 if (constantPool[i] instanceof CONSTANT_Long_Info 590 || constantPool[i] instanceof CONSTANT_Double_Info) 591 i++; 592 } 593 594 //println("ConstantPool: "); 595 //for(int i = 1; i < count; i++) { 596 // println(i + ", " + constantPool[i]); 597 //} 598 599 } 600 601 602 603 private static final int CONSTANT_Class = 7; 604 605 606 private static final int CONSTANT_FieldRef = 9; 607 608 609 private static final int CONSTANT_MethodRef = 10; 610 611 612 private static final int CONSTANT_InterfaceMethodRef = 11; 613 614 615 private static final int CONSTANT_String = 8; 616 617 618 private static final int CONSTANT_Integer = 3; 619 620 621 private static final int CONSTANT_Float = 4; 622 623 624 private static final int CONSTANT_Long = 5; 625 626 627 private static final int CONSTANT_Double = 6; 628 629 630 private static final int CONSTANT_NameAndType = 12; 631 632 633 private static final int CONSTANT_Utf8 = 1; 634 635 636 637 public void parseEntry(int i) { 638 int tag = u1(); 639 switch (tag) { 640 case CONSTANT_Class: 641 constantPool[i] = new CONSTANT_Class_Info(this); 642 break; 643 case CONSTANT_FieldRef: 644 constantPool[i] = new CONSTANT_Fieldref_Info(this); 645 break; 646 case CONSTANT_MethodRef: 647 constantPool[i] = new CONSTANT_Methodref_Info(this); 648 break; 649 case CONSTANT_InterfaceMethodRef: 650 constantPool[i] = new CONSTANT_InterfaceMethodref_Info(this); 651 break; 652 case CONSTANT_String: 653 constantPool[i] = new CONSTANT_String_Info(this); 654 break; 655 case CONSTANT_Integer: 656 constantPool[i] = new CONSTANT_Integer_Info(this); 657 break; 658 case CONSTANT_Float: 659 constantPool[i] = new CONSTANT_Float_Info(this); 660 break; 661 case CONSTANT_Long: 662 constantPool[i] = new CONSTANT_Long_Info(this); 663 break; 664 case CONSTANT_Double: 665 constantPool[i] = new CONSTANT_Double_Info(this); 666 break; 667 case CONSTANT_NameAndType: 668 constantPool[i] = new CONSTANT_NameAndType_Info(this); 669 break; 670 case CONSTANT_Utf8: 671 constantPool[i] = new CONSTANT_Utf8_Info(this); 672 break; 673 default: 674 println("Unknown entry: " + tag); 675 } 676 } 677 678 679 }