001 package org.extendj.ast; 002 003 import java.util.HashSet; 004 import java.io.File; 005 import java.util.Set; 006 import java.util.Collections; 007 import java.util.Collection; 008 import java.util.ArrayList; 009 import beaver.*; 010 import java.util.*; 011 import java.io.ByteArrayOutputStream; 012 import java.io.PrintStream; 013 import java.lang.reflect.InvocationTargetException; 014 import java.lang.reflect.Method; 015 import org.jastadd.util.*; 016 import java.util.zip.*; 017 import java.io.*; 018 import org.jastadd.util.PrettyPrintable; 019 import org.jastadd.util.PrettyPrinter; 020 import java.io.FileNotFoundException; 021 import java.io.BufferedInputStream; 022 import java.io.DataInputStream; 023 /** 024 * @ast class 025 * @aspect BytecodeReader 026 * @declaredat /home/jesper/git/extendj/java8/frontend/BytecodeReader.jrag:35 027 */ 028 public class BytecodeParser extends AbstractClassfileParser implements Flags { 029 030 031 public String outerClassName; 032 033 034 035 public BytecodeParser(InputStream in, String name) { 036 super(in, name); 037 } 038 039 040 041 @Override 042 public boolean outerClassNameEquals(String name) { 043 return outerClassName != null && outerClassName.equals(name); 044 } 045 046 047 048 public CompilationUnit parse(TypeDecl outerTypeDecl, String outerClassName, 049 Program classPath, boolean isInner) 050 throws FileNotFoundException, IOException { 051 isInnerClass = isInner; 052 return parse(outerTypeDecl, outerClassName, classPath); 053 } 054 055 056 057 public CompilationUnit parse(TypeDecl outerTypeDecl, String outerClassName, Program program) 058 throws FileNotFoundException, IOException { 059 060 if (VERBOSE) { 061 println("Parsing byte codes in " + name); 062 } 063 064 this.outerClassName = outerClassName; 065 parseMagic(); 066 int minor = parseMinor(); 067 int major = parseMajor(); 068 if (AbstractClassfileParser.VERBOSE) { 069 println(String.format("Classfile version: %d.%d", major, minor)); 070 } 071 if (major > 52) { 072 error(String.format("Can not parse classfile version %d.%d." 073 + " Classfile versions up to 52.x (Java 8) are supported by" 074 + " this version of the compiler.", 075 major, minor)); 076 } 077 parseConstantPool(); 078 CompilationUnit cu = new CompilationUnit(); 079 TypeDecl typeDecl = parseTypeDecl(); 080 cu.setPackageDecl(classInfo.packageDecl()); 081 cu.addTypeDecl(typeDecl); 082 parseFields(typeDecl); 083 parseMethods(typeDecl); 084 //parse attributes, and if we have an inner class, then execute the branch... 085 if (new Attributes.TypeAttributes(this, typeDecl, outerTypeDecl, program).isInnerClass()) { 086 //this is a workaround for the fact that JastAdd stores inner classes as members of 087 //their outer classes, even for inner classes that come from bytecode; 088 //to avoid having inner classes show up as top-level classes, we remove them here 089 //from the compilation unit again... 090 091 //first add the cu to the program, so that getTypeDecls() won't fail 092 program.addCompilationUnit(cu); 093 //then clear the cu 094 for (int i=0;i<cu.getTypeDecls().getNumChild();i++) { 095 cu.getTypeDecls().removeChild(i); 096 } 097 //and remove the cu from the program again 098 program.getCompilationUnits().removeChild(program.getCompilationUnits().getIndexOfChild(cu)); 099 } 100 101 return cu; 102 } 103 104 105 106 public TypeDecl parseTypeDecl() throws IOException { 107 int flags = u2(); 108 Modifiers modifiers = modifiers(flags & 0xfddf); 109 if ((flags & (ACC_INTERFACE | ACC_ENUM)) == ACC_ENUM) { 110 // Modifiers <ID:String> /[SuperClass:Access]/ Implements:Access* BodyDecl*; 111 EnumDecl decl = new EnumDecl(); 112 decl.setModifiers(modifiers); 113 decl.setID(parseThisClass()); 114 Access superClass = parseSuperClass(); 115 // TODO trying to overwrite NTA? 116 decl.setImplementsList(parseInterfaces(new List())); 117 return decl; 118 } else if ((flags & ACC_INTERFACE) == 0) { 119 ClassDecl decl = new ClassDecl(); 120 decl.setModifiers(modifiers); 121 decl.setID(parseThisClass()); 122 Access superClass = parseSuperClass(); 123 decl.setSuperClassOpt( 124 superClass == null 125 ? new Opt() 126 : new Opt(superClass)); 127 decl.setImplementsList(parseInterfaces(new List())); 128 return decl; 129 } else if ((flags & ACC_ANNOTATION) == 0) { 130 InterfaceDecl decl = new InterfaceDecl(); 131 decl.setModifiers(modifiers); 132 decl.setID(parseThisClass()); 133 Access superClass = parseSuperClass(); 134 decl.setSuperInterfaceList(parseInterfaces( 135 superClass == null 136 ? new List() 137 : new List().add(superClass))); 138 return decl; 139 } else { 140 AnnotationDecl decl = new AnnotationDecl(); 141 decl.setModifiers(modifiers); 142 decl.setID(parseThisClass()); 143 Access superClass = parseSuperClass(); 144 parseInterfaces( 145 superClass == null 146 ? new List() 147 : new List().add(superClass)); 148 return decl; 149 } 150 } 151 152 153 154 public static Access fromClassName(String s) { 155 // Sample ClassName: a/b/c$d$e 156 // the package name ends at the last '/' 157 // after that follows a list of type names separated by '$' 158 // all except the first are nested types 159 160 String packageName = ""; 161 int index = s.lastIndexOf('/'); 162 if (index != -1) { 163 packageName = s.substring(0, index).replace('/', '.'); 164 } 165 String typeName = s.substring(index + 1, s.length()); 166 if (typeName.indexOf('$') != -1) { 167 return new BytecodeTypeAccess(packageName, typeName); 168 } else { 169 return new TypeAccess(packageName, typeName); 170 } 171 } 172 173 174 175 public void parseMethods(TypeDecl typeDecl) throws IOException { 176 int count = u2(); 177 if (VERBOSE) { 178 println("Methods (" + count + "):"); 179 } 180 for (int i = 0; i < count; i++) { 181 if (VERBOSE) { 182 print(" Method nbr " + i + " "); 183 } 184 MethodInfo info = new MethodInfo(this); 185 if (!info.isSynthetic() && !info.name.equals("<clinit>")) { 186 BodyDecl bodyDecl = info.bodyDecl(); 187 if (bodyDecl instanceof MethodDecl && typeDecl instanceof InterfaceDecl) { 188 MethodDecl methodDecl = (MethodDecl) bodyDecl; 189 boolean foundAbstract = false; 190 boolean foundStatic = false; 191 for (int j = 0; j < methodDecl.getModifiers().getNumModifier(); j++) { 192 Modifier modifier = methodDecl.getModifiers().getModifier(j); 193 if (modifier.getID().equals("abstract")) { 194 foundAbstract = true; 195 } else if (modifier.getID().equals("static")) { 196 foundStatic = true; 197 } 198 } 199 if (!foundAbstract && !foundStatic) { 200 methodDecl.getModifiers().addModifier(new Modifier("default")); 201 } 202 } 203 typeDecl.addBodyDecl(bodyDecl); 204 } 205 } 206 } 207 208 209 210 @Override 211 public void parseConstantPoolEntry(int i) throws IOException { 212 int tag = u1(); 213 switch (tag) { 214 case CONSTANT_Class: 215 constantPool[i] = new CONSTANT_Class_Info(this); 216 break; 217 case CONSTANT_FieldRef: 218 constantPool[i] = new CONSTANT_Fieldref_Info(this); 219 break; 220 case CONSTANT_MethodRef: 221 constantPool[i] = new CONSTANT_Methodref_Info(this); 222 break; 223 case CONSTANT_InterfaceMethodRef: 224 constantPool[i] = new CONSTANT_InterfaceMethodref_Info(this); 225 break; 226 case CONSTANT_String: 227 constantPool[i] = new CONSTANT_String_Info(this); 228 break; 229 case CONSTANT_Integer: 230 constantPool[i] = new CONSTANT_Integer_Info(this); 231 break; 232 case CONSTANT_Float: 233 constantPool[i] = new CONSTANT_Float_Info(this); 234 break; 235 case CONSTANT_Long: 236 constantPool[i] = new CONSTANT_Long_Info(this); 237 break; 238 case CONSTANT_Double: 239 constantPool[i] = new CONSTANT_Double_Info(this); 240 break; 241 case CONSTANT_NameAndType: 242 constantPool[i] = new CONSTANT_NameAndType_Info(this); 243 break; 244 case CONSTANT_Utf8: 245 constantPool[i] = new CONSTANT_Utf8_Info(this); 246 break; 247 case 15: 248 u1(); 249 u2(); 250 break; 251 case 16: 252 u2(); 253 break; 254 case 18: 255 u2(); 256 u2(); 257 default: 258 println("Unknown entry: " + tag); 259 } 260 } 261 262 263 }