@@ -1,5 +1,5 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). | |||
* Copyright (c) 2002 Contributors | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
@@ -7,11 +7,12 @@ | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* PARC initial implementation | |||
* PARC initial implementation | |||
* Andy Clement pushed down into bcel module | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
package org.aspectj.apache.bcel.generic; | |||
/** we don't actually target instructions, but instructions target us. */ | |||
public class LineNumberTag extends Tag { |
@@ -1,5 +1,5 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). | |||
* Copyright (c) 2002 Contributors | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
@@ -8,15 +8,15 @@ | |||
* | |||
* Contributors: | |||
* PARC initial implementation | |||
* Andy Clement pushed down into bcel module | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
import org.aspectj.weaver.UnresolvedType; | |||
package org.aspectj.apache.bcel.generic; | |||
public final class LocalVariableTag extends Tag { | |||
private final UnresolvedType type; | |||
private Type type; // not always known, in which case signature has to be used | |||
private final String signature; | |||
private final String name; | |||
private int slot; | |||
private final int startPos; | |||
@@ -24,22 +24,26 @@ public final class LocalVariableTag extends Tag { | |||
// AMC - pr101047, two local vars with the same name can share the same slot, but must in that case | |||
// have different start positions. | |||
public LocalVariableTag(UnresolvedType type, String name, int slot, int startPosition) { | |||
this.type = type; | |||
public LocalVariableTag(String sig, String name, int slot, int startPosition) { | |||
this.signature = sig; | |||
this.name = name; | |||
this.slot = slot; | |||
this.startPos = startPosition; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public int getSlot() { | |||
return slot; | |||
} | |||
public UnresolvedType getType() { | |||
return type; | |||
public LocalVariableTag(Type t,String sig, String name, int slot, int startPosition) { | |||
this.type = t; | |||
this.signature = sig; | |||
this.name = name; | |||
this.slot = slot; | |||
this.startPos = startPosition; | |||
} | |||
public String getName() {return name;} | |||
public int getSlot() {return slot;} | |||
public String getType() {return signature;} | |||
public Type getRealType() {return type;} | |||
public void updateSlot(int newSlot) { | |||
this.slot = newSlot; | |||
@@ -51,18 +55,20 @@ public final class LocalVariableTag extends Tag { | |||
// ---- from Object | |||
public String toString() { | |||
return "local " + slot + ": " + type + " " + name; | |||
return "local " + slot + ": " + signature + " " + name; | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof LocalVariableTag)) return false; | |||
LocalVariableTag o = (LocalVariableTag)other; | |||
return o.type.equals(type) && o.name.equals(name) && o.slot == slot && o.startPos == startPos; | |||
return o.slot == slot && o.startPos == startPos && o.signature.equals(signature) && o.name.equals(name); | |||
} | |||
private volatile int hashCode = 0; | |||
private int hashCode = 0; | |||
public int hashCode() { | |||
if (hashCode == 0) { | |||
int ret = 17; | |||
ret = 37*ret + type.hashCode(); | |||
ret = 37*ret + signature.hashCode(); | |||
ret = 37*ret + name.hashCode(); | |||
ret = 37*ret + slot; | |||
ret = 37*ret + startPos; |
@@ -86,7 +86,7 @@ import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; | |||
* use the `removeNOPs' method to get rid off them. | |||
* The resulting method object can be obtained via the `getMethod()' method. | |||
* | |||
* @version $Id: MethodGen.java,v 1.6 2006/02/14 13:32:07 aclement Exp $ | |||
* @version $Id: MethodGen.java,v 1.7 2006/02/21 10:49:15 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A> [setMaxStack()] | |||
* @see InstructionList | |||
@@ -100,6 +100,7 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
private int max_stack; | |||
private InstructionList il; | |||
private boolean strip_attributes; | |||
private int highestLineNumber = 0; | |||
private ArrayList variable_vec = new ArrayList(); | |||
private ArrayList line_number_vec = new ArrayList(); | |||
@@ -188,6 +189,8 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} | |||
} | |||
} | |||
public int getHighestlinenumber() { return highestLineNumber; } | |||
/** | |||
* Instantiate from existing method. | |||
@@ -198,6 +201,10 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
*/ | |||
public MethodGen(Method m, String class_name, ConstantPoolGen cp) { | |||
this(m,class_name,cp,false); | |||
} | |||
public MethodGen(Method m, String class_name, ConstantPoolGen cp,boolean useTags) { | |||
this( | |||
m.getAccessFlags(), | |||
@@ -261,29 +268,63 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
if (a instanceof LineNumberTable) { | |||
LineNumber[] ln = ((LineNumberTable) a).getLineNumberTable(); | |||
for (int k = 0; k < ln.length; k++) { | |||
LineNumber l = ln[k]; | |||
addLineNumber(il.findHandle(l.getStartPC(),arrayOfInstructions), | |||
l.getLineNumber()); | |||
if (useTags) { | |||
// abracadabra, lets create tags rather than linenumbergens. | |||
for (int k = 0; k < ln.length; k++) { | |||
LineNumber l = ln[k]; | |||
int lnum = l.getLineNumber(); | |||
if (lnum>highestLineNumber) highestLineNumber=lnum; | |||
LineNumberTag lt = new LineNumberTag(lnum); | |||
il.findHandle(l.getStartPC(),arrayOfInstructions).addTargeter(lt); | |||
} | |||
} else { | |||
for (int k = 0; k < ln.length; k++) { | |||
LineNumber l = ln[k]; | |||
addLineNumber(il.findHandle(l.getStartPC(),arrayOfInstructions), | |||
l.getLineNumber()); | |||
} | |||
} | |||
} else if (a instanceof LocalVariableTable) { | |||
LocalVariable[] lv = ((LocalVariableTable) a).getLocalVariableTable(); | |||
removeLocalVariables(); | |||
for (int k = 0; k < lv.length; k++) { | |||
LocalVariable l = lv[k]; | |||
InstructionHandle start = il.findHandle(l.getStartPC(), arrayOfInstructions); | |||
InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength(), arrayOfInstructions); | |||
// AMC, this actually gives us the first instruction AFTER the range, | |||
// so move back one... (findHandle can't cope with mid-instruction indices) | |||
if (end != null) end = end.getPrev(); | |||
// Repair malformed handles | |||
if (null == start) start = il.getStart(); | |||
if (null == end) end = il.getEnd(); | |||
addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end); | |||
// Lets have a go at creating Tags directly | |||
if (useTags) { | |||
LocalVariable[] lv = ((LocalVariableTable) a).getLocalVariableTable(); | |||
for (int k = 0; k < lv.length; k++) { | |||
LocalVariable l = lv[k]; | |||
Type t = Type.getType(l.getSignature()); | |||
LocalVariableTag lvt = new LocalVariableTag(t,l.getSignature(),l.getName(),l.getIndex(),l.getStartPC()); | |||
InstructionHandle start = il.findHandle(l.getStartPC(), arrayOfInstructions); | |||
byte b = t.getType(); | |||
if (b!= Constants.T_ADDRESS) { | |||
int increment = t.getSize(); | |||
if (l.getIndex()+increment>max_locals) max_locals = l.getIndex()+increment; | |||
} | |||
int end = l.getStartPC()+l.getLength(); | |||
do { | |||
start.addTargeter(lvt); | |||
start = start.getNext(); | |||
} while (start!=null && start.getPosition()<end); | |||
} | |||
} else { | |||
LocalVariable[] lv = ((LocalVariableTable) a).getLocalVariableTable(); | |||
removeLocalVariables(); | |||
for (int k = 0; k < lv.length; k++) { | |||
LocalVariable l = lv[k]; | |||
InstructionHandle start = il.findHandle(l.getStartPC(), arrayOfInstructions); | |||
InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength(), arrayOfInstructions); | |||
// AMC, this actually gives us the first instruction AFTER the range, | |||
// so move back one... (findHandle can't cope with mid-instruction indices) | |||
if (end != null) end = end.getPrev(); | |||
// Repair malformed handles | |||
if (null == start) start = il.getStart(); | |||
if (null == end) end = il.getEnd(); | |||
addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end); | |||
} | |||
} | |||
} else addCodeAttribute(a); | |||
} |
@@ -1,5 +1,5 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). | |||
* Copyright (c) 2002 Contributors | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
@@ -8,16 +8,15 @@ | |||
* | |||
* Contributors: | |||
* PARC initial implementation | |||
* Andy Clement pushed down into bcel module | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.bcel; | |||
package org.aspectj.apache.bcel.generic; | |||
import org.aspectj.apache.bcel.generic.InstructionHandle; | |||
import org.aspectj.apache.bcel.generic.InstructionTargeter; | |||
/** A tag is an instruction-targeter that doesn't bother remembering its target(s) */ | |||
abstract class Tag implements InstructionTargeter, Cloneable { | |||
public abstract class Tag implements InstructionTargeter, Cloneable { | |||
public Tag() { | |||
} |
@@ -55,6 +55,7 @@ import org.aspectj.apache.bcel.generic.PUTSTATIC; | |||
import org.aspectj.apache.bcel.generic.RET; | |||
import org.aspectj.apache.bcel.generic.ReturnInstruction; | |||
import org.aspectj.apache.bcel.generic.Select; | |||
import org.aspectj.apache.bcel.generic.Tag; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; | |||
import org.aspectj.bridge.IMessage; | |||
@@ -769,7 +770,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
Annotation a = decaM.getAnnotationX().getBcelAnnotation(); | |||
AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPoolGen(),true); | |||
Method oldMethod = mg.getMethod(); | |||
MethodGen myGen = new MethodGen(oldMethod,clazz.getClassName(),clazz.getConstantPoolGen()); | |||
MethodGen myGen = new MethodGen(oldMethod,clazz.getClassName(),clazz.getConstantPoolGen(),false);// dont use tags, they won't get repaired like for woven methods. | |||
myGen.addAnnotation(ag); | |||
Method newMethod = myGen.getMethod(); | |||
mg.addAnnotation(decaM.getAnnotationX()); |
@@ -43,6 +43,7 @@ import org.aspectj.apache.bcel.generic.InstructionList; | |||
import org.aspectj.apache.bcel.generic.InstructionTargeter; | |||
import org.aspectj.apache.bcel.generic.InvokeInstruction; | |||
import org.aspectj.apache.bcel.generic.LoadInstruction; | |||
import org.aspectj.apache.bcel.generic.LocalVariableTag; | |||
import org.aspectj.apache.bcel.generic.MULTIANEWARRAY; | |||
import org.aspectj.apache.bcel.generic.NEW; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
@@ -1344,12 +1345,13 @@ public class BcelShadow extends Shadow { | |||
*/ | |||
public UnresolvedType ensureTargetTypeIsCorrect(UnresolvedType tx) { | |||
if (tx.equals(ResolvedType.OBJECT) && getKind() == MethodCall && | |||
getSignature().getReturnType().equals(ResolvedType.OBJECT) && | |||
getSignature().getArity()==0 && | |||
getSignature().getName().charAt(0) == 'c' && | |||
getSignature().getName().equals("clone")) { | |||
Member msig = getSignature(); | |||
if (msig.getArity()==0 && | |||
getKind() == MethodCall && | |||
msig.getName().charAt(0) == 'c' && | |||
tx.equals(ResolvedType.OBJECT) && | |||
msig.getReturnType().equals(ResolvedType.OBJECT) && | |||
msig.getName().equals("clone")) { | |||
// Lets go back through the code from the start of the shadow | |||
InstructionHandle searchPtr = range.getStart().getPrev(); | |||
@@ -1363,7 +1365,7 @@ public class BcelShadow extends Shadow { | |||
LoadInstruction li = (LoadInstruction)searchPtr.getInstruction(); | |||
li.getIndex(); | |||
LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr,li.getIndex()); | |||
if (lvt!=null) return lvt.getType(); | |||
if (lvt!=null) return UnresolvedType.forSignature(lvt.getType()); | |||
} | |||
// A field access instruction may tell us the real type of what the clone() call is on | |||
if (searchPtr.getInstruction() instanceof FieldInstruction) { |
@@ -24,6 +24,7 @@ import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
import java.util.Set; | |||
import java.util.Stack; | |||
@@ -44,15 +45,19 @@ import org.aspectj.apache.bcel.generic.InstructionHandle; | |||
import org.aspectj.apache.bcel.generic.InstructionList; | |||
import org.aspectj.apache.bcel.generic.InstructionTargeter; | |||
import org.aspectj.apache.bcel.generic.LineNumberGen; | |||
import org.aspectj.apache.bcel.generic.LineNumberTag; | |||
import org.aspectj.apache.bcel.generic.LocalVariableGen; | |||
import org.aspectj.apache.bcel.generic.LocalVariableInstruction; | |||
import org.aspectj.apache.bcel.generic.LocalVariableTag; | |||
import org.aspectj.apache.bcel.generic.MethodGen; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
import org.aspectj.apache.bcel.generic.Select; | |||
import org.aspectj.apache.bcel.generic.Tag; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.bridge.MessageUtil; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AnnotationX; | |||
import org.aspectj.weaver.BCException; | |||
@@ -94,6 +99,27 @@ public final class LazyMethodGen { | |||
private BcelMethod memberView; | |||
private AjAttribute.EffectiveSignatureAttribute effectiveSignature; | |||
int highestLineNumber = 0; | |||
/* | |||
* This option specifies whether we let the BCEL classes create LineNumberGens and LocalVariableGens | |||
* or if we make it create LineNumberTags and LocalVariableTags. Up until 1.5.1 we always created | |||
* Gens - then on return from the MethodGen ctor we took them apart, reprocessed them all and | |||
* created Tags. (see unpackLocals/unpackLineNumbers). As we have our own copy of Bcel, why not create | |||
* the right thing straightaway? So setting this to true will call the MethodGen ctor() in such | |||
* a way that it creates Tags - removing the need for unpackLocals/unpackLineNumbers - HOWEVER see | |||
* the ensureAllLineNumberSetup() method for some other relevant info. | |||
* | |||
* Whats the difference between a Tag and a Gen? A Tag is more lightweight, it doesn't know which | |||
* instructions it targets, it relies on the instructions targetting *it* - this reduces the amount | |||
* of targeter manipulation we have to do. | |||
* | |||
* Because this *could* go wrong - it passes all our tests, but you never know, the option: | |||
* -Xset:optimizeWithTags=false | |||
* will turn it *OFF* | |||
*/ | |||
public static boolean avoidUseOfBcelGenObjects = true; | |||
public static boolean checkedXsetOption = false; | |||
/** This is nonnull if this method is the result of an "inlining". We currently | |||
* copy methods into other classes for around advice. We add this field so | |||
@@ -248,9 +274,20 @@ public final class LazyMethodGen { | |||
private void initialize() { | |||
if (returnType != null) return; | |||
// Check whether we need to configure the optimization | |||
if (!checkedXsetOption) { | |||
Properties p = enclosingClass.getWorld().getExtraConfiguration(); | |||
if (p!=null) { | |||
avoidUseOfBcelGenObjects = Boolean.parseBoolean(p.getProperty("optimizeWithTags","true")); | |||
if (!avoidUseOfBcelGenObjects) | |||
enclosingClass.getWorld().getMessageHandler().handleMessage(MessageUtil.info("[optimizeWithTags=false] Disabling optimization to use Tags rather than Gens")); | |||
} | |||
checkedXsetOption=true; | |||
} | |||
//System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod); | |||
MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPoolGen()); | |||
MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPoolGen(),avoidUseOfBcelGenObjects); | |||
this.returnType = gen.getReturnType(); | |||
this.argumentTypes = gen.getArgumentTypes(); | |||
@@ -273,10 +310,16 @@ public final class LazyMethodGen { | |||
} else { | |||
//body = new InstructionList(savedMethod.getCode().getCode()); | |||
body = gen.getInstructionList(); | |||
unpackHandlers(gen); | |||
unpackLineNumbers(gen); | |||
unpackLocals(gen); | |||
if (avoidUseOfBcelGenObjects) { | |||
ensureAllLineNumberSetup(gen); | |||
highestLineNumber = gen.getHighestlinenumber(); | |||
} else { | |||
unpackLineNumbers(gen); | |||
unpackLocals(gen); | |||
} | |||
} | |||
assertGoodBody(); | |||
@@ -363,6 +406,33 @@ public final class LazyMethodGen { | |||
gen.removeLineNumbers(); | |||
} | |||
/** | |||
* On entry to this method we have a method whose instruction stream contains a few instructions | |||
* that have line numbers assigned to them (LineNumberTags). The aim is to ensure every instruction | |||
* has the right line number. This is necessary because some of them may be extracted out into other | |||
* methods - and it'd be useful for them to maintain the source line number for debugging. | |||
*/ | |||
private void ensureAllLineNumberSetup(MethodGen gen) { | |||
LineNumberTag lr = null; | |||
boolean skip = false; | |||
for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { | |||
InstructionTargeter[] targeters = ih.getTargeters(); | |||
skip = false; | |||
if (targeters != null) { | |||
for (int i = targeters.length - 1; i >= 0; i--) { | |||
InstructionTargeter targeter = targeters[i]; | |||
if (targeter instanceof LineNumberTag) { | |||
lr = (LineNumberTag) targeter; | |||
skip=true; | |||
} | |||
} | |||
} | |||
if (lr != null && !skip) { | |||
ih.addTargeter(lr); | |||
} | |||
} | |||
} | |||
private void unpackLocals(MethodGen gen) { | |||
Set locals = new HashSet(); | |||
for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { | |||
@@ -373,7 +443,7 @@ public final class LazyMethodGen { | |||
InstructionTargeter targeter = targeters[i]; | |||
if (targeter instanceof LocalVariableGen) { | |||
LocalVariableGen lng = (LocalVariableGen) targeter; | |||
LocalVariableTag lr = new LocalVariableTag(BcelWorld.fromBcel(lng.getType()), lng.getName(), lng.getIndex(), lng.getStart().getPosition()); | |||
LocalVariableTag lr = new LocalVariableTag(lng.getType().getSignature()/*BcelWorld.fromBcel(lng.getType())*/, lng.getName(), lng.getIndex(), lng.getStart().getPosition()); | |||
if (lng.getStart() == ih) { | |||
locals.add(lr); | |||
} else { | |||
@@ -1006,9 +1076,13 @@ public final class LazyMethodGen { | |||
continue; | |||
} | |||
slots.add(new Integer(tag.getSlot())); | |||
gen.addLocalVariable(tag.getName(), | |||
BcelWorld.makeBcelType(tag.getType()), | |||
Type t = tag.getRealType(); | |||
if (t==null) { | |||
t = BcelWorld.makeBcelType(UnresolvedType.forSignature(tag.getType())); | |||
} | |||
gen.addLocalVariable( | |||
tag.getName(), | |||
t, | |||
tag.getSlot(),(InstructionHandle) start,(InstructionHandle) lvpos.end); | |||
} | |||
} |
@@ -197,6 +197,7 @@ abstract class Range implements InstructionTargeter { | |||
// assert isRangeHandle(ih) | |||
Range ret = null; | |||
InstructionTargeter[] targeters = ih.getTargeters(); | |||
if (targeters!=null) { | |||
for (int i = targeters.length - 1; i >= 0; i--) { | |||
if (targeters[i] instanceof Range) { | |||
Range r = (Range) targeters[i]; | |||
@@ -205,7 +206,10 @@ abstract class Range implements InstructionTargeter { | |||
ret = (Range) targeters[i]; | |||
} | |||
} | |||
if (ret == null) throw new BCException("shouldn't happen"); | |||
} | |||
if (ret == null) { | |||
throw new BCException("shouldn't happen"); | |||
} | |||
return ret; | |||
} | |||
@@ -21,6 +21,7 @@ import org.aspectj.apache.bcel.generic.InstructionHandle; | |||
import org.aspectj.apache.bcel.generic.InstructionList; | |||
import org.aspectj.apache.bcel.generic.InstructionTargeter; | |||
import org.aspectj.apache.bcel.generic.LocalVariableInstruction; | |||
import org.aspectj.apache.bcel.generic.LocalVariableTag; | |||
import org.aspectj.apache.bcel.generic.RET; | |||
import org.aspectj.apache.bcel.generic.Select; | |||
import org.aspectj.apache.bcel.generic.TargetLostException; |
@@ -44,6 +44,7 @@ import org.aspectj.apache.bcel.generic.InstructionHandle; | |||
import org.aspectj.apache.bcel.generic.InstructionList; | |||
import org.aspectj.apache.bcel.generic.InstructionTargeter; | |||
import org.aspectj.apache.bcel.generic.LDC; | |||
import org.aspectj.apache.bcel.generic.LineNumberTag; | |||
import org.aspectj.apache.bcel.generic.ObjectType; | |||
import org.aspectj.apache.bcel.generic.ReferenceType; | |||
import org.aspectj.apache.bcel.generic.SIPUSH; | |||
@@ -655,9 +656,8 @@ public class Utility { | |||
// } | |||
// return getSourceLine(ih.getNext()); | |||
// } | |||
public static int getSourceLine(InstructionHandle ih) { | |||
public static int getSourceLine(InstructionHandle ih) {//,boolean goforwards) { | |||
int lookahead=0; | |||
// arbitrary rule that we will never lookahead more than 100 instructions for a line # | |||
while (lookahead++ < 100) { | |||
@@ -672,11 +672,16 @@ public class Utility { | |||
} | |||
} | |||
} | |||
ih = ih.getNext(); | |||
// if (goforwards) ih=ih.getNext(); else | |||
ih=ih.getPrev(); | |||
} | |||
//System.err.println("no line information available for: " + ih); | |||
return -1; | |||
} | |||
// public static int getSourceLine(InstructionHandle ih) { | |||
// return getSourceLine(ih,false); | |||
// } | |||
// assumes that there is no already extant source line tag. Otherwise we'll have to be better. | |||
public static void setSourceLine(InstructionHandle ih, int lineNumber) { |