00001 package de.fub.bytecode.generic;
00002
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.classfile.*;
00005 import java.util.*;
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 public class MethodGen extends AccessFlags implements Constants {
00024 private String method_name;
00025 private String class_name;
00026 private Type return_type;
00027 private Type[] arg_types;
00028 private String[] arg_names;
00029 private int max_locals;
00030 private int max_stack;
00031 private InstructionList il;
00032 private ConstantPoolGen cp;
00033 private boolean strip_attributes;
00034
00035 private Vector variable_vec = new Vector();
00036 private Vector line_number_vec = new Vector();
00037 private Vector attribute_vec = new Vector();
00038 private Vector exception_vec = new Vector();
00039 private Vector throws_vec = new Vector();
00040 private Vector code_attrs_vec = new Vector();
00041
00042 static final class BranchTarget {
00043 InstructionHandle target;
00044 int stackDepth;
00045
00046 BranchTarget(InstructionHandle target, int stackDepth) {
00047 this.target = target;
00048 this.stackDepth = stackDepth;
00049 }
00050 }
00051
00052 static final class BranchStack {
00053 Stack branchTargets = new Stack();
00054 Hashtable visitedTargets = new Hashtable();
00055
00056 public void push(InstructionHandle target, int stackDepth) {
00057 if(visited(target))
00058 return;
00059
00060 branchTargets.push(visit(target, stackDepth));
00061 }
00062
00063 public BranchTarget pop() {
00064 if(!branchTargets.empty()) {
00065 BranchTarget bt = (BranchTarget) branchTargets.pop();
00066 return bt;
00067 }
00068
00069 return null;
00070 }
00071
00072 private final BranchTarget visit(InstructionHandle target, int stackDepth) {
00073 BranchTarget bt = new BranchTarget(target, stackDepth);
00074 visitedTargets.put(target, bt);
00075
00076 return bt;
00077 }
00078
00079 private final boolean visited(InstructionHandle target) {
00080 return (visitedTargets.get(target) != null);
00081 }
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 public MethodGen(int access_flags, Type return_type, Type[] arg_types,
00107 String[] arg_names, String method_name, String class_name,
00108 InstructionList il, ConstantPoolGen cp) {
00109 this.access_flags = access_flags;
00110 this.return_type = return_type;
00111 this.arg_types = arg_types;
00112 this.arg_names = arg_names;
00113 this.method_name = method_name;
00114 this.class_name = class_name;
00115 this.il = il;
00116 this.cp = cp;
00117
00118 if((access_flags & (ACC_ABSTRACT | ACC_NATIVE)) == 0) {
00119 InstructionHandle start = il.getStart();
00120 InstructionHandle end = il.getEnd();
00121
00122
00123
00124 if(!isStatic() && (class_name != null))
00125 addLocalVariable("this", new ObjectType(class_name), start, end);
00126
00127 if(arg_types != null) {
00128 int size = arg_types.length;
00129
00130 if(arg_names != null) {
00131 if(size != arg_names.length)
00132 throw new ClassGenException("Mismatch in argument array lengths: " +
00133 size + " vs. " + arg_names.length);
00134 } else {
00135 arg_names = new String[size];
00136
00137 for(int i=0; i < size; i++)
00138 arg_names[i] = "arg" + i;
00139 }
00140
00141 for(int i=0; i < size; i++)
00142 addLocalVariable(arg_names[i], arg_types[i], start, end);
00143 }
00144 }
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 public MethodGen(Method m, String class_name, ConstantPoolGen cp) {
00154 this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
00155 Type.getArgumentTypes(m.getSignature()), null ,
00156 m.getName(), class_name,
00157 ((m.getAccessFlags() & (ACC_ABSTRACT | ACC_NATIVE)) == 0)?
00158 new InstructionList(m.getCode().getCode()) : null,
00159 cp);
00160
00161 Attribute[] attributes = m.getAttributes();
00162 for(int i=0; i < attributes.length; i++) {
00163 Attribute a = attributes[i];
00164
00165 if(a instanceof Code) {
00166 Code c = (Code)a;
00167 setMaxStack(c.getMaxStack());
00168 setMaxLocals(c.getMaxLocals());
00169
00170 CodeException[] ces = c.getExceptionTable();
00171
00172 if(ces != null) {
00173 for(int j=0; j < ces.length; j++) {
00174 CodeException ce = ces[j];
00175 int type = ce.getCatchType();
00176 ObjectType c_type = null;
00177
00178 if(type > 0)
00179 c_type = new ObjectType(cp.getConstantPool().getConstantString(type, CONSTANT_Class));
00180 int end_pc = ce.getEndPC();
00181 int length = m.getCode().getCode().length;
00182
00183 if(length == end_pc)
00184 end_pc = end_pc - il.getEnd().getInstruction().getLength();
00185
00186 addExceptionHandler(il.findHandle(ce.getStartPC()), il.findHandle(end_pc),
00187 il.findHandle(ce.getHandlerPC()), c_type);
00188 }
00189 }
00190
00191 Attribute[] c_attributes = c.getAttributes();
00192 for(int j=0; j < c_attributes.length; j++) {
00193 a = c_attributes[j];
00194
00195 if(a instanceof LineNumberTable) {
00196 LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();
00197 for(int k=0; k < ln.length; k++) {
00198 LineNumber l = ln[k];
00199 addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
00200 }
00201 }
00202 else if(a instanceof LocalVariableTable) {
00203 LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();
00204 for(int k=0; k < lv.length; k++) {
00205 LocalVariable l = lv[k];
00206 InstructionHandle start = il.findHandle(l.getStartPC());
00207 InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
00208
00209
00210 if(start == null)
00211 start = il.getStart();
00212 if(end == null)
00213 end = il.getEnd();
00214
00215 addLocalVariable(l.getName(), Type.getType(l.getSignature()),
00216 l.getIndex(), start, end);
00217 }
00218 }
00219 else
00220 System.err.println("Unknown Code attribute " + a + " ignored.");
00221 }
00222 }
00223 else if(a instanceof ExceptionTable) {
00224 String[] names = ((ExceptionTable)a).getExceptionNames();
00225 for(int j=0; j < names.length; j++)
00226 addException(names[j]);
00227 }
00228 else
00229 addAttribute(a);
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239 public void addAttribute(Attribute a) { attribute_vec.addElement(a); }
00240
00241
00242
00243
00244
00245
00246
00247 public void addCodeAttribute(Attribute a) { code_attrs_vec.addElement(a); }
00248
00249
00250
00251
00252
00253 public void addException(String class_name) {
00254 throws_vec.addElement(class_name);
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
00268 InstructionHandle end_pc,
00269 InstructionHandle handler_pc,
00270 ObjectType catch_type) {
00271 if((start_pc == null) || (end_pc == null) || (handler_pc == null))
00272 throw new ClassGenException("Exception handler target is null instruction");
00273
00274 CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
00275 handler_pc, catch_type);
00276 exception_vec.addElement(c);
00277 return c;
00278 }
00279
00280
00281
00282 public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
00283 InstructionHandle end_pc,
00284 InstructionHandle handler_pc,
00285 String catch_type) {
00286 return addExceptionHandler(start_pc, end_pc, handler_pc, catch_type == null?
00287 null : new ObjectType(catch_type));
00288 }
00289
00290
00291
00292
00293
00294
00295
00296 public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) {
00297 LineNumberGen l = new LineNumberGen(ih, src_line);
00298 line_number_vec.addElement(l);
00299 return l;
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 public LocalVariableGen addLocalVariable(String name, Type type, int slot,
00314 InstructionHandle start,
00315 InstructionHandle end) {
00316 byte t = type.getType();
00317 int add = type.getSize();
00318
00319 if(slot + add > max_locals)
00320 max_locals = slot + add;
00321
00322 LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
00323 int i;
00324
00325 if((i = variable_vec.indexOf(l)) >= 0)
00326 variable_vec.setElementAt(l, i);
00327 else
00328 variable_vec.addElement(l);
00329 return l;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 public LocalVariableGen addLocalVariable(String name, Type type,
00344 InstructionHandle start,
00345 InstructionHandle end) {
00346 return addLocalVariable(name, type, max_locals, start, end);
00347 }
00348 public Type getArgType(int i) { return arg_types[i]; }
00349 public Type[] getArgTypes() { return arg_types; }
00350
00351
00352
00353 public Attribute[] getAttributes() {
00354 Attribute[] attributes = new Attribute[attribute_vec.size()];
00355 attribute_vec.copyInto(attributes);
00356 return attributes;
00357 }
00358 public String getClassName() { return class_name; }
00359
00360
00361
00362 public Attribute[] getCodeAttributes() {
00363 Attribute[] attributes = new Attribute[code_attrs_vec.size()];
00364 code_attrs_vec.copyInto(attributes);
00365 return attributes;
00366 }
00367
00368
00369
00370 private CodeException[] getCodeExceptions() {
00371 int size = exception_vec.size();
00372 CodeException[] c_exc = new CodeException[size];
00373
00374 try {
00375 for(int i=0; i < size; i++) {
00376 CodeExceptionGen c = (CodeExceptionGen)exception_vec.elementAt(i);
00377 c_exc[i] = c.getCodeException(cp);
00378 }
00379 } catch(ArrayIndexOutOfBoundsException e) {}
00380
00381 return c_exc;
00382 }
00383 public ConstantPoolGen getConstantPool() { return cp; }
00384
00385
00386
00387 public CodeExceptionGen[] getExceptionHandlers() {
00388 CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()];
00389 exception_vec.copyInto(cg);
00390 return cg;
00391 }
00392
00393
00394
00395 public String[] getExceptions() {
00396 String[] e = new String[throws_vec.size()];
00397 throws_vec.copyInto(e);
00398 return e;
00399 }
00400
00401
00402
00403 private ExceptionTable getExceptionTable(ConstantPoolGen cp) {
00404 int size = throws_vec.size();
00405 int[] ex = new int[size];
00406
00407 try {
00408 for(int i=0; i < size; i++)
00409 ex[i] = cp.addClass((String)throws_vec.elementAt(i));
00410 } catch(ArrayIndexOutOfBoundsException e) {}
00411
00412 return new ExceptionTable(cp.addUtf8("Exceptions"),
00413 2 + 2 * size, ex, cp.getConstantPool());
00414 }
00415 public InstructionList getInstructionList() { return il; }
00416
00417
00418
00419 public LineNumberGen[] getLineNumbers() {
00420 LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
00421 line_number_vec.copyInto(lg);
00422 return lg;
00423 }
00424
00425
00426
00427 public LineNumberTable getLineNumberTable(ConstantPoolGen cp) {
00428 int size = line_number_vec.size();
00429 LineNumber[] ln = new LineNumber[size];
00430
00431 try {
00432 for(int i=0; i < size; i++)
00433 ln[i] = ((LineNumberGen)line_number_vec.elementAt(i)).getLineNumber(cp);
00434 } catch(ArrayIndexOutOfBoundsException e) {}
00435
00436 return new LineNumberTable(cp.addUtf8("LineNumberTable"),
00437 2 + ln.length * 4, ln, cp.getConstantPool());
00438 }
00439
00440
00441
00442
00443
00444
00445 public LocalVariableGen[] getLocalVariables() {
00446 int size = variable_vec.size();
00447 LocalVariableGen[] lg = new LocalVariableGen[size];
00448 variable_vec.copyInto(lg);
00449
00450 for(int i=0; i < size; i++) {
00451 if(lg[i].getStart() == null)
00452 lg[i].setStart(il.getStart());
00453
00454 if(lg[i].getEnd() == null)
00455 lg[i].setEnd(il.getEnd());
00456 }
00457
00458 return lg;
00459 }
00460
00461
00462
00463 public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) {
00464 LocalVariableGen[] lg = getLocalVariables();
00465 int size = lg.length;
00466 LocalVariable[] lv = new LocalVariable[size];
00467
00468 for(int i=0; i < size; i++)
00469 lv[i] = lg[i].getLocalVariable(cp);
00470
00471 return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
00472 2 + lv.length * 10, lv, cp.getConstantPool());
00473 }
00474 public int getMaxLocals() { return max_locals; }
00475 public int getMaxStack() { return max_stack; }
00476
00477
00478
00479
00480
00481 public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) {
00482 BranchStack branchTargets = new BranchStack();
00483
00484
00485
00486
00487
00488
00489 for (int i = 0; i < et.length; i++) {
00490 InstructionHandle handler_pc = et[i].getHandlerPC();
00491 if (handler_pc != null)
00492 branchTargets.push(handler_pc, 1);
00493 }
00494
00495 int stackDepth = 0, maxStackDepth = 0;
00496 InstructionHandle ih = il.getStart();
00497
00498 while(ih != null) {
00499 Instruction instruction = ih.getInstruction();
00500 short tag = instruction.getTag();
00501 int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
00502
00503 stackDepth += delta;
00504 if(stackDepth > maxStackDepth)
00505 maxStackDepth = stackDepth;
00506
00507
00508 if(instruction instanceof BranchInstruction) {
00509 BranchInstruction branch = (BranchInstruction) instruction;
00510 if(instruction instanceof Select) {
00511
00512 Select select = (Select) branch;
00513 InstructionHandle[] targets = select.getTargets();
00514 for (int i = 0; i < targets.length; i++)
00515 branchTargets.push(targets[i], stackDepth);
00516
00517 ih = null;
00518 } else if(!(branch instanceof IfInstruction)) {
00519
00520
00521 if(tag == JSR || tag == JSR_W)
00522 branchTargets.push(ih.getNext(), stackDepth - 1);
00523 ih = null;
00524 }
00525
00526
00527
00528 branchTargets.push(branch.getTarget(), stackDepth);
00529 } else {
00530
00531 if(tag == ATHROW || tag == RET || (tag >= IRETURN && tag <= RETURN))
00532 ih = null;
00533 }
00534
00535 if(ih != null)
00536 ih = ih.getNext();
00537
00538 if(ih == null) {
00539 BranchTarget bt = branchTargets.pop();
00540 if (bt != null) {
00541 ih = bt.target;
00542 stackDepth = bt.stackDepth;
00543 }
00544 }
00545 }
00546
00547 return maxStackDepth;
00548 }
00549
00550
00551
00552
00553
00554
00555
00556 public Method getMethod() {
00557 String signature = Type.getMethodSignature(return_type, arg_types);
00558 int name_index = cp.addUtf8(method_name);
00559 int signature_index = cp.addUtf8(signature);
00560
00561
00562
00563 byte[] byte_code = null;
00564
00565 if(il != null)
00566 byte_code = il.getByteCode();
00567
00568
00569
00570 if((variable_vec.size() > 0) && !strip_attributes)
00571 addCodeAttribute(getLocalVariableTable(cp));
00572
00573 if((line_number_vec.size() > 0) && !strip_attributes)
00574 addCodeAttribute(getLineNumberTable(cp));
00575
00576 Attribute[] code_attrs = getCodeAttributes();
00577
00578
00579
00580 int attrs_len = 0;
00581 for(int i=0; i < code_attrs.length; i++)
00582 attrs_len += (code_attrs[i].getLength() + 6);
00583
00584 CodeException[] c_exc = getCodeExceptions();
00585 int exc_len = c_exc.length * 8;
00586
00587 if((il != null) && !isAbstract()) {
00588 Code code = new Code(cp.addUtf8("Code"),
00589 8 + byte_code.length +
00590 2 + exc_len +
00591 2 + attrs_len,
00592 max_stack, max_locals,
00593 byte_code, c_exc,
00594 code_attrs,
00595 cp.getConstantPool());
00596
00597 addAttribute(code);
00598 }
00599
00600 if(throws_vec.size() > 0)
00601 addAttribute(getExceptionTable(cp));
00602
00603 return new Method(access_flags, name_index, signature_index,
00604 getAttributes(), cp.getConstantPool());
00605 }
00606 public String getMethodName() { return method_name; }
00607 public String getMethodSignature() {
00608 return Type.getMethodSignature(return_type, arg_types);
00609 }
00610 public Type getReturnType() { return return_type; }
00611
00612
00613
00614 public void removeAttribute(Attribute a) { attribute_vec.removeElement(a); }
00615
00616
00617
00618 public void removeCodeAttribute(Attribute a) { code_attrs_vec.removeElement(a); }
00619
00620
00621
00622 public void removeException(String c) {
00623 throws_vec.removeElement(c);
00624 }
00625
00626
00627
00628 public void removeExceptionHandler(CodeExceptionGen c) {
00629 exception_vec.removeElement(c);
00630 }
00631
00632
00633
00634 public void removeLineNumber(LineNumberGen l) {
00635 line_number_vec.removeElement(l);
00636 }
00637
00638
00639
00640
00641 public void removeLocalVariable(LocalVariableGen l) {
00642 variable_vec.removeElement(l);
00643 }
00644
00645
00646
00647
00648
00649 public void removeNOPs() {
00650 if(il != null) {
00651 InstructionHandle next;
00652
00653
00654 for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
00655 next = ih.next;
00656
00657 if((next != null) && (ih.getInstruction() instanceof NOP)) {
00658 try {
00659 il.delete(ih);
00660 } catch(TargetLostException e) {
00661 InstructionHandle[] targets = e.getTargets();
00662
00663 for(int i=0; i < targets.length; i++) {
00664 InstructionTargeter[] targeters = targets[i].getTargeters();
00665
00666 for(int j=0; j < targeters.length; j++)
00667 targeters[j].updateTarget(targets[i], next);
00668 }
00669 }
00670 }
00671 }
00672 }
00673 }
00674 public void setArgType(int i, Type type) { arg_types[i] = type; }
00675 public void setArgTypes(Type[] arg_types) { this.arg_types = arg_types; }
00676 public void setConstantPool(ConstantPoolGen cp) { this.cp = cp; }
00677 public void setInstructionList(InstructionList il) { this.il = il; }
00678
00679
00680
00681 public void setMaxLocals() {
00682 if(il != null) {
00683 int max = 0;
00684
00685 if(arg_types != null)
00686 for(int i=0; i < arg_types.length; i++)
00687 max += arg_types[i].getSize();
00688
00689 for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
00690 Instruction ins = ih.getInstruction();
00691 if(ins instanceof LocalVariableInstruction) {
00692 int index = ((LocalVariableInstruction)ins).getIndex() + 1;
00693
00694 if(index > max)
00695 max = index;
00696 }
00697 }
00698
00699 max_locals = max + 1;
00700 } else
00701 max_locals = 0;
00702 }
00703
00704
00705
00706 public void setMaxLocals(int m) { max_locals = m; }
00707
00708
00709
00710
00711 public void setMaxStack() {
00712 if(il != null)
00713 max_stack = getMaxStack(cp, il, getExceptionHandlers());
00714 else
00715 max_stack = 0;
00716 }
00717
00718
00719
00720 public void setMaxStack(int m) { max_stack = m; }
00721 public void setMethodName(String method_name) { this.method_name = method_name; }
00722 public void setReturnType(Type return_type) { this.return_type = return_type; }
00723
00724
00725
00726 public void stripAttributes(boolean flag) { strip_attributes = flag; }
00727 }