< prev index next >
src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java
Print this page
rev 47452 : imported patch jdk-new-asmv6.patch
@@ -126,26 +126,38 @@
* this case the maximum stack size and number of local variables is also
* recomputed from scratch.
*
* @see #compute
*/
- private static final int FRAMES = 0;
+ static final int FRAMES = 0;
/**
+ * Indicates that the stack map frames of type F_INSERT must be computed.
+ * The other frames are not (re)computed. They should all be of type F_NEW
+ * and should be sufficient to compute the content of the F_INSERT frames,
+ * together with the bytecode instructions between a F_NEW and a F_INSERT
+ * frame - and without any knowledge of the type hierarchy (by definition of
+ * F_INSERT).
+ *
+ * @see #compute
+ */
+ static final int INSERTED_FRAMES = 1;
+
+ /**
* Indicates that the maximum stack size and number of local variables must
* be automatically computed.
*
* @see #compute
*/
- private static final int MAXS = 1;
+ static final int MAXS = 2;
/**
* Indicates that nothing must be automatically computed.
*
* @see #compute
*/
- private static final int NOTHING = 2;
+ static final int NOTHING = 3;
/**
* The class writer to which this method must be added.
*/
final ClassWriter cw;
@@ -275,11 +287,11 @@
private int currentLocals;
/**
* Number of stack map frames in the StackMapTable attribute.
*/
- private int frameCount;
+ int frameCount;
/**
* The StackMapTable attribute.
*/
private ByteVector stackMap;
@@ -382,15 +394,10 @@
* The non standard attributes of the method's code.
*/
private Attribute cattrs;
/**
- * Indicates if some jump instructions are too small and need to be resized.
- */
- private boolean resize;
-
- /**
* The number of subroutines in this method.
*/
private int subroutines;
// ------------------------------------------------------------------------
@@ -407,10 +414,11 @@
/**
* Indicates what must be automatically computed.
*
* @see #FRAMES
+ * @see #INSERTED_FRAMES
* @see #MAXS
* @see #NOTHING
*/
private final int compute;
@@ -469,22 +477,17 @@
* @param signature
* the method's signature. May be <tt>null</tt>.
* @param exceptions
* the internal names of the method's exceptions. May be
* <tt>null</tt>.
- * @param computeMaxs
- * <tt>true</tt> if the maximum stack size and number of local
- * variables must be automatically computed.
- * @param computeFrames
- * <tt>true</tt> if the stack map tables must be recomputed from
- * scratch.
+ * @param compute
+ * Indicates what must be automatically computed (see #compute).
*/
MethodWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature,
- final String[] exceptions, final boolean computeMaxs,
- final boolean computeFrames) {
- super(Opcodes.ASM5);
+ final String[] exceptions, final int compute) {
+ super(Opcodes.ASM6);
if (cw.firstMethod == null) {
cw.firstMethod = this;
} else {
cw.lastMethod.mv = this;
}
@@ -495,22 +498,20 @@
this.access |= ACC_CONSTRUCTOR;
}
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
this.descriptor = desc;
- if (ClassReader.SIGNATURES) {
this.signature = signature;
- }
if (exceptions != null && exceptions.length > 0) {
exceptionCount = exceptions.length;
this.exceptions = new int[exceptionCount];
for (int i = 0; i < exceptionCount; ++i) {
this.exceptions[i] = cw.newClass(exceptions[i]);
}
}
- this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
- if (computeMaxs || computeFrames) {
+ this.compute = compute;
+ if (compute != NOTHING) {
// updates maxLocals
int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
if ((access & Opcodes.ACC_STATIC) != 0) {
--size;
}
@@ -537,23 +538,17 @@
.putShort(access);
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
annd = new ByteVector();
return new AnnotationWriter(cw, false, annd, null, 0);
}
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
if (visible) {
@@ -567,13 +562,10 @@
}
@Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
@@ -590,13 +582,10 @@
}
@Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
ByteVector bv = new ByteVector();
if ("Ljava/lang/Synthetic;".equals(desc)) {
// workaround for a bug in javac with synthetic parameters
// see ClassReader.readParameterAnnotations
synthetics = Math.max(synthetics, parameter + 1);
@@ -637,38 +626,60 @@
}
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
- if (!ClassReader.FRAMES || compute == FRAMES) {
+ if (compute == FRAMES) {
return;
}
+ if (compute == INSERTED_FRAMES) {
+ if (currentBlock.frame == null) {
+ // This should happen only once, for the implicit first frame
+ // (which is explicitly visited in ClassReader if the
+ // EXPAND_ASM_INSNS option is used).
+ currentBlock.frame = new CurrentFrame();
+ currentBlock.frame.owner = currentBlock;
+ currentBlock.frame.initInputFrame(cw, access,
+ Type.getArgumentTypes(descriptor), nLocal);
+ visitImplicitFirstFrame();
+ } else {
if (type == Opcodes.F_NEW) {
+ currentBlock.frame.set(cw, nLocal, local, nStack, stack);
+ } else {
+ // In this case type is equal to F_INSERT by hypothesis, and
+ // currentBlock.frame contains the stack map frame at the
+ // current instruction, computed from the last F_NEW frame
+ // and the bytecode instructions in between (via calls to
+ // CurrentFrame#execute).
+ }
+ visitFrame(currentBlock.frame);
+ }
+ } else if (type == Opcodes.F_NEW) {
if (previousFrame == null) {
visitImplicitFirstFrame();
}
currentLocals = nLocal;
int frameIndex = startFrame(code.length, nLocal, nStack);
for (int i = 0; i < nLocal; ++i) {
if (local[i] instanceof String) {
- frame[frameIndex++] = Frame.OBJECT
- | cw.addType((String) local[i]);
+ String desc = Type.getObjectType((String) local[i]).getDescriptor();
+ frame[frameIndex++] = Frame.type(cw, desc);
} else if (local[i] instanceof Integer) {
- frame[frameIndex++] = ((Integer) local[i]).intValue();
+ frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue();
} else {
frame[frameIndex++] = Frame.UNINITIALIZED
| cw.addUninitializedType("",
((Label) local[i]).position);
}
}
for (int i = 0; i < nStack; ++i) {
if (stack[i] instanceof String) {
- frame[frameIndex++] = Frame.OBJECT
- | cw.addType((String) stack[i]);
+ String desc = Type.getObjectType((String) stack[i]).getDescriptor();
+ frame[frameIndex++] = Frame.type(cw, desc);
} else if (stack[i] instanceof Integer) {
- frame[frameIndex++] = ((Integer) stack[i]).intValue();
+ frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue();
} else {
frame[frameIndex++] = Frame.UNINITIALIZED
| cw.addUninitializedType("",
((Label) stack[i]).position);
}
@@ -745,11 +756,11 @@
// adds the instruction to the bytecode of the method
code.putByte(opcode);
// update currentBlock
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(opcode, 0, null, null);
} else {
// updates current and max stack sizes
int size = stackSize + Frame.SIZE[opcode];
if (size > maxStackSize) {
@@ -768,11 +779,11 @@
@Override
public void visitIntInsn(final int opcode, final int operand) {
lastCodeOffset = code.length;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(opcode, operand, null, null);
} else if (opcode != Opcodes.NEWARRAY) {
// updates current and max stack sizes only for NEWARRAY
// (stack size variation = 0 for BIPUSH or SIPUSH)
int size = stackSize + 1;
@@ -793,11 +804,11 @@
@Override
public void visitVarInsn(final int opcode, final int var) {
lastCodeOffset = code.length;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(opcode, var, null, null);
} else {
// updates current and max stack sizes
if (opcode == Opcodes.RET) {
// no stack change, but end of current block (no successor)
@@ -850,14 +861,14 @@
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
lastCodeOffset = code.length;
- Item i = cw.newClassItem(type);
+ Item i = cw.newStringishItem(ClassWriter.CLASS, type);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(opcode, code.length, cw, i);
} else if (opcode == Opcodes.NEW) {
// updates current and max stack sizes only if opcode == NEW
// (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
int size = stackSize + 1;
@@ -876,11 +887,11 @@
final String name, final String desc) {
lastCodeOffset = code.length;
Item i = cw.newFieldItem(owner, name, desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(opcode, 0, cw, i);
} else {
int size;
// computes the stack size variation
char c = desc.charAt(0);
@@ -916,11 +927,11 @@
lastCodeOffset = code.length;
Item i = cw.newMethodItem(owner, name, desc, itf);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(opcode, 0, cw, i);
} else {
/*
* computes the stack size variation. In order not to recompute
* several times this variation for the same Item, we use the
@@ -968,11 +979,11 @@
lastCodeOffset = code.length;
Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
} else {
/*
* computes the stack size variation. In order not to recompute
* several times this variation for the same Item, we use the
@@ -1002,11 +1013,13 @@
code.put12(Opcodes.INVOKEDYNAMIC, i.index);
code.putShort(0);
}
@Override
- public void visitJumpInsn(final int opcode, final Label label) {
+ public void visitJumpInsn(int opcode, final Label label) {
+ boolean isWide = opcode >= 200; // GOTO_W
+ opcode = isWide ? opcode - 33 : opcode;
lastCodeOffset = code.length;
Label nextInsn = null;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
@@ -1017,10 +1030,12 @@
addSuccessor(Edge.NORMAL, label);
if (opcode != Opcodes.GOTO) {
// creates a Label for the next basic block
nextInsn = new Label();
}
+ } else if (compute == INSERTED_FRAMES) {
+ currentBlock.frame.execute(opcode, 0, null, null);
} else {
if (opcode == Opcodes.JSR) {
if ((label.status & Label.SUBROUTINE) == 0) {
label.status |= Label.SUBROUTINE;
++subroutines;
@@ -1048,12 +1063,12 @@
if ((label.status & Label.RESOLVED) != 0
&& label.position - code.length < Short.MIN_VALUE) {
/*
* case of a backward jump with an offset < -32768. In this case we
* automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
- * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
- * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
+ * <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is the
+ * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <L>
* designates the instruction just after the GOTO_W.
*/
if (opcode == Opcodes.GOTO) {
code.putByte(200); // GOTO_W
} else if (opcode == Opcodes.JSR) {
@@ -1065,13 +1080,25 @@
nextInsn.status |= Label.TARGET;
}
code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
: opcode ^ 1);
code.putShort(8); // jump offset
- code.putByte(200); // GOTO_W
+ // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real
+ // GOTO_W because we might need to insert a frame just after (as
+ // the target of the IFNOTxxx jump instruction).
+ code.putByte(220);
+ cw.hasAsmInsns = true;
}
label.put(this, code, code.length - 1, true);
+ } else if (isWide) {
+ /*
+ * case of a GOTO_W or JSR_W specified by the user (normally
+ * ClassReader when used to resize instructions). In this case we
+ * keep the original instruction.
+ */
+ code.putByte(opcode + 33);
+ label.put(this, code, code.length - 1, true);
} else {
/*
* case of a backward jump with an offset >= -32768, or of a forward
* jump with, of course, an unknown offset. In these cases we store
* the offset in 2 bytes (which will be increased in
@@ -1095,11 +1122,11 @@
}
@Override
public void visitLabel(final Label label) {
// resolves previous forward references to label, if any
- resize |= label.resolve(this, code.length, code.data);
+ cw.hasAsmInsns |= label.resolve(this, code.length, code.data);
// updates currentBlock
if ((label.status & Label.DEBUG) != 0) {
return;
}
if (compute == FRAMES) {
@@ -1128,10 +1155,22 @@
return;
}
previousBlock.successor = label;
}
previousBlock = label;
+ } else if (compute == INSERTED_FRAMES) {
+ if (currentBlock == null) {
+ // This case should happen only once, for the visitLabel call in
+ // the constructor. Indeed, if compute is equal to
+ // INSERTED_FRAMES currentBlock can not be set back to null (see
+ // #noSuccessor).
+ currentBlock = label;
+ } else {
+ // Updates the frame owner so that a correct frame offset is
+ // computed in visitFrame(Frame).
+ currentBlock.frame.owner = label;
+ }
} else if (compute == MAXS) {
if (currentBlock != null) {
// ends current block (with one new successor)
currentBlock.outputStackMax = maxStackSize;
addSuccessor(stackSize, label);
@@ -1153,11 +1192,11 @@
public void visitLdcInsn(final Object cst) {
lastCodeOffset = code.length;
Item i = cw.newConstItem(cst);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
} else {
int size;
// computes the stack size variation
if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
@@ -1185,11 +1224,11 @@
@Override
public void visitIincInsn(final int var, final int increment) {
lastCodeOffset = code.length;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(Opcodes.IINC, var, null, null);
}
}
if (compute != NOTHING) {
// updates max locals
@@ -1269,14 +1308,14 @@
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
lastCodeOffset = code.length;
- Item i = cw.newClassItem(desc);
+ Item i = cw.newStringishItem(ClassWriter.CLASS, desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
- if (compute == FRAMES) {
+ if (compute == FRAMES || compute == INSERTED_FRAMES) {
currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
} else {
// updates current stack size (max stack size unchanged because
// stack size variation always negative or null)
stackSize += 1 - dims;
@@ -1287,13 +1326,10 @@
}
@Override
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
ByteVector bv = new ByteVector();
// write target_type and target_info
typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
AnnotationWriter.putTarget(typeRef, typePath, bv);
// write type, and reserve space for values count
@@ -1329,13 +1365,10 @@
}
@Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
@@ -1385,13 +1418,10 @@
@Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
- if (!ClassReader.ANNOTATIONS) {
- return null;
- }
ByteVector bv = new ByteVector();
// write target_type and target_info
bv.putByte(typeRef >>> 24).putShort(start.length);
for (int i = 0; i < start.length; ++i) {
bv.putShort(start[i].position)
@@ -1428,19 +1458,11 @@
lineNumber.putShort(line);
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
- if (resize) {
- // replaces the temporary jump opcodes introduced by Label.resolve.
- if (ClassReader.RESIZE) {
- resizeInstructions();
- } else {
- throw new RuntimeException("Method code too large!");
- }
- }
- if (ClassReader.FRAMES && compute == FRAMES) {
+ if (compute == FRAMES) {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
while (handler != null) {
Label l = handler.start.getFirst();
Label h = handler.handler.getFirst();
@@ -1466,12 +1488,12 @@
handler = handler.next;
}
// creates and visits the first (implicit) frame
Frame f = labels.frame;
- Type[] args = Type.getArgumentTypes(descriptor);
- f.initInputFrame(cw, access, args, this.maxLocals);
+ f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor),
+ this.maxLocals);
visitFrame(f);
/*
* fix point algorithm: mark the first basic block as 'changed'
* (i.e. put it in the 'changed' list) and, while there are changed
@@ -1715,12 +1737,14 @@
previousBlock.successor = l;
previousBlock = l;
} else {
currentBlock.outputStackMax = maxStackSize;
}
+ if (compute != INSERTED_FRAMES) {
currentBlock = null;
}
+ }
// ------------------------------------------------------------------------
// Utility methods: stack map frames
// ------------------------------------------------------------------------
@@ -1787,11 +1811,11 @@
int frameIndex = startFrame(0, descriptor.length() + 1, 0);
if ((access & Opcodes.ACC_STATIC) == 0) {
if ((access & ACC_CONSTRUCTOR) == 0) {
frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
} else {
- frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
+ frame[frameIndex++] = Frame.UNINITIALIZED_THIS;
}
}
int i = 1;
loop: while (true) {
int j = i;
@@ -1799,20 +1823,20 @@
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
- frame[frameIndex++] = 1; // Opcodes.INTEGER;
+ frame[frameIndex++] = Frame.INTEGER;
break;
case 'F':
- frame[frameIndex++] = 2; // Opcodes.FLOAT;
+ frame[frameIndex++] = Frame.FLOAT;
break;
case 'J':
- frame[frameIndex++] = 4; // Opcodes.LONG;
+ frame[frameIndex++] = Frame.LONG;
break;
case 'D':
- frame[frameIndex++] = 3; // Opcodes.DOUBLE;
+ frame[frameIndex++] = Frame.DOUBLE;
break;
case '[':
while (descriptor.charAt(i) == '[') {
++i;
}
@@ -1820,12 +1844,11 @@
++i;
while (descriptor.charAt(i) != ';') {
++i;
}
}
- frame[frameIndex++] = Frame.OBJECT
- | cw.addType(descriptor.substring(j, ++i));
+ frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i));
break;
case 'L':
while (descriptor.charAt(i) != ';') {
++i;
}
@@ -2081,15 +2104,15 @@
if (stackMap != null) {
boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
cw.newUTF8(zip ? "StackMapTable" : "StackMap");
size += 8 + stackMap.length;
}
- if (ClassReader.ANNOTATIONS && ctanns != null) {
+ if (ctanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + ctanns.getSize();
}
- if (ClassReader.ANNOTATIONS && ictanns != null) {
+ if (ictanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + ictanns.getSize();
}
if (cattrs != null) {
size += cattrs.getSize(cw, code.data, code.length, maxStack,
@@ -2109,47 +2132,47 @@
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
cw.newUTF8("Deprecated");
size += 6;
}
- if (ClassReader.SIGNATURES && signature != null) {
+ if (signature != null) {
cw.newUTF8("Signature");
cw.newUTF8(signature);
size += 8;
}
if (methodParameters != null) {
cw.newUTF8("MethodParameters");
size += 7 + methodParameters.length;
}
- if (ClassReader.ANNOTATIONS && annd != null) {
+ if (annd != null) {
cw.newUTF8("AnnotationDefault");
size += 6 + annd.length;
}
- if (ClassReader.ANNOTATIONS && anns != null) {
+ if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize();
}
- if (ClassReader.ANNOTATIONS && ianns != null) {
+ if (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
- if (ClassReader.ANNOTATIONS && tanns != null) {
+ if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize();
}
- if (ClassReader.ANNOTATIONS && itanns != null) {
+ if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize();
}
- if (ClassReader.ANNOTATIONS && panns != null) {
+ if (panns != null) {
cw.newUTF8("RuntimeVisibleParameterAnnotations");
size += 7 + 2 * (panns.length - synthetics);
for (int i = panns.length - 1; i >= synthetics; --i) {
size += panns[i] == null ? 0 : panns[i].getSize();
}
}
- if (ClassReader.ANNOTATIONS && ipanns != null) {
+ if (ipanns != null) {
cw.newUTF8("RuntimeInvisibleParameterAnnotations");
size += 7 + 2 * (ipanns.length - synthetics);
for (int i = ipanns.length - 1; i >= synthetics; --i) {
size += ipanns[i] == null ? 0 : ipanns[i].getSize();
}
@@ -2191,35 +2214,35 @@
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
}
- if (ClassReader.SIGNATURES && signature != null) {
+ if (signature != null) {
++attributeCount;
}
if (methodParameters != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && annd != null) {
+ if (annd != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && anns != null) {
+ if (anns != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && ianns != null) {
+ if (ianns != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && tanns != null) {
+ if (tanns != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && itanns != null) {
+ if (itanns != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && panns != null) {
+ if (panns != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && ipanns != null) {
+ if (ipanns != null) {
++attributeCount;
}
if (attrs != null) {
attributeCount += attrs.getCount();
}
@@ -2236,14 +2259,14 @@
size += 8 + lineNumber.length;
}
if (stackMap != null) {
size += 8 + stackMap.length;
}
- if (ClassReader.ANNOTATIONS && ctanns != null) {
+ if (ctanns != null) {
size += 8 + ctanns.getSize();
}
- if (ClassReader.ANNOTATIONS && ictanns != null) {
+ if (ictanns != null) {
size += 8 + ictanns.getSize();
}
if (cattrs != null) {
size += cattrs.getSize(cw, code.data, code.length, maxStack,
maxLocals);
@@ -2271,14 +2294,14 @@
++attributeCount;
}
if (stackMap != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && ctanns != null) {
+ if (ctanns != null) {
++attributeCount;
}
- if (ClassReader.ANNOTATIONS && ictanns != null) {
+ if (ictanns != null) {
++attributeCount;
}
if (cattrs != null) {
attributeCount += cattrs.getCount();
}
@@ -2302,15 +2325,15 @@
boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
out.putInt(stackMap.length + 2).putShort(frameCount);
out.putByteArray(stackMap.data, 0, stackMap.length);
}
- if (ClassReader.ANNOTATIONS && ctanns != null) {
+ if (ctanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
ctanns.put(out);
}
- if (ClassReader.ANNOTATIONS && ictanns != null) {
+ if (ictanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
ictanns.put(out);
}
if (cattrs != null) {
cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
@@ -2331,614 +2354,49 @@
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
}
- if (ClassReader.SIGNATURES && signature != null) {
+ if (signature != null) {
out.putShort(cw.newUTF8("Signature")).putInt(2)
.putShort(cw.newUTF8(signature));
}
if (methodParameters != null) {
out.putShort(cw.newUTF8("MethodParameters"));
out.putInt(methodParameters.length + 1).putByte(
methodParametersCount);
out.putByteArray(methodParameters.data, 0, methodParameters.length);
}
- if (ClassReader.ANNOTATIONS && annd != null) {
+ if (annd != null) {
out.putShort(cw.newUTF8("AnnotationDefault"));
out.putInt(annd.length);
out.putByteArray(annd.data, 0, annd.length);
}
- if (ClassReader.ANNOTATIONS && anns != null) {
+ if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
- if (ClassReader.ANNOTATIONS && ianns != null) {
+ if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
- if (ClassReader.ANNOTATIONS && tanns != null) {
+ if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
- if (ClassReader.ANNOTATIONS && itanns != null) {
+ if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}
- if (ClassReader.ANNOTATIONS && panns != null) {
+ if (panns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
AnnotationWriter.put(panns, synthetics, out);
}
- if (ClassReader.ANNOTATIONS && ipanns != null) {
+ if (ipanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
AnnotationWriter.put(ipanns, synthetics, out);
}
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
}
}
-
- // ------------------------------------------------------------------------
- // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
- // ------------------------------------------------------------------------
-
- /**
- * Resizes and replaces the temporary instructions inserted by
- * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
- * and instruction addresses consistent. This may require to resize other
- * existing instructions, or even to introduce new instructions: for
- * example, increasing the size of an instruction by 2 at the middle of a
- * method can increases the offset of an IFEQ instruction from 32766 to
- * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
- * 32765. This, in turn, may require to increase the size of another jump
- * instruction, and so on... All these operations are handled automatically
- * by this method.
- * <p>
- * <i>This method must be called after all the method that is being built
- * has been visited</i>. In particular, the {@link Label Label} objects used
- * to construct the method are no longer valid after this method has been
- * called.
- */
- private void resizeInstructions() {
- byte[] b = code.data; // bytecode of the method
- int u, v, label; // indexes in b
- int i, j; // loop indexes
- /*
- * 1st step: As explained above, resizing an instruction may require to
- * resize another one, which may require to resize yet another one, and
- * so on. The first step of the algorithm consists in finding all the
- * instructions that need to be resized, without modifying the code.
- * This is done by the following "fix point" algorithm:
- *
- * Parse the code to find the jump instructions whose offset will need
- * more than 2 bytes to be stored (the future offset is computed from
- * the current offset and from the number of bytes that will be inserted
- * or removed between the source and target instructions). For each such
- * instruction, adds an entry in (a copy of) the indexes and sizes
- * arrays (if this has not already been done in a previous iteration!).
- *
- * If at least one entry has been added during the previous step, go
- * back to the beginning, otherwise stop.
- *
- * In fact the real algorithm is complicated by the fact that the size
- * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
- * position in the bytecode (because of padding). In order to ensure the
- * convergence of the algorithm, the number of bytes to be added or
- * removed from these instructions is over estimated during the previous
- * loop, and computed exactly only after the loop is finished (this
- * requires another pass to parse the bytecode of the method).
- */
- int[] allIndexes = new int[0]; // copy of indexes
- int[] allSizes = new int[0]; // copy of sizes
- boolean[] resize; // instructions to be resized
- int newOffset; // future offset of a jump instruction
-
- resize = new boolean[code.length];
-
- // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
- int state = 3;
- do {
- if (state == 3) {
- state = 2;
- }
- u = 0;
- while (u < b.length) {
- int opcode = b[u] & 0xFF; // opcode of current instruction
- int insert = 0; // bytes to be added after this instruction
-
- switch (ClassWriter.TYPE[opcode]) {
- case ClassWriter.NOARG_INSN:
- case ClassWriter.IMPLVAR_INSN:
- u += 1;
- break;
- case ClassWriter.LABEL_INSN:
- if (opcode > 201) {
- // converts temporary opcodes 202 to 217, 218 and
- // 219 to IFEQ ... JSR (inclusive), IFNULL and
- // IFNONNULL
- opcode = opcode < 218 ? opcode - 49 : opcode - 20;
- label = u + readUnsignedShort(b, u + 1);
- } else {
- label = u + readShort(b, u + 1);
- }
- newOffset = getNewOffset(allIndexes, allSizes, u, label);
- if (newOffset < Short.MIN_VALUE
- || newOffset > Short.MAX_VALUE) {
- if (!resize[u]) {
- if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
- // two additional bytes will be required to
- // replace this GOTO or JSR instruction with
- // a GOTO_W or a JSR_W
- insert = 2;
- } else {
- // five additional bytes will be required to
- // replace this IFxxx <l> instruction with
- // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
- // is the "opposite" opcode of IFxxx (i.e.,
- // IFNE for IFEQ) and where <l'> designates
- // the instruction just after the GOTO_W.
- insert = 5;
- }
- resize[u] = true;
- }
- }
- u += 3;
- break;
- case ClassWriter.LABELW_INSN:
- u += 5;
- break;
- case ClassWriter.TABL_INSN:
- if (state == 1) {
- // true number of bytes to be added (or removed)
- // from this instruction = (future number of padding
- // bytes - current number of padding byte) -
- // previously over estimated variation =
- // = ((3 - newOffset%4) - (3 - u%4)) - u%4
- // = (-newOffset%4 + u%4) - u%4
- // = -(newOffset & 3)
- newOffset = getNewOffset(allIndexes, allSizes, 0, u);
- insert = -(newOffset & 3);
- } else if (!resize[u]) {
- // over estimation of the number of bytes to be
- // added to this instruction = 3 - current number
- // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
- insert = u & 3;
- resize[u] = true;
- }
- // skips instruction
- u = u + 4 - (u & 3);
- u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
- break;
- case ClassWriter.LOOK_INSN:
- if (state == 1) {
- // like TABL_INSN
- newOffset = getNewOffset(allIndexes, allSizes, 0, u);
- insert = -(newOffset & 3);
- } else if (!resize[u]) {
- // like TABL_INSN
- insert = u & 3;
- resize[u] = true;
- }
- // skips instruction
- u = u + 4 - (u & 3);
- u += 8 * readInt(b, u + 4) + 8;
- break;
- case ClassWriter.WIDE_INSN:
- opcode = b[u + 1] & 0xFF;
- if (opcode == Opcodes.IINC) {
- u += 6;
- } else {
- u += 4;
- }
- break;
- case ClassWriter.VAR_INSN:
- case ClassWriter.SBYTE_INSN:
- case ClassWriter.LDC_INSN:
- u += 2;
- break;
- case ClassWriter.SHORT_INSN:
- case ClassWriter.LDCW_INSN:
- case ClassWriter.FIELDORMETH_INSN:
- case ClassWriter.TYPE_INSN:
- case ClassWriter.IINC_INSN:
- u += 3;
- break;
- case ClassWriter.ITFMETH_INSN:
- case ClassWriter.INDYMETH_INSN:
- u += 5;
- break;
- // case ClassWriter.MANA_INSN:
- default:
- u += 4;
- break;
- }
- if (insert != 0) {
- // adds a new (u, insert) entry in the allIndexes and
- // allSizes arrays
- int[] newIndexes = new int[allIndexes.length + 1];
- int[] newSizes = new int[allSizes.length + 1];
- System.arraycopy(allIndexes, 0, newIndexes, 0,
- allIndexes.length);
- System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
- newIndexes[allIndexes.length] = u;
- newSizes[allSizes.length] = insert;
- allIndexes = newIndexes;
- allSizes = newSizes;
- if (insert > 0) {
- state = 3;
- }
- }
- }
- if (state < 3) {
- --state;
- }
- } while (state != 0);
-
- // 2nd step:
- // copies the bytecode of the method into a new bytevector, updates the
- // offsets, and inserts (or removes) bytes as requested.
-
- ByteVector newCode = new ByteVector(code.length);
-
- u = 0;
- while (u < code.length) {
- int opcode = b[u] & 0xFF;
- switch (ClassWriter.TYPE[opcode]) {
- case ClassWriter.NOARG_INSN:
- case ClassWriter.IMPLVAR_INSN:
- newCode.putByte(opcode);
- u += 1;
- break;
- case ClassWriter.LABEL_INSN:
- if (opcode > 201) {
- // changes temporary opcodes 202 to 217 (inclusive), 218
- // and 219 to IFEQ ... JSR (inclusive), IFNULL and
- // IFNONNULL
- opcode = opcode < 218 ? opcode - 49 : opcode - 20;
- label = u + readUnsignedShort(b, u + 1);
- } else {
- label = u + readShort(b, u + 1);
- }
- newOffset = getNewOffset(allIndexes, allSizes, u, label);
- if (resize[u]) {
- // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
- // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
- // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
- // and where <l'> designates the instruction just after
- // the GOTO_W.
- if (opcode == Opcodes.GOTO) {
- newCode.putByte(200); // GOTO_W
- } else if (opcode == Opcodes.JSR) {
- newCode.putByte(201); // JSR_W
- } else {
- newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
- : opcode ^ 1);
- newCode.putShort(8); // jump offset
- newCode.putByte(200); // GOTO_W
- // newOffset now computed from start of GOTO_W
- newOffset -= 3;
- }
- newCode.putInt(newOffset);
- } else {
- newCode.putByte(opcode);
- newCode.putShort(newOffset);
- }
- u += 3;
- break;
- case ClassWriter.LABELW_INSN:
- label = u + readInt(b, u + 1);
- newOffset = getNewOffset(allIndexes, allSizes, u, label);
- newCode.putByte(opcode);
- newCode.putInt(newOffset);
- u += 5;
- break;
- case ClassWriter.TABL_INSN:
- // skips 0 to 3 padding bytes
- v = u;
- u = u + 4 - (v & 3);
- // reads and copies instruction
- newCode.putByte(Opcodes.TABLESWITCH);
- newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
- label = v + readInt(b, u);
- u += 4;
- newOffset = getNewOffset(allIndexes, allSizes, v, label);
- newCode.putInt(newOffset);
- j = readInt(b, u);
- u += 4;
- newCode.putInt(j);
- j = readInt(b, u) - j + 1;
- u += 4;
- newCode.putInt(readInt(b, u - 4));
- for (; j > 0; --j) {
- label = v + readInt(b, u);
- u += 4;
- newOffset = getNewOffset(allIndexes, allSizes, v, label);
- newCode.putInt(newOffset);
- }
- break;
- case ClassWriter.LOOK_INSN:
- // skips 0 to 3 padding bytes
- v = u;
- u = u + 4 - (v & 3);
- // reads and copies instruction
- newCode.putByte(Opcodes.LOOKUPSWITCH);
- newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
- label = v + readInt(b, u);
- u += 4;
- newOffset = getNewOffset(allIndexes, allSizes, v, label);
- newCode.putInt(newOffset);
- j = readInt(b, u);
- u += 4;
- newCode.putInt(j);
- for (; j > 0; --j) {
- newCode.putInt(readInt(b, u));
- u += 4;
- label = v + readInt(b, u);
- u += 4;
- newOffset = getNewOffset(allIndexes, allSizes, v, label);
- newCode.putInt(newOffset);
- }
- break;
- case ClassWriter.WIDE_INSN:
- opcode = b[u + 1] & 0xFF;
- if (opcode == Opcodes.IINC) {
- newCode.putByteArray(b, u, 6);
- u += 6;
- } else {
- newCode.putByteArray(b, u, 4);
- u += 4;
- }
- break;
- case ClassWriter.VAR_INSN:
- case ClassWriter.SBYTE_INSN:
- case ClassWriter.LDC_INSN:
- newCode.putByteArray(b, u, 2);
- u += 2;
- break;
- case ClassWriter.SHORT_INSN:
- case ClassWriter.LDCW_INSN:
- case ClassWriter.FIELDORMETH_INSN:
- case ClassWriter.TYPE_INSN:
- case ClassWriter.IINC_INSN:
- newCode.putByteArray(b, u, 3);
- u += 3;
- break;
- case ClassWriter.ITFMETH_INSN:
- case ClassWriter.INDYMETH_INSN:
- newCode.putByteArray(b, u, 5);
- u += 5;
- break;
- // case MANA_INSN:
- default:
- newCode.putByteArray(b, u, 4);
- u += 4;
- break;
- }
- }
-
- // updates the stack map frame labels
- if (compute == FRAMES) {
- Label l = labels;
- while (l != null) {
- /*
- * Detects the labels that are just after an IF instruction that
- * has been resized with the IFNOT GOTO_W pattern. These labels
- * are now the target of a jump instruction (the IFNOT
- * instruction). Note that we need the original label position
- * here. getNewOffset must therefore never have been called for
- * this label.
- */
- u = l.position - 3;
- if (u >= 0 && resize[u]) {
- l.status |= Label.TARGET;
- }
- getNewOffset(allIndexes, allSizes, l);
- l = l.successor;
- }
- // Update the offsets in the uninitialized types
- if (cw.typeTable != null) {
- for (i = 0; i < cw.typeTable.length; ++i) {
- Item item = cw.typeTable[i];
- if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
- item.intVal = getNewOffset(allIndexes, allSizes, 0,
- item.intVal);
- }
- }
- }
- // The stack map frames are not serialized yet, so we don't need
- // to update them. They will be serialized in visitMaxs.
- } else if (frameCount > 0) {
- /*
- * Resizing an existing stack map frame table is really hard. Not
- * only the table must be parsed to update the offets, but new
- * frames may be needed for jump instructions that were inserted by
- * this method. And updating the offsets or inserting frames can
- * change the format of the following frames, in case of packed
- * frames. In practice the whole table must be recomputed. For this
- * the frames are marked as potentially invalid. This will cause the
- * whole class to be reread and rewritten with the COMPUTE_FRAMES
- * option (see the ClassWriter.toByteArray method). This is not very
- * efficient but is much easier and requires much less code than any
- * other method I can think of.
- */
- cw.invalidFrames = true;
- }
- // updates the exception handler block labels
- Handler h = firstHandler;
- while (h != null) {
- getNewOffset(allIndexes, allSizes, h.start);
- getNewOffset(allIndexes, allSizes, h.end);
- getNewOffset(allIndexes, allSizes, h.handler);
- h = h.next;
- }
- // updates the instructions addresses in the
- // local var and line number tables
- for (i = 0; i < 2; ++i) {
- ByteVector bv = i == 0 ? localVar : localVarType;
- if (bv != null) {
- b = bv.data;
- u = 0;
- while (u < bv.length) {
- label = readUnsignedShort(b, u);
- newOffset = getNewOffset(allIndexes, allSizes, 0, label);
- writeShort(b, u, newOffset);
- label += readUnsignedShort(b, u + 2);
- newOffset = getNewOffset(allIndexes, allSizes, 0, label)
- - newOffset;
- writeShort(b, u + 2, newOffset);
- u += 10;
- }
- }
- }
- if (lineNumber != null) {
- b = lineNumber.data;
- u = 0;
- while (u < lineNumber.length) {
- writeShort(
- b,
- u,
- getNewOffset(allIndexes, allSizes, 0,
- readUnsignedShort(b, u)));
- u += 4;
- }
- }
- // updates the labels of the other attributes
- Attribute attr = cattrs;
- while (attr != null) {
- Label[] labels = attr.getLabels();
- if (labels != null) {
- for (i = labels.length - 1; i >= 0; --i) {
- getNewOffset(allIndexes, allSizes, labels[i]);
- }
- }
- attr = attr.next;
- }
-
- // replaces old bytecodes with new ones
- code = newCode;
- }
-
- /**
- * Reads an unsigned short value in the given byte array.
- *
- * @param b
- * a byte array.
- * @param index
- * the start index of the value to be read.
- * @return the read value.
- */
- static int readUnsignedShort(final byte[] b, final int index) {
- return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
- }
-
- /**
- * Reads a signed short value in the given byte array.
- *
- * @param b
- * a byte array.
- * @param index
- * the start index of the value to be read.
- * @return the read value.
- */
- static short readShort(final byte[] b, final int index) {
- return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
- }
-
- /**
- * Reads a signed int value in the given byte array.
- *
- * @param b
- * a byte array.
- * @param index
- * the start index of the value to be read.
- * @return the read value.
- */
- static int readInt(final byte[] b, final int index) {
- return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
- | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
- }
-
- /**
- * Writes a short value in the given byte array.
- *
- * @param b
- * a byte array.
- * @param index
- * where the first byte of the short value must be written.
- * @param s
- * the value to be written in the given byte array.
- */
- static void writeShort(final byte[] b, final int index, final int s) {
- b[index] = (byte) (s >>> 8);
- b[index + 1] = (byte) s;
- }
-
- /**
- * Computes the future value of a bytecode offset.
- * <p>
- * Note: it is possible to have several entries for the same instruction in
- * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and
- * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
- *
- * @param indexes
- * current positions of the instructions to be resized. Each
- * instruction must be designated by the index of its <i>last</i>
- * byte, plus one (or, in other words, by the index of the
- * <i>first</i> byte of the <i>next</i> instruction).
- * @param sizes
- * the number of bytes to be <i>added</i> to the above
- * instructions. More precisely, for each i < <tt>len</tt>,
- * <tt>sizes</tt>[i] bytes will be added at the end of the
- * instruction designated by <tt>indexes</tt>[i] or, if
- * <tt>sizes</tt>[i] is negative, the <i>last</i> |
- * <tt>sizes[i]</tt>| bytes of the instruction will be removed
- * (the instruction size <i>must not</i> become negative or
- * null).
- * @param begin
- * index of the first byte of the source instruction.
- * @param end
- * index of the first byte of the target instruction.
- * @return the future value of the given bytecode offset.
- */
- static int getNewOffset(final int[] indexes, final int[] sizes,
- final int begin, final int end) {
- int offset = end - begin;
- for (int i = 0; i < indexes.length; ++i) {
- if (begin < indexes[i] && indexes[i] <= end) {
- // forward jump
- offset += sizes[i];
- } else if (end < indexes[i] && indexes[i] <= begin) {
- // backward jump
- offset -= sizes[i];
- }
- }
- return offset;
- }
-
- /**
- * Updates the offset of the given label.
- *
- * @param indexes
- * current positions of the instructions to be resized. Each
- * instruction must be designated by the index of its <i>last</i>
- * byte, plus one (or, in other words, by the index of the
- * <i>first</i> byte of the <i>next</i> instruction).
- * @param sizes
- * the number of bytes to be <i>added</i> to the above
- * instructions. More precisely, for each i < <tt>len</tt>,
- * <tt>sizes</tt>[i] bytes will be added at the end of the
- * instruction designated by <tt>indexes</tt>[i] or, if
- * <tt>sizes</tt>[i] is negative, the <i>last</i> |
- * <tt>sizes[i]</tt>| bytes of the instruction will be removed
- * (the instruction size <i>must not</i> become negative or
- * null).
- * @param label
- * the label whose offset must be updated.
- */
- static void getNewOffset(final int[] indexes, final int[] sizes,
- final Label label) {
- if ((label.status & Label.RESIZED) == 0) {
- label.position = getNewOffset(indexes, sizes, 0, label.position);
- label.status |= Label.RESIZED;
- }
- }
}
< prev index next >