diff options
author | Olivier Thomann | 2012-09-26 08:29:51 +0000 |
---|---|---|
committer | Jayaprakash Arthanareeswaran | 2012-10-19 04:49:05 +0000 |
commit | a00bb5eefc5dc1b2770154375a5f65dad7ebaf03 (patch) | |
tree | 3dc087e61562f5201d56fb2bf3f1fb8ffa7009ef | |
parent | 99610839b414c1a151891246c04d5389bbb2fe00 (diff) | |
download | eclipse.jdt.core-a00bb5eefc5dc1b2770154375a5f65dad7ebaf03.tar.gz eclipse.jdt.core-a00bb5eefc5dc1b2770154375a5f65dad7ebaf03.tar.xz eclipse.jdt.core-a00bb5eefc5dc1b2770154375a5f65dad7ebaf03.zip |
Fix for bug 385593: [compiler] Unexpected stackmap frames
2 files changed, 88 insertions, 23 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java index e50b97dbbf..2e5452338f 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java @@ -1162,12 +1162,11 @@ public class StackMapAttributeTest extends AbstractRegressionTest { " [pc: 19, pc: 102] local: x index: 1 type: X\n" + " [pc: 2, pc: 111] local: i index: 2 type: int\n" + " [pc: 90, pc: 102] local: diff index: 3 type: java.lang.Object\n" + - " Stack map table: number of frames 8\n" + + " Stack map table: number of frames 7\n" + " [pc: 5, full, stack: {}, locals: {java.lang.String[], _, int}]\n" + " [pc: 38, full, stack: {}, locals: {java.lang.String[], X, int}]\n" + " [pc: 44, same]\n" + " [pc: 64, same]\n" + - " [pc: 82, same]\n" + " [pc: 85, same]\n" + " [pc: 102, full, stack: {}, locals: {java.lang.String[], _, int}]\n" + " [pc: 105, same]\n"; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java index b2b2f9c87f..14dfa14df3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -18,8 +18,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import org.eclipse.jdt.core.compiler.CategorizedProblem; @@ -3191,9 +3194,9 @@ public class ClassFile implements TypeConstants, TypeIds { StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.removeFramePosition(code_length); if (stackMapFrameCodeStream.hasFramePositions()) { - ArrayList frames = new ArrayList(); - traverse(isClinit ? null : methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit); - int numberOfFrames = frames.size(); + Map frames = new HashMap(); + List realFrames = traverse(isClinit ? null : methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit); + int numberOfFrames = realFrames.size(); if (numberOfFrames > 1) { int stackMapTableAttributeOffset = localContentsOffset; // add the stack map table attribute @@ -3216,10 +3219,10 @@ public class ClassFile implements TypeConstants, TypeIds { if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } - StackMapFrame currentFrame = (StackMapFrame) frames.get(0); + StackMapFrame currentFrame = (StackMapFrame) realFrames.get(0); for (int j = 1; j < numberOfFrames; j++) { // select next frame - currentFrame = (StackMapFrame) frames.get(j); + currentFrame = (StackMapFrame) realFrames.get(j); // generate current frame // need to find differences between the current frame and the previous frame int frameOffset = currentFrame.pc; @@ -3368,9 +3371,9 @@ public class ClassFile implements TypeConstants, TypeIds { StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.removeFramePosition(code_length); if (stackMapFrameCodeStream.hasFramePositions()) { - ArrayList frames = new ArrayList(); - traverse(isClinit ? null: methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit); - int numberOfFrames = frames.size(); + Map frames = new HashMap(); + List realFrames = traverse(isClinit ? null: methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit); + int numberOfFrames = realFrames.size(); if (numberOfFrames > 1) { int stackMapTableAttributeOffset = localContentsOffset; // add the stack map table attribute @@ -3393,12 +3396,12 @@ public class ClassFile implements TypeConstants, TypeIds { if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } - StackMapFrame currentFrame = (StackMapFrame) frames.get(0); + StackMapFrame currentFrame = (StackMapFrame) realFrames.get(0); StackMapFrame prevFrame = null; for (int j = 1; j < numberOfFrames; j++) { // select next frame prevFrame = currentFrame; - currentFrame = (StackMapFrame) frames.get(j); + currentFrame = (StackMapFrame) realFrames.get(j); // generate current frame // need to find differences between the current frame and the previous frame int offsetDelta = currentFrame.getOffsetDelta(prevFrame); @@ -3835,7 +3838,6 @@ public class ClassFile implements TypeConstants, TypeIds { methodSignature.length); } - private final int i4At(byte[] reference, int relativeOffset, int structOffset) { int position = relativeOffset + structOffset; @@ -4244,8 +4246,32 @@ public class ClassFile implements TypeConstants, TypeIds { this.methodCountOffset = this.contentsOffset; this.contentsOffset += 2; } + + private List filterFakeFrames(Set realJumpTargets, Map frames, int codeLength) { + // no more frame to generate + // filter out "fake" frames + realJumpTargets.remove(new Integer(codeLength)); + List result = new ArrayList(); + for (Iterator iterator = realJumpTargets.iterator(); iterator.hasNext(); ) { + Integer jumpTarget = (Integer) iterator.next(); + StackMapFrame frame = (StackMapFrame) frames.get(jumpTarget); + if (frame != null) { + result.add(frame); + } + } + Collections.sort(result, new Comparator() { + public int compare(Object o1, Object o2) { + StackMapFrame frame = (StackMapFrame) o1; + StackMapFrame frame2 = (StackMapFrame) o2; + return frame.pc - frame2.pc; + } + }); + return result; + } + + public List traverse(MethodBinding methodBinding, int maxLocals, byte[] bytecodes, int codeOffset, int codeLength, Map frames, boolean isClinit) { + Set realJumpTarget = new HashSet(); - public void traverse(MethodBinding methodBinding, int maxLocals, byte[] bytecodes, int codeOffset, int codeLength, ArrayList frames, boolean isClinit) { StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; int[] framePositions = stackMapFrameCodeStream.getFramePositions(); int pc = codeOffset; @@ -4293,7 +4319,14 @@ public class ClassFile implements TypeConstants, TypeIds { initializeDefaultLocals(frame, methodBinding, maxLocals, codeLength); } frame.pc = -1; - frames.add(frame.duplicate()); + add(frames, frame.duplicate()); + addRealJumpTarget(realJumpTarget, -1); + for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { + ExceptionLabel exceptionLabel = this.codeStream.exceptionLabels[i]; + if (exceptionLabel != null) { + addRealJumpTarget(realJumpTarget, exceptionLabel.position); + } + } while (true) { int currentPC = pc - codeOffset; if (hasStackMarkers && stackMarker.pc == currentPC) { @@ -4346,8 +4379,7 @@ public class ClassFile implements TypeConstants, TypeIds { if (indexInFramePositions < framePositionsLength) { currentFramePosition = framePositions[indexInFramePositions]; } else { - // no more frame to generate - return; + currentFramePosition = Integer.MAX_VALUE; } } while (currentFramePosition < currentPC); } @@ -4358,13 +4390,12 @@ public class ClassFile implements TypeConstants, TypeIds { // initialize locals initializeLocals(isClinit ? true : methodBinding.isStatic(), currentPC, currentFrame); // insert a new frame - frames.add(currentFrame); + add(frames, currentFrame); indexInFramePositions++; if (indexInFramePositions < framePositionsLength) { currentFramePosition = framePositions[indexInFramePositions]; } else { - // no more frame to generate - return; + currentFramePosition = Integer.MAX_VALUE; } } byte opcode = (byte) u1At(bytecodes, 0, pc); @@ -4910,6 +4941,7 @@ public class ClassFile implements TypeConstants, TypeIds { case Opcodes.OPC_ifgt: case Opcodes.OPC_ifle: frame.numberOfStackItems--; + addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc)); pc += 3; break; case Opcodes.OPC_if_icmpeq: @@ -4921,23 +4953,32 @@ public class ClassFile implements TypeConstants, TypeIds { case Opcodes.OPC_if_acmpeq: case Opcodes.OPC_if_acmpne: frame.numberOfStackItems -= 2; + addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc)); pc += 3; break; case Opcodes.OPC_goto: + addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc)); pc += 3; + addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_tableswitch: pc++; while (((pc - codeOffset) & 0x03) != 0) { pc++; } + // default offset + addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc)); pc += 4; // default int low = i4At(bytecodes, 0, pc); pc += 4; int high = i4At(bytecodes, 0, pc); pc += 4; int length = high - low + 1; - pc += (length * 4); + for (int i = 0; i < length; i++) { + // pair offset + addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc)); + pc += 4; + } frame.numberOfStackItems--; break; case Opcodes.OPC_lookupswitch: @@ -4945,9 +4986,16 @@ public class ClassFile implements TypeConstants, TypeIds { while (((pc - codeOffset) & 0x03) != 0) { pc++; } - pc += 4; // default + addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc)); + pc += 4; // default offset int npairs = (int) u4At(bytecodes, 0, pc); - pc += (4 + npairs * 8); + pc += 4; // npair value + for (int i = 0; i < npairs; i++) { + pc += 4; // case value + // pair offset + addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc)); + pc += 4; + } frame.numberOfStackItems--; break; case Opcodes.OPC_ireturn: @@ -4957,9 +5005,11 @@ public class ClassFile implements TypeConstants, TypeIds { case Opcodes.OPC_areturn: frame.numberOfStackItems--; pc++; + addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_return: pc++; + addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_getstatic: index = u2At(bytecodes, 1, pc); @@ -5362,6 +5412,7 @@ public class ClassFile implements TypeConstants, TypeIds { case Opcodes.OPC_athrow: frame.numberOfStackItems--; pc++; + addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_checkcast: index = u2At(bytecodes, 1, pc); @@ -5456,10 +5507,13 @@ public class ClassFile implements TypeConstants, TypeIds { case Opcodes.OPC_ifnull: case Opcodes.OPC_ifnonnull: frame.numberOfStackItems--; + addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc)); pc += 3; break; case Opcodes.OPC_goto_w: + addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 1, pc)); pc += 5; + addRealJumpTarget(realJumpTarget, pc - codeOffset); // handle infinite loop break; default: // should not occur this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( @@ -5477,8 +5531,15 @@ public class ClassFile implements TypeConstants, TypeIds { break; } } + return filterFakeFrames(realJumpTarget, frames, codeLength); } + private void addRealJumpTarget(Set realJumpTarget, int pc) { + realJumpTarget.add(new Integer(pc)); + } + private void add(Map frames, StackMapFrame frame) { + frames.put(new Integer(frame.pc), frame); + } private final int u1At(byte[] reference, int relativeOffset, int structOffset) { return (reference[relativeOffset + structOffset] & 0xFF); @@ -5499,6 +5560,11 @@ public class ClassFile implements TypeConstants, TypeIds { + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF)); } + private final int i2At(byte[] reference, int relativeOffset, int structOffset) { + int position = relativeOffset + structOffset; + return (reference[position++] << 8) + (reference[position] & 0xFF); + } + public char[] utf8At(byte[] reference, int absoluteOffset, int bytesAvailable) { int length = bytesAvailable; |