1 34 package jarg; 35 36 import java.io.ByteArrayInputStream ; 37 import java.io.IOException ; 38 import java.util.*; 39 40 import org.apache.bcel.classfile.*; 41 import org.apache.bcel.generic.*; 42 import org.apache.bcel.Constants; 43 import org.apache.bcel.util.*; 44 45 51 class ClassHandler { 52 private Jarg app; 53 String filename; 54 String packagename; 55 String classname_slash; 56 String classname; 57 String superclassname; 58 int orgsize; 59 60 private PackageHandler pkgh; 61 62 JavaClass jcls; 63 private JavaClass njcls; 64 65 NameCreater ncF = new NameCreater(); 66 NameCreater ncM = new NameCreater(); 67 boolean isNative = false; 68 boolean isPackageScope = false; 69 boolean isUsed = false; 70 71 ClassHandler(Jarg app, String filename, byte[] buf) throws IOException { 72 this.app = app; 73 this.filename = filename; 74 75 ByteArrayInputStream in = new ByteArrayInputStream (buf); 76 this.jcls = new ClassParser(in, filename).parse(); 77 78 this.packagename = this.jcls.getPackageName(); 80 this.classname = this.jcls.getClassName(); 81 this.classname_slash = this.classname.replace('.','/'); 82 this.superclassname = this.jcls.getSuperclassName(); 83 this.orgsize = buf.length; 84 85 if (this.jcls.isClass() 87 && !this.jcls.isPrivate() 88 && !this.jcls.isProtected() 89 && !this.jcls.isPublic()) { 90 this.isPackageScope = true; 91 } 92 93 Field[] fs = this.jcls.getFields(); 95 for (int i=0; i<fs.length; i++) { 96 this.ncF.addName(fs[i].getName()); 97 } 98 99 Method[] ms = this.jcls.getMethods(); 101 for (int i=0; i<ms.length; i++) { 102 Method m = ms[i]; 103 this.ncM.addName(m.getName()); 104 if (m.isNative()) { 105 this.isNative = true; 106 } 107 } 108 109 app.statistics.addOldClassFileSize(buf.length); 111 setupOldStatistics(); 112 } 113 114 private void setupOldStatistics() { 115 app.statistics.incOldClassCount(); 116 117 ConstantPool cp = this.jcls.getConstantPool(); 118 app.statistics.addOldCpEntryCount(cp.getLength()); 119 app.statistics.addOldCpEntrySize(calcConstantPoolSize(cp)); 120 121 Field[] fs = this.jcls.getFields(); 122 for (int i=0; i<fs.length; i++) { 123 app.statistics.incOldFieldCount(); 124 } 125 126 Method[] ms = this.jcls.getMethods(); 127 for (int i=0; i<ms.length; i++) { 128 app.statistics.incOldMethodCount(); 129 Code code = ms[i].getCode(); 130 if (code != null) { 131 byte[] bcode = code.getCode(); 132 if (bcode != null) { 133 app.statistics.addOldByteCodeSize(bcode.length); 134 app.statistics.addOldByteCodeCount(calcOpecode(code)); 135 } 136 } 137 } 138 } 139 140 void setupNewStatistics() { 141 app.statistics.incNewClassCount(); 142 143 ConstantPool cp = this.njcls.getConstantPool(); 144 app.statistics.addNewCpEntryCount(cp.getLength()); 145 app.statistics.addNewCpEntrySize(calcConstantPoolSize(cp)); 146 147 Field[] fs = this.njcls.getFields(); 148 for (int i=0; i<fs.length; i++) { 149 app.statistics.incNewFieldCount(); 150 } 151 152 Method[] ms = this.njcls.getMethods(); 153 for (int i=0; i<ms.length; i++) { 154 app.statistics.incNewMethodCount(); 155 Code code = ms[i].getCode(); 156 if (code != null) { 157 byte[] bcode = code.getCode(); 158 if (bcode != null) { 159 app.statistics.addNewByteCodeSize(bcode.length); 160 app.statistics.addNewByteCodeCount(calcOpecode(code)); 161 } 162 } 163 } 164 } 165 166 private int calcConstantPoolSize(ConstantPool cp) { 167 java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream (); 168 try { 169 cp.dump(new java.io.DataOutputStream (bout)); 170 bout.close(); 171 } catch (java.io.IOException ex) { 172 ex.printStackTrace(); 173 } 174 return bout.size(); 175 } 176 177 private int calcOpecode(Code code) { 178 int cnt = -1; 179 cnt = OpecodeCounter.countOpcode(code.getCode()); 180 return (cnt < 0) ? 0 : cnt; 181 } 182 183 void setPackageHandler(PackageHandler pkgh) { 184 this.pkgh = pkgh; 185 } 186 187 byte[] getBytes() { 188 return njcls.getBytes(); 189 } 190 191 void doCheckUsedClass (PackageCollection pkgcol) { 192 ConstantPool cp = jcls.getConstantPool(); 193 Constant[] css = cp.getConstantPool(); 194 for (int i=0; i<css.length; i++) { 195 Constant cs = css[i]; 196 if (cs instanceof ConstantClass) { 197 ConstantClass cc = (ConstantClass)cs; 198 int idx = cc.getNameIndex(); 199 Constant csu = css[idx]; 200 ConstantUtf8 utf8 = (ConstantUtf8)csu; 201 String s = utf8.getBytes(); 202 if (!this.classname_slash.equals(s)) { 203 pkgcol.markUsedClass(s); 204 } 205 } 206 } 207 } 208 209 void doOptimize() { 210 this.njcls = optimizeJavaClass(jcls); 211 this.jcls = null; 212 213 if ("java.lang.Object".equals(njcls.getClassName())) { 214 njcls.setSuperclassNameIndex(0); 215 } 216 } 217 218 private JavaClass optimizeJavaClass(JavaClass jcls) { 219 String oldpkgnm = jcls.getPackageName(); 221 String oldclsnm = jcls.getClassName(); 222 String oldsupclsnm = jcls.getSuperclassName(); 223 String newclsnm = pkgh.convClassName(oldclsnm); 224 String newsupclsnm = pkgh.convClassName(oldsupclsnm); 225 226 if (app.isVerboseAll) { 227 System.out.println("Optimizing class " + oldclsnm); 228 } 229 230 if (app.renameLog != null) { 231 app.renameLog.println(newclsnm + "\t <- " + oldclsnm); 232 } 233 234 ConstantPoolGen cpg = new ConstantPoolGen(jcls.getConstantPool()); 236 237 boolean isOptClass = true; 238 239 if (oldpkgnm != null && oldpkgnm.length() > 0) { 241 for (int i=0; i<app.excpPathes.length; i++) { 242 if (oldpkgnm.startsWith(app.excpPathes[i])) { 243 isOptClass = false; 244 break; 245 } 246 } 247 } 248 if (isOptClass && app.excpPackages.contains(oldpkgnm)) { 249 isOptClass = false; 250 } 251 252 if (isOptClass && app.excpClasses.contains(oldclsnm)) { 255 isOptClass = false; 256 } 257 258 if (isOptClass) { 259 Field[] curfields = jcls.getFields(); 260 Method[] curmethods = jcls.getMethods(); 261 262 if (!this.isNative) { 264 removeUnusedFieldAndMethod(oldclsnm, cpg, curfields, curmethods); 265 } 266 267 { 269 boolean isOptimize = true; 270 271 for (int i=0; i < curfields.length; i++) { 275 Field f = curfields[i]; 276 if (f != null && "serialPersistentFields".equals(f.getName())) { 277 isOptimize = false; 278 break; 279 } 280 } 281 282 if (this.isNative) { 284 isOptimize = false; 285 } 286 287 if (isOptimize) { 288 for (int i=0; i < curfields.length; i++) { 289 Field oldf = curfields[i]; 290 if (oldf != null) { 291 Field newf = optimizeFields(oldf, oldclsnm, cpg, newclsnm); 292 curfields[i] = newf; 293 } 294 } 295 } 296 } 297 298 { 300 boolean isOptimize = true; 301 if (this.isNative) { 303 isOptimize = false; 304 } 305 if (isOptimize) { 306 for (int i=0; i < curmethods.length; i++) { 307 Method oldm = curmethods[i]; 308 if (oldm != null) { 309 Method newm = optimizeMethod(oldm, oldclsnm, cpg, newclsnm); 310 curmethods[i] = newm; 311 } 312 } 313 } 314 } 315 } 316 317 if (app.renameLog != null) { 318 app.renameLog.println(); 319 } 320 321 jcls.setConstantPool(cpg.getFinalConstantPool()); 324 325 JavaClassReshaper jcr = new JavaClassReshaper(this.app, this.pkgh); 327 return jcr.reshapeJavaClass(jcls, newclsnm, newsupclsnm); 328 } 329 330 private void removeUnusedFieldAndMethod(String oldclsnm, ConstantPoolGen cpg, Field[] curfields, Method[] curmethods) { 331 HashSet fset = new HashSet(); 332 HashSet mset = new HashSet(); 333 334 HashMap mthmap = new HashMap(); 336 MethodGen[] mgs = new MethodGen[curmethods.length]; 337 for (int i=0; i < curmethods.length; i++) { 338 Method m = curmethods[i]; 339 if (m != null) { 340 MethodGen mg = new MethodGen(m, oldclsnm, cpg); 341 mgs[i] = mg; 342 String key = mg.getClassName() + '#' + m.getName() + m.getSignature(); 343 mthmap.put(key, mg); 344 } 345 } 346 347 for (int i=0; i < mgs.length; i++) { 349 MethodGen mg = mgs[i]; 350 if (!mg.isPrivate()) { 351 scanMethodForUsedCheck(mg, mthmap, fset, mset); 352 } 353 } 354 355 for (int i=0; i < curmethods.length; i++) { 357 Method m = curmethods[i]; 358 if (m.isPrivate()) { 359 String clsnm = oldclsnm; 360 String mthnm = m.getName(); 361 String sig = m.getSignature(); 362 String mthsig = clsnm + '#' + mthnm + sig; 363 if (!mset.contains(mthsig)) { 364 curmethods[i] = null; 365 if (app.isVerboseUFM) { 366 System.out.println("Removed method : " + mthsig); 367 } 368 } 369 } 370 } 371 372 for (int i=0; i < curfields.length; i++) { 374 Field f = curfields[i]; 375 if (f.isPrivate()) { 376 String clsnm = oldclsnm; 377 String fldnm = f.getName(); 378 String clsfld = clsnm + '!' + fldnm; 379 if (!fset.contains(clsfld)) { 380 curfields[i] = null; 381 if (app.isVerboseUFM) { 382 System.out.println("Removed field : " + clsfld); 383 } 384 } 385 } 386 } 387 } 388 389 private void scanMethodForUsedCheck(MethodGen mg, HashMap mthmap, HashSet fset, HashSet mset) { 390 ConstantPoolGen cpg = mg.getConstantPool(); 391 InstructionList il = mg.getInstructionList(); 392 if (il == null) { 393 return; 394 } 395 for (InstructionHandle first = il.getStart(); first != null; first = first.getNext()) { 396 Instruction ins1 = first.getInstruction(); 397 if (ins1 instanceof InvokeInstruction) { 398 InvokeInstruction inv = (InvokeInstruction)ins1; 399 String clsnm = inv.getClassName(cpg); 400 String mthnm = inv.getMethodName(cpg); 401 String sig = inv.getSignature(cpg); 402 String mthsig = clsnm + '#' + mthnm + sig; 403 if (!mset.contains(mthsig)) { 404 mset.add(mthsig); 405 MethodGen mg2 = (MethodGen)mthmap.get(mthsig); 406 if (mg2 != null) { 407 scanMethodForUsedCheck(mg2, mthmap, fset, mset); 408 } 409 } 410 } else if (ins1 instanceof FieldInstruction) { 412 FieldInstruction fins = (FieldInstruction)ins1; 413 String clsnm = fins.getClassName(cpg); 414 String fldnm = fins.getFieldName(cpg); 415 String fld = clsnm + '!' + fldnm; 416 fset.add(fld); 417 } 419 } 420 } 421 422 private Field optimizeFields(Field f, String oldclsnm, ConstantPoolGen cpg, String newclsnm) { 423 int flags = f.getAccessFlags(); 424 String oldfldnm = f.getName(); 425 String oldsignm = f.getSignature(); 426 427 boolean flg = false; 429 430 if (app.isRenameField && f.isPrivate()) { 431 if (!"this".equals(oldfldnm) 432 && !"serialVersionUID".equals(oldfldnm) 433 && !app.excpFields.contains(oldfldnm) 434 ) { 437 flg = true; 439 } 440 } 441 442 String newnm = this.ncF.createNext(); 443 if (oldfldnm.length() <= newnm.length()) { 444 flg = false; 445 } 446 if (flg) { 447 String newfldnm = newnm; 448 449 int idx = cpg.addUtf8(newfldnm); 451 f.setNameIndex(idx); 452 453 idx = cpg.lookupFieldref(oldclsnm, oldfldnm, oldsignm); 455 if (idx > 0) { 456 ConstantFieldref fr = (ConstantFieldref)cpg.getConstant(idx); 457 int idx2 = cpg.addNameAndType(newfldnm, oldsignm); 458 fr.setNameAndTypeIndex(idx2); 459 } 460 461 if (app.isVerboseRN) { 462 System.out.println("rename field " + oldclsnm + "!" + oldfldnm + " -> " + newfldnm); 463 } 464 if (app.renameLog != null) { 465 app.renameLog.println(newclsnm + "!" + newfldnm + "\t <- " + oldclsnm + "!" + oldfldnm); 466 } 467 } else { 468 if (app.renameLog != null) { 469 String newfldnm = pkgh.convFieldName(oldclsnm, oldfldnm); 470 app.renameLog.println(newclsnm + "!" + newfldnm + "\t <- " + oldclsnm + "!" + oldfldnm); 471 } 472 } 473 return f; 474 } 475 476 private Method optimizeMethod(Method m, String oldclsnm, ConstantPoolGen cpg, String newclsnm) { 477 Code code = m.getCode(); 478 int flags = m.getAccessFlags(); 479 String oldmthnm = m.getName(); 480 String oldsignm = m.getSignature(); 481 482 if(m.isNative() || m.isAbstract() || (code == null)) { 484 return m; 485 } 486 MethodGen mg = new MethodGen(m, oldclsnm, cpg); 487 488 boolean flg = false; 490 491 if (app.isRenameMethod && m.isPrivate()) { 492 if (!"<init>".equals(oldmthnm) 493 && !"<clinit>".equals(oldmthnm) 494 && !app.excpMethods.contains(oldmthnm) 495 ) { 496 flg = true; 497 } 498 } 499 500 String newnm = this.ncM.createNext(); 501 if (oldmthnm.length() <= newnm.length()) { 502 flg = false; 503 } 504 if (flg) { 505 String newmthnm = newnm; 506 int idx; 507 508 mg.setName(newmthnm); 510 511 idx = cpg.lookupMethodref(oldclsnm, oldmthnm, oldsignm); 513 if (idx > 0) { 514 ConstantMethodref mr = (ConstantMethodref)cpg.getConstant(idx); 515 int idx2 = cpg.addNameAndType(newmthnm, oldsignm); 516 mr.setNameAndTypeIndex(idx2); 517 } 518 519 if (app.isVerboseRN) { 520 System.out.println("rename method " + oldclsnm + "#" + oldmthnm + oldsignm + " -> " + newmthnm); 521 } 522 if (app.renameLog != null) { 523 String newsignm = pkgh.convSignatureM(oldsignm); 524 app.renameLog.println(newclsnm + "#" + newmthnm + newsignm + "\t <- " + oldclsnm + "#" + oldmthnm + oldsignm); 525 } 526 } else { 527 if (app.renameLog != null) { 528 String newmthnm = pkgh.convMethodName(oldclsnm, oldmthnm, oldsignm); 529 String newsignm = pkgh.convSignatureM(oldsignm); 530 app.renameLog.println(newclsnm + "#" + newmthnm + newsignm + "\t <- " + oldclsnm + "#" + oldmthnm + oldsignm); 531 } 532 } 533 534 return mg.getMethod(); 536 } 537 } 538 | Popular Tags |