1 29 30 package com.caucho.bytecode; 31 32 import com.caucho.log.Log; 33 import com.caucho.util.ByteBuffer; 34 import com.caucho.util.IntArray; 35 import com.caucho.util.L10N; 36 37 import java.util.ArrayList ; 38 import java.util.logging.Level ; 39 import java.util.logging.Logger ; 40 41 44 public class CodeEnhancer extends CodeVisitor { 45 static private final Logger log = Log.open(CodeEnhancer.class); 46 static private final L10N L = new L10N(CodeEnhancer.class); 47 48 private ByteBuffer _code; 49 50 private ArrayList <Jump> _jumps; 51 private ArrayList <Switch> _switches; 52 private boolean _changeLength; 53 54 private IntArray _pendingTargets; 56 private IntArray _completedTargets; 57 58 public CodeEnhancer() 59 { 60 } 61 62 public CodeEnhancer(JavaClass javaClass, CodeAttribute code) 63 { 64 init(javaClass, code); 65 } 66 67 public void init(JavaClass javaClass, CodeAttribute codeAttr) 68 { 69 super.init(javaClass, codeAttr); 70 71 _code = new ByteBuffer(); 72 73 byte []codeBuffer = codeAttr.getCode(); 74 75 _code.add(codeBuffer, 0, codeBuffer.length); 76 77 _changeLength = false; 78 } 79 80 83 public void analyze(Analyzer analyzer, boolean allowFlow) 84 throws Exception 85 { 86 _pendingTargets = new IntArray(); 87 _completedTargets = new IntArray(); 88 89 analyzeImpl(analyzer, allowFlow, _pendingTargets, _completedTargets); 90 } 91 92 95 public byte []getCode() 96 { 97 return _code.getBuffer(); 98 } 99 100 103 public int getLength() 104 { 105 return _code.getLength(); 106 } 107 108 111 public void addByte(int offset, int value) 112 { 113 insertCode(offset, 1); 114 115 _code.set(offset, value); 116 } 117 118 121 public void setByte(int offset, int value) 122 { 123 _code.set(offset, value); 124 } 125 126 129 public void addShort(int offset, int value) 130 { 131 insertCode(offset, 2); 132 133 _code.set(offset + 0, value >> 8); 134 _code.set(offset + 1, value); 135 } 136 137 140 public void add(int offset, byte []buffer, int bufOffset, int length) 141 { 142 insertCode(offset, length); 143 144 _code.set(offset, buffer, bufOffset, length); 145 } 146 147 150 public void remove(int offset, int count) 151 { 152 removeCode(offset, count); 153 } 154 155 158 public void addNulls(int offset, int count) 159 { 160 insertCode(offset, count); 161 } 162 163 172 protected void insertCode(int offset, int count) 173 { 174 if (_jumps == null) 175 analyzeJumps(); 176 177 if (offset <= _offset) { 179 _offset += count; 180 } 181 182 for (int i = 0; i < _jumps.size(); i++) { 183 Jump jump = _jumps.get(i); 184 185 jump.insert(this, offset, count); 186 } 187 188 ArrayList <CodeAttribute.ExceptionItem> exns = getExceptions(); 189 190 for (int i = 0; i < exns.size(); i++) { 191 CodeAttribute.ExceptionItem exn = exns.get(i); 192 193 if (offset <= exn.getStart()) 194 exn.setStart(exn.getStart() + count); 195 196 if (offset <= exn.getEnd()) 197 exn.setEnd(exn.getEnd() + count); 198 199 if (offset <= exn.getHandler()) 200 exn.setHandler(exn.getHandler() + count); 201 } 202 203 if (_pendingTargets != null) { 204 for (int i = _pendingTargets.size() - 1; i >= 0; i--) { 205 int target = _pendingTargets.get(i); 206 207 if (offset <= target) 208 _pendingTargets.set(i, target + count); 209 } 210 211 for (int i = _completedTargets.size() - 1; i >= 0; i--) { 212 int target = _completedTargets.get(i); 213 214 if (offset <= target) 215 _completedTargets.set(i, target + count); 216 } 217 } 218 219 for (int i = 0; i < _switches.size(); i++) { 220 Branch branch = _switches.get(i); 221 222 branch.insert(this, offset, count); 223 } 224 225 for (int i = 0; i < count; i++) 226 _code.add(offset, 0); 227 228 for (int i = 0; i < _switches.size(); i++) { 229 Switch branch = _switches.get(i); 230 231 branch.insertPad(this, offset, count); 232 } 233 } 234 235 protected void removeCode(int offset, int count) 236 { 237 if (_jumps == null) 238 analyzeJumps(); 239 240 if (offset + count < _offset) 241 _offset -= count; 242 else if (offset <= _offset) 243 _offset = offset; 244 245 for (int i = 0; i < _jumps.size(); i++) { 246 Branch jump = _jumps.get(i); 247 248 jump.remove(this, offset, count); 249 } 250 251 ArrayList <CodeAttribute.ExceptionItem> exns = getExceptions(); 252 253 for (int i = 0; i < exns.size(); i++) { 254 CodeAttribute.ExceptionItem exn = exns.get(i); 255 256 exn.setStart(remove(exn.getStart(), offset, count)); 257 exn.setEnd(remove(exn.getEnd(), offset, count)); 258 exn.setHandler(remove(exn.getHandler(), offset, count)); 259 } 260 261 if (_pendingTargets != null) { 262 for (int i = _pendingTargets.size() - 1; i >= 0; i--) { 263 int target = _pendingTargets.get(i); 264 265 _pendingTargets.set(i, remove(target, offset, count)); 266 } 267 268 for (int i = _completedTargets.size() - 1; i >= 0; i--) { 269 int target = _completedTargets.get(i); 270 271 _completedTargets.set(i, remove(target, offset, count)); 272 } 273 } 274 275 for (int i = 0; i < _switches.size(); i++) { 276 Branch branch = _switches.get(i); 277 278 branch.remove(this, offset, count); 279 } 280 281 _code.remove(offset, count); 282 283 for (int i = 0; i < _switches.size(); i++) { 284 Switch branch = _switches.get(i); 285 286 branch.removePad(this, offset, count); 287 } 288 } 289 290 protected void analyzeJumps() 291 { 292 _jumps = new ArrayList <Jump>(); 293 _switches = new ArrayList <Switch>(); 294 295 _changeLength = true; 296 297 JumpAnalyzer analyzer = new JumpAnalyzer(); 298 299 CodeVisitor visitor = new CodeVisitor(getJavaClass(), getCodeAttribute()); 300 301 try { 302 visitor.analyze(analyzer); 303 } catch (Exception e) { 304 log.log(Level.WARNING, e.toString(), e); 305 } 306 } 307 308 311 public void update() 312 { 313 byte []code = new byte[_code.size()]; 314 315 System.arraycopy(_code.getBuffer(), 0, code, 0, _code.size()); 316 317 _codeAttr.setCode(code); 318 319 if (_changeLength) { 320 ArrayList <Attribute> attrList = getCodeAttribute().getAttributes(); 322 for (int i = attrList.size() - 1; i >= 0; i--) { 323 Attribute attr = attrList.get(i); 324 325 if (attr.getName().equals("LineNumberTable")) 326 attrList.remove(i); 327 } 328 } 329 } 330 331 private int remove(int pc, int offset, int count) 332 { 333 if (pc < offset) 334 return pc; 335 else if (pc < offset + count) 336 return offset; 337 else 338 return pc - count; 339 } 340 341 abstract static class Branch { 342 abstract void insert(CodeEnhancer enhancer, int offset, int count); 343 abstract void remove(CodeEnhancer enhancer, int offset, int count); 344 } 345 346 static class Jump extends Branch { 347 private int _src; 348 private int _delta; 349 350 Jump(int src, int delta) 351 { 352 _src = src; 353 _delta = delta; 354 } 355 356 void insert(CodeEnhancer enhancer, int offset, int count) 357 { 358 if (offset <= _src && offset <= _src + _delta) { 360 _src += count; 361 } 362 else if (_src < offset && offset < _src + _delta) { 364 _delta += count; 365 enhancer.setShort(_src + 1, _delta); 366 } 367 else if (_src + _delta <= offset && offset <= _src) { 369 _delta -= count; 370 enhancer.setShort(_src + 1, _delta); 371 _src += count; 372 } 373 } 374 375 void remove(CodeEnhancer enhancer, int offset, int count) 376 { 377 if (offset <= _src && offset <= _src + _delta) { 379 _src -= count; 380 } 381 else if (_src < offset && offset < _src + _delta) { 383 _delta -= count; 384 enhancer.setShort(_src + 1, _delta); 385 } 386 else if (_src + _delta <= offset && offset <= _src) { 388 _delta += count; 389 enhancer.setShort(_src + 1, _delta); 390 _src -= count; 391 } 392 } 393 } 394 395 static class Switch extends Branch { 396 private int _oldSrc; 397 private int _src; 398 private int []_offsets; 399 400 Switch(int src) 401 { 402 _src = src; 403 _oldSrc = src; 404 } 405 406 protected void setOffsets(int []offsets) 407 { 408 _offsets = offsets; 409 } 410 411 void insert(CodeEnhancer enhancer, int offset, int count) 412 { 413 for (int i = 0; i < _offsets.length; i++) { 414 int delta = enhancer.getInt(_offsets[i]); 415 416 if (offset <= _src && _src + delta <= offset) 417 enhancer.setInt(_offsets[i], delta - count); 418 else if (_src < offset && offset < _src + delta) 419 enhancer.setInt(_offsets[i], delta + count); 420 421 if (offset <= _src + 1) 422 _offsets[i] += count; 423 } 424 425 if (offset < _src) 426 _src += count; 427 } 428 429 void remove(CodeEnhancer enhancer, int offset, int count) 430 { 431 for (int i = 0; i < _offsets.length; i++) { 432 int delta = enhancer.getInt(_offsets[i]); 433 434 if (offset <= _src && _src + delta <= offset) 435 enhancer.setInt(_offsets[i], delta + count); 436 else if (_src < offset && offset < _src + delta) 437 enhancer.setInt(_offsets[i], delta - count); 438 439 if (offset <= _src + 1) 440 _offsets[i] -= count; 441 } 442 443 if (offset < _src) 444 _src -= count; 445 } 446 447 void insertPad(CodeEnhancer enhancer, int offset, int count) 448 { 449 if (_oldSrc != _src) { 451 int oldPad = (4 - (_oldSrc + 1) % 4) % 4; 452 int newPad = (4 - (_src + 1) % 4) % 4; 453 454 _oldSrc = _src; 455 456 if (newPad < oldPad) 457 enhancer.remove(_src + 1, oldPad - newPad); 458 else if (oldPad < newPad) 459 enhancer.addNulls(_src + 1, newPad - oldPad); 460 } 461 } 462 463 void removePad(CodeEnhancer enhancer, int offset, int count) 464 { 465 if (_oldSrc != _src) { 467 int oldPad = (4 - (_oldSrc + 1) % 4) % 4; 468 int newPad = (4 - (_src + 1) % 4) % 4; 469 470 _oldSrc = _src; 471 472 if (newPad < oldPad) 473 enhancer.remove(_src + 1, oldPad - newPad); 474 else if (oldPad < newPad) 475 enhancer.addNulls(_src + 1, newPad - oldPad); 476 } 477 } 478 479 public boolean equals(Object v) 480 { 481 if (! (v instanceof Switch)) 482 return false; 483 484 Switch s = (Switch) v; 485 486 return _src == s._src; 487 } 488 } 489 490 static class TableSwitch extends Switch { 491 TableSwitch(int src, CodeVisitor visitor) 492 { 493 super(src); 494 495 int arg = src + 1; 496 arg += (4 - arg % 4) % 4; 497 498 int low = visitor.getInt(arg + 4); 499 int high = visitor.getInt(arg + 8); 500 501 int []offsets = new int[high - low + 2]; 502 503 offsets[0] = arg; 504 505 for (int i = 0; i <= high - low; i++) { 506 offsets[i + 1] = arg + 12 + i * 4; 507 } 508 509 setOffsets(offsets); 510 } 511 } 512 513 static class LookupSwitch extends Switch { 514 LookupSwitch(int src, CodeVisitor visitor) 515 { 516 super(src); 517 518 int arg = src + 1; 519 arg += (4 - arg % 4) % 4; 520 521 int n = visitor.getInt(arg + 4); 522 523 int []offsets = new int[n + 1]; 524 offsets[0] = arg; 525 526 for (int i = 0; i < n; i++) { 527 offsets[i + 1] = arg + 8 + i * 8 + 4; 528 } 529 530 setOffsets(offsets); 531 } 532 } 533 534 class JumpAnalyzer extends Analyzer { 535 public void analyze(CodeVisitor visitor) 536 throws Exception 537 { 538 if (visitor.isSwitch()) { 539 int src = visitor.getOffset(); 540 541 switch (visitor.getOpcode()) { 542 case TABLESWITCH: 543 { 544 TableSwitch branch = new TableSwitch(src, visitor); 545 if (! _switches.contains(branch)) 546 _switches.add(branch); 547 break; 548 } 549 550 case LOOKUPSWITCH: 551 { 552 LookupSwitch branch = new LookupSwitch(src, visitor); 553 if (! _switches.contains(branch)) 554 _switches.add(branch); 555 break; 556 } 557 } 558 } 559 else if (visitor.isBranch()) { 560 int src = visitor.getOffset(); 561 int offset = visitor.getShortArg(1); 562 563 _jumps.add(new Jump(src, offset)); 564 } 565 } 566 } 567 } 568 | Popular Tags |