8343436: Regression in StackMapGenerator after JDK-8339205

Reviewed-by: liach
This commit is contained in:
Adam Sotona 2024-11-04 07:19:23 +00:00
parent 2432c4f862
commit f9e1c62dcd
2 changed files with 131 additions and 302 deletions

View file

@ -349,7 +349,6 @@ public final class StackMapGenerator {
var it = handlers.listIterator(); var it = handlers.listIterator();
while (it.hasNext()) { while (it.hasNext()) {
var e = it.next(); var e = it.next();
var labelContext = this.labelContext;
int handlerStart = labelContext.labelToBci(e.tryStart()); int handlerStart = labelContext.labelToBci(e.tryStart());
int handlerEnd = labelContext.labelToBci(e.tryEnd()); int handlerEnd = labelContext.labelToBci(e.tryEnd());
if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
@ -391,15 +390,14 @@ public final class StackMapGenerator {
return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) {
@Override @Override
public void writeBody(BufWriterImpl b) { public void writeBody(BufWriterImpl b) {
var gen = StackMapGenerator.this; b.writeU2(framesCount);
b.writeU2(gen.framesCount); Frame prevFrame = new Frame(classHierarchy);
Frame prevFrame = gen.new Frame(gen.classHierarchy); prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType);
prevFrame.setLocalsFromArg(gen.methodName, gen.methodDesc, gen.isStatic, gen.thisType);
prevFrame.trimAndCompress(); prevFrame.trimAndCompress();
for (int i = 0; i < gen.framesCount; i++) { for (int i = 0; i < framesCount; i++) {
var fr = gen.frames[i]; var fr = frames[i];
fr.trimAndCompress(); fr.trimAndCompress();
fr.writeTo(b, prevFrame, gen.cp); fr.writeTo(b, prevFrame, cp);
prevFrame = fr; prevFrame = fr;
} }
} }
@ -462,7 +460,6 @@ public final class StackMapGenerator {
processExceptionHandlerTargets(bci, this_uninit); processExceptionHandlerTargets(bci, this_uninit);
verified_exc_handlers = true; verified_exc_handlers = true;
} }
var currentFrame = this.currentFrame;
switch (opcode) { switch (opcode) {
case NOP -> {} case NOP -> {}
case RETURN -> { case RETURN -> {
@ -503,27 +500,27 @@ public final class StackMapGenerator {
case ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 -> case ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 ->
currentFrame.pushStack(currentFrame.getLocal(opcode - ALOAD_0)); currentFrame.pushStack(currentFrame.getLocal(opcode - ALOAD_0));
case IALOAD, BALOAD, CALOAD, SALOAD -> case IALOAD, BALOAD, CALOAD, SALOAD ->
currentFrame.decStack2PushStack(Type.INTEGER_TYPE); currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
case LALOAD -> case LALOAD ->
currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case FALOAD -> case FALOAD ->
currentFrame.decStack2PushStack(Type.FLOAT_TYPE); currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
case DALOAD -> case DALOAD ->
currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case AALOAD -> case AALOAD ->
currentFrame.pushStack((type1 = currentFrame.decStack().popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent()); currentFrame.pushStack((type1 = currentFrame.decStack(1).popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent());
case ISTORE -> case ISTORE ->
currentFrame.decStack().setLocal(bcs.getIndex(), Type.INTEGER_TYPE); currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.INTEGER_TYPE);
case ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3 -> case ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3 ->
currentFrame.decStack().setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE); currentFrame.decStack(1).setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE);
case LSTORE -> case LSTORE ->
currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.LONG_TYPE, Type.LONG2_TYPE);
case LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 -> case LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 ->
currentFrame.decStack(2).setLocal2(opcode - LSTORE_0, Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(2).setLocal2(opcode - LSTORE_0, Type.LONG_TYPE, Type.LONG2_TYPE);
case FSTORE -> case FSTORE ->
currentFrame.decStack().setLocal(bcs.getIndex(), Type.FLOAT_TYPE); currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.FLOAT_TYPE);
case FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3 -> case FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3 ->
currentFrame.decStack().setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE); currentFrame.decStack(1).setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE);
case DSTORE -> case DSTORE ->
currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 -> case DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 ->
@ -537,75 +534,98 @@ public final class StackMapGenerator {
case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE -> case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE ->
currentFrame.decStack(3); currentFrame.decStack(3);
case POP, MONITORENTER, MONITOREXIT -> case POP, MONITORENTER, MONITOREXIT ->
currentFrame.decStack(); currentFrame.decStack(1);
case POP2 -> case POP2 ->
currentFrame.decStack(2); currentFrame.decStack(2);
case DUP -> case DUP ->
currentFrame.dup(); currentFrame.pushStack(type1 = currentFrame.popStack()).pushStack(type1);
case DUP_X1 -> case DUP_X1 -> {
currentFrame.dup_x1(); type1 = currentFrame.popStack();
case DUP_X2 -> type2 = currentFrame.popStack();
currentFrame.dup_x2(); currentFrame.pushStack(type1).pushStack(type2).pushStack(type1);
case DUP2 -> }
currentFrame.dup2(); case DUP_X2 -> {
case DUP2_X1 -> type1 = currentFrame.popStack();
currentFrame.dup2_x1(); type2 = currentFrame.popStack();
case DUP2_X2 -> type3 = currentFrame.popStack();
currentFrame.dup2_x2(); currentFrame.pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1);
case SWAP -> }
currentFrame.swap(); case DUP2 -> {
type1 = currentFrame.popStack();
type2 = currentFrame.popStack();
currentFrame.pushStack(type2).pushStack(type1).pushStack(type2).pushStack(type1);
}
case DUP2_X1 -> {
type1 = currentFrame.popStack();
type2 = currentFrame.popStack();
type3 = currentFrame.popStack();
currentFrame.pushStack(type2).pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1);
}
case DUP2_X2 -> {
type1 = currentFrame.popStack();
type2 = currentFrame.popStack();
type3 = currentFrame.popStack();
type4 = currentFrame.popStack();
currentFrame.pushStack(type2).pushStack(type1).pushStack(type4).pushStack(type3).pushStack(type2).pushStack(type1);
}
case SWAP -> {
type1 = currentFrame.popStack();
type2 = currentFrame.popStack();
currentFrame.pushStack(type1);
currentFrame.pushStack(type2);
}
case IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND -> case IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND ->
currentFrame.decStack2PushStack(Type.INTEGER_TYPE); currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
case INEG, ARRAYLENGTH, INSTANCEOF -> case INEG, ARRAYLENGTH, INSTANCEOF ->
currentFrame.decStack1PushStack(Type.INTEGER_TYPE); currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE);
case LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR -> case LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR ->
currentFrame.decStack4PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(4).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case LNEG -> case LNEG ->
currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case LSHL, LSHR, LUSHR -> case LSHL, LSHR, LUSHR ->
currentFrame.decStack3PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(3).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case FADD, FSUB, FMUL, FDIV, FREM -> case FADD, FSUB, FMUL, FDIV, FREM ->
currentFrame.decStack2PushStack(Type.FLOAT_TYPE); currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
case FNEG -> case FNEG ->
currentFrame.decStack1PushStack(Type.FLOAT_TYPE); currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE);
case DADD, DSUB, DMUL, DDIV, DREM -> case DADD, DSUB, DMUL, DDIV, DREM ->
currentFrame.decStack4PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(4).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case DNEG -> case DNEG ->
currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case IINC -> case IINC ->
currentFrame.checkLocal(bcs.getIndex()); currentFrame.checkLocal(bcs.getIndex());
case I2L -> case I2L ->
currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case L2I -> case L2I ->
currentFrame.decStack2PushStack(Type.INTEGER_TYPE); currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
case I2F -> case I2F ->
currentFrame.decStack1PushStack(Type.FLOAT_TYPE); currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE);
case I2D -> case I2D ->
currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case L2F -> case L2F ->
currentFrame.decStack2PushStack(Type.FLOAT_TYPE); currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
case L2D -> case L2D ->
currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case F2I -> case F2I ->
currentFrame.decStack1PushStack(Type.INTEGER_TYPE); currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE);
case F2L -> case F2L ->
currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case F2D -> case F2D ->
currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
case D2L -> case D2L ->
currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE); currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
case D2F -> case D2F ->
currentFrame.decStack2PushStack(Type.FLOAT_TYPE); currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
case I2B, I2C, I2S -> case I2B, I2C, I2S ->
currentFrame.decStack1PushStack(Type.INTEGER_TYPE); currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE);
case LCMP, DCMPL, DCMPG -> case LCMP, DCMPL, DCMPG ->
currentFrame.decStack4PushStack(Type.INTEGER_TYPE); currentFrame.decStack(4).pushStack(Type.INTEGER_TYPE);
case FCMPL, FCMPG, D2I -> case FCMPL, FCMPG, D2I ->
currentFrame.decStack2PushStack(Type.INTEGER_TYPE); currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE ->
checkJumpTarget(currentFrame.decStack(2), bcs.dest()); checkJumpTarget(currentFrame.decStack(2), bcs.dest());
case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL ->
checkJumpTarget(currentFrame.decStack(), bcs.dest()); checkJumpTarget(currentFrame.decStack(1), bcs.dest());
case GOTO -> { case GOTO -> {
checkJumpTarget(currentFrame, bcs.dest()); checkJumpTarget(currentFrame, bcs.dest());
ncf = true; ncf = true;
@ -623,7 +643,7 @@ public final class StackMapGenerator {
ncf = true; ncf = true;
} }
case IRETURN, FRETURN, ARETURN, ATHROW -> { case IRETURN, FRETURN, ARETURN, ATHROW -> {
currentFrame.decStack(); currentFrame.decStack(1);
ncf = true; ncf = true;
} }
case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD -> case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD ->
@ -633,16 +653,17 @@ public final class StackMapGenerator {
case NEW -> case NEW ->
currentFrame.pushStack(Type.uninitializedType(bci)); currentFrame.pushStack(Type.uninitializedType(bci));
case NEWARRAY -> case NEWARRAY ->
currentFrame.decStack1PushStack(getNewarrayType(bcs.getIndex())); currentFrame.decStack(1).pushStack(getNewarrayType(bcs.getIndex()));
case ANEWARRAY -> case ANEWARRAY ->
processAnewarray(bcs.getIndexU2()); processAnewarray(bcs.getIndexU2());
case CHECKCAST -> case CHECKCAST ->
currentFrame.decStack1PushStack(cpIndexToType(bcs.getIndexU2(), cp)); currentFrame.decStack(1).pushStack(cpIndexToType(bcs.getIndexU2(), cp));
case MULTIANEWARRAY -> { case MULTIANEWARRAY -> {
type1 = cpIndexToType(bcs.getIndexU2(), cp); type1 = cpIndexToType(bcs.getIndexU2(), cp);
currentFrame.decStack( int dim = bcs.getU1Unchecked(bcs.bci() + 3);
bcs.getU1Unchecked(bcs.bci() + 3) /* dim */ for (int i = 0; i < dim; i++) {
); currentFrame.popStack();
}
currentFrame.pushStack(type1); currentFrame.pushStack(type1);
} }
case JSR, JSR_W, RET -> case JSR, JSR_W, RET ->
@ -657,7 +678,6 @@ public final class StackMapGenerator {
} }
private void processExceptionHandlerTargets(int bci, boolean this_uninit) { private void processExceptionHandlerTargets(int bci, boolean this_uninit) {
var currentFrame = this.currentFrame;
for (var ex : rawHandlers) { for (var ex : rawHandlers) {
if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) { if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) {
int flags = currentFrame.flags; int flags = currentFrame.flags;
@ -670,10 +690,7 @@ public final class StackMapGenerator {
} }
private void processLdc(int index) { private void processLdc(int index) {
var e = cp.entryByIndex(index); switch (cp.entryByIndex(index).tag()) {
byte tag = e.tag();
var currentFrame = this.currentFrame;
switch (tag) {
case TAG_UTF8 -> case TAG_UTF8 ->
currentFrame.pushStack(Type.OBJECT_TYPE); currentFrame.pushStack(Type.OBJECT_TYPE);
case TAG_STRING -> case TAG_STRING ->
@ -693,9 +710,9 @@ public final class StackMapGenerator {
case TAG_METHOD_TYPE -> case TAG_METHOD_TYPE ->
currentFrame.pushStack(Type.METHOD_TYPE); currentFrame.pushStack(Type.METHOD_TYPE);
case TAG_DYNAMIC -> case TAG_DYNAMIC ->
currentFrame.pushStack(ClassReaderImpl.checkType(e, index, ConstantDynamicEntry.class).asSymbol().constantType()); currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType());
default -> default ->
throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, tag)); throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag()));
} }
} }
@ -704,7 +721,7 @@ public final class StackMapGenerator {
int alignedBci = RawBytecodeHelper.align(bci + 1); int alignedBci = RawBytecodeHelper.align(bci + 1);
int defaultOffset = bcs.getIntUnchecked(alignedBci); int defaultOffset = bcs.getIntUnchecked(alignedBci);
int keys, delta; int keys, delta;
currentFrame.decStack(); currentFrame.popStack();
if (bcs.opcode() == TABLESWITCH) { if (bcs.opcode() == TABLESWITCH) {
int low = bcs.getIntUnchecked(alignedBci + 4); int low = bcs.getIntUnchecked(alignedBci + 4);
int high = bcs.getIntUnchecked(alignedBci + 2 * 4); int high = bcs.getIntUnchecked(alignedBci + 2 * 4);
@ -748,7 +765,8 @@ public final class StackMapGenerator {
currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1); currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1);
} }
case GETFIELD -> { case GETFIELD -> {
currentFrame.dec1PushStack(desc); currentFrame.decStack(1);
currentFrame.pushStack(desc);
} }
case PUTFIELD -> { case PUTFIELD -> {
currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2); currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2);
@ -786,7 +804,7 @@ public final class StackMapGenerator {
throw generatorError("Bad operand type when invoking <init>"); throw generatorError("Bad operand type when invoking <init>");
} }
} else { } else {
currentFrame.decStack(); currentFrame.decStack(1);
} }
} }
currentFrame.pushStack(mDesc.returnType()); currentFrame.pushStack(mDesc.returnType());
@ -799,17 +817,10 @@ public final class StackMapGenerator {
} }
private void processAnewarray(int index) { private void processAnewarray(int index) {
currentFrame.decStack(); currentFrame.popStack();
currentFrame.pushStack(cpIndexToType(index, cp).toArray()); currentFrame.pushStack(cpIndexToType(index, cp).toArray());
} }
/**
* {@return the generator error with stack underflow}
*/
private IllegalArgumentException stackUnderflow() {
return generatorError("Operand stack underflow");
}
/** /**
* {@return the generator error with attached details} * {@return the generator error with attached details}
* @param msg error message * @param msg error message
@ -889,7 +900,6 @@ public final class StackMapGenerator {
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
throw generatorError("Detected branch target out of bytecode range", bci); throw generatorError("Detected branch target out of bytecode range", bci);
} }
for (int i = 0; i < rawHandlers.size(); i++) try { for (int i = 0; i < rawHandlers.size(); i++) try {
addFrame(rawHandlers.get(i).handler()); addFrame(rawHandlers.get(i).handler());
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
@ -958,101 +968,6 @@ public final class StackMapGenerator {
return (dirty ? "frame* @" : "frame @") + offset + " with locals " + (locals == null ? "[]" : Arrays.asList(locals).subList(0, localsSize)) + " and stack " + (stack == null ? "[]" : Arrays.asList(stack).subList(0, stackSize)); return (dirty ? "frame* @" : "frame @") + offset + " with locals " + (locals == null ? "[]" : Arrays.asList(locals).subList(0, localsSize)) + " and stack " + (stack == null ? "[]" : Arrays.asList(stack).subList(0, stackSize));
} }
Frame dup() {
int stackSize = this.stackSize;
if (stackSize < 1) throw stackUnderflow();
checkStack(stackSize + 1);
stack[stackSize] = stack[stackSize - 1];
this.stackSize = stackSize + 1;
return this;
}
Frame dup_x1() {
int stackSize = this.stackSize;
if (stackSize < 2) throw stackUnderflow();
checkStack(stackSize + 1);
var stack = this.stack;
Type type0 = stack[stackSize - 2];
Type type1 = stack[stackSize - 1];
stack[stackSize - 2] = type1;
stack[stackSize - 1] = type0;
stack[stackSize ] = type1;
this.stackSize = stackSize + 1;
return this;
}
Frame dup_x2() {
int stackSize = this.stackSize;
if (stackSize < 3) throw stackUnderflow();
checkStack(stackSize + 1);
var stack = this.stack;
Type type0 = stack[stackSize - 3];
Type type1 = stack[stackSize - 2];
Type type2 = stack[stackSize - 1];
stack[stackSize - 3] = type2;
stack[stackSize - 2] = type0;
stack[stackSize - 1] = type1;
stack[stackSize ] = type2;
this.stackSize = stackSize + 1;
return this;
}
Frame dup2() {
int stackSize = this.stackSize;
if (stackSize < 2) throw stackUnderflow();
checkStack(stackSize + 2);
stack[stackSize ] = stack[stackSize - 2];
stack[stackSize + 1] = stack[stackSize - 1];
this.stackSize = stackSize + 2;
return this;
}
Frame dup2_x1() {
int stackSize = this.stackSize;
if (stackSize < 3) throw stackUnderflow();
checkStack(stackSize + 2);
var stack = this.stack;
Type type0 = stack[stackSize - 3];
Type type1 = stack[stackSize - 2];
Type type2 = stack[stackSize - 1];
stack[stackSize - 3] = type1;
stack[stackSize - 2] = type2;
stack[stackSize - 1] = type0;
stack[stackSize ] = type1;
stack[stackSize + 1] = type2;
this.stackSize = stackSize + 2;
return this;
}
Frame dup2_x2() {
int stackSize = this.stackSize;
if (stackSize < 4) throw stackUnderflow();
checkStack(stackSize + 2);
var stack = this.stack;
Type type0 = stack[stackSize - 4];
Type type1 = stack[stackSize - 3];
Type type2 = stack[stackSize - 2];
Type type3 = stack[stackSize - 1];
stack[stackSize - 4] = type2;
stack[stackSize - 3] = type3;
stack[stackSize - 2] = type0;
stack[stackSize - 1] = type1;
stack[stackSize ] = type2;
stack[stackSize + 1] = type3;
this.stackSize = stackSize + 4;
return this;
}
Frame swap() {
int stackSize = this.stackSize - 2;
if (stackSize < 0) throw stackUnderflow();
var stack = this.stack;
Type type = stack[stackSize];
stack[stackSize] = stack[stackSize + 1];
stack[stackSize + 1] = type;
return this;
}
Frame pushStack(ClassDesc desc) { Frame pushStack(ClassDesc desc) {
if (desc == CD_long) return pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); if (desc == CD_long) return pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
@ -1063,109 +978,27 @@ public final class StackMapGenerator {
: Type.referenceType(desc)); : Type.referenceType(desc));
} }
Frame dec1PushStack(ClassDesc desc) {
if (desc == CD_long) return decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
if (desc == CD_double) return decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
return desc == CD_void ? this
: decStack1PushStack(
desc.isPrimitive()
? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE)
: Type.referenceType(desc));
}
Frame pushStack(Type type) { Frame pushStack(Type type) {
int stackSize = this.stackSize;
checkStack(stackSize); checkStack(stackSize);
stack[stackSize] = type; stack[stackSize++] = type;
this.stackSize = stackSize + 1;
return this; return this;
} }
Frame pushStack(Type type1, Type type2) { Frame pushStack(Type type1, Type type2) {
int stackSize = this.stackSize;
checkStack(stackSize + 1); checkStack(stackSize + 1);
stack[stackSize] = type1; stack[stackSize++] = type1;
stack[stackSize + 1] = type2; stack[stackSize++] = type2;
this.stackSize = stackSize + 2;
return this; return this;
} }
Type popStack() { Type popStack() {
int stackSize = this.stackSize - 1; if (stackSize < 1) throw generatorError("Operand stack underflow");
if (stackSize < 0) throw stackUnderflow(); return stack[--stackSize];
this.stackSize = stackSize;
return stack[stackSize];
}
Frame decStack() {
if (--stackSize < 0) throw stackUnderflow();
return this;
} }
Frame decStack(int size) { Frame decStack(int size) {
stackSize -= size; stackSize -= size;
if (stackSize < 0) throw stackUnderflow(); if (stackSize < 0) throw generatorError("Operand stack underflow");
return this;
}
Frame decStack1PushStack(Type type1, Type type2) {
int stackSize = this.stackSize - 1;
if (stackSize < 0) throw stackUnderflow();
checkStack(stackSize + 2);
stack[stackSize ] = type1;
stack[stackSize + 1] = type2;
this.stackSize = stackSize + 2;
return this;
}
Frame decStack1PushStack(Type type) {
int stackSize = this.stackSize - 1;
if (stackSize < 0) throw stackUnderflow();
stack[stackSize] = type;
return this;
}
Frame decStack2PushStack(Type type) {
int stackSize = this.stackSize - 2;
if (stackSize < 0) throw stackUnderflow();
stack[stackSize] = type;
this.stackSize = stackSize + 1;
return this;
}
Frame decStack2PushStack(Type type1, Type type2) {
int stackSize = this.stackSize - 2;
if (stackSize < 0) throw stackUnderflow();
var stack = this.stack;
stack[stackSize ] = type1;
stack[stackSize + 1] = type2;
return this;
}
Frame decStack3PushStack(Type type1, Type type2) {
int stackSize = this.stackSize - 3;
if (stackSize < 0) throw stackUnderflow();
stack[stackSize ] = type1;
stack[stackSize + 1] = type2;
this.stackSize = stackSize + 2;
return this;
}
Frame decStack4PushStack(Type type) {
int stackSize = this.stackSize - 4;
if (stackSize < 0) throw stackUnderflow();
stack[stackSize] = type;
this.stackSize = stackSize + 1;
return this;
}
Frame decStack4PushStack(Type type1, Type type2) {
int stackSize = this.stackSize - 4;
if (stackSize < 0) throw stackUnderflow();
var stack = this.stack;
stack[stackSize ] = type1;
stack[stackSize + 1] = type2;
this.stackSize = stackSize + 2;
return this; return this;
} }
@ -1194,59 +1027,34 @@ public final class StackMapGenerator {
Frame checkLocal(int index) { Frame checkLocal(int index) {
if (index >= frameMaxLocals) frameMaxLocals = index + 1; if (index >= frameMaxLocals) frameMaxLocals = index + 1;
if (locals == null) { if (locals == null) {
initLocals(index); locals = new Type[index + FRAME_DEFAULT_CAPACITY];
Arrays.fill(locals, Type.TOP_TYPE);
} else if (index >= locals.length) { } else if (index >= locals.length) {
growLocals(index); int current = locals.length;
locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY);
Arrays.fill(locals, current, locals.length, Type.TOP_TYPE);
} }
return this; return this;
} }
private void initLocals(int index) {
locals = new Type[index + FRAME_DEFAULT_CAPACITY];
Arrays.fill(locals, Type.TOP_TYPE);
}
private void growLocals(int index) {
int current = locals.length;
locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY);
Arrays.fill(locals, current, locals.length, Type.TOP_TYPE);
}
private void checkStack(int index) { private void checkStack(int index) {
if (index >= frameMaxStack) frameMaxStack = index + 1; if (index >= frameMaxStack) frameMaxStack = index + 1;
if (stack == null) { if (stack == null) {
initStack(index); stack = new Type[index + FRAME_DEFAULT_CAPACITY];
Arrays.fill(stack, Type.TOP_TYPE);
} else if (index >= stack.length) { } else if (index >= stack.length) {
growStack(index); int current = stack.length;
stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY);
Arrays.fill(stack, current, stack.length, Type.TOP_TYPE);
} }
} }
private void initStack(int index) {
stack = new Type[index + FRAME_DEFAULT_CAPACITY];
Arrays.fill(stack, Type.TOP_TYPE);
}
private void growStack(int index) {
int current = stack.length;
stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY);
Arrays.fill(stack, current, stack.length, Type.TOP_TYPE);
}
private void setLocalRawInternal(int index, Type type) { private void setLocalRawInternal(int index, Type type) {
checkLocal(index); checkLocal(index);
var locals = this.locals;
localsChanged |= !type.equals(locals[index]); localsChanged |= !type.equals(locals[index]);
locals[index] = type; locals[index] = type;
} }
private void setLocalRawInternal(int index, Type type1, Type type2) {
checkLocal(index + 1);
var locals = this.locals;
localsChanged |= !type1.equals(locals[index]) || !type2.equals(locals[index + 1]);
locals[index ] = type1;
locals[index + 1] = type2;
}
void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) {
int localsSize = 0; int localsSize = 0;
// Pre-emptively create a locals array that encompass all parameter slots // Pre-emptively create a locals array that encompass all parameter slots
@ -1347,7 +1155,8 @@ public final class StackMapGenerator {
Type old = getLocalRawInternal(index); Type old = getLocalRawInternal(index);
if (old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE) { if (old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE) {
setLocalRawInternal(index + 1, Type.TOP_TYPE); setLocalRawInternal(index + 1, Type.TOP_TYPE);
} else if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { }
if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) {
setLocalRawInternal(index - 1, Type.TOP_TYPE); setLocalRawInternal(index - 1, Type.TOP_TYPE);
} }
setLocalRawInternal(index, type); setLocalRawInternal(index, type);
@ -1365,7 +1174,8 @@ public final class StackMapGenerator {
if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) {
setLocalRawInternal(index - 1, Type.TOP_TYPE); setLocalRawInternal(index - 1, Type.TOP_TYPE);
} }
setLocalRawInternal(index, type1, type2); setLocalRawInternal(index, type1);
setLocalRawInternal(index + 1, type2);
if (index >= localsSize - 1) { if (index >= localsSize - 1) {
localsSize = index + 2; localsSize = index + 2;
} }

View file

@ -24,7 +24,7 @@
/* /*
* @test * @test
* @summary Testing Classfile stack maps generator. * @summary Testing Classfile stack maps generator.
* @bug 8305990 8320222 8320618 8335475 8338623 8338661 * @bug 8305990 8320222 8320618 8335475 8338623 8338661 8343436
* @build testdata.* * @build testdata.*
* @run junit StackMapsTest * @run junit StackMapsTest
*/ */
@ -344,8 +344,27 @@ class StackMapsTest {
} }
} }
@ParameterizedTest
@EnumSource(ClassFile.StackMapsOption.class)
void testI2LCounters(ClassFile.StackMapsOption option) {
var cf = ClassFile.of(option);
var bytes = cf.build(ClassDesc.of("Test"), clb -> clb
.withMethodBody("a", MTD_long_int, ACC_STATIC, cob ->
cob.iload(0)
.i2l()
.lreturn()));
var cm = ClassFile.of().parse(bytes);
for (var method : cm.methods()) {
var code = (CodeAttribute) method.code().orElseThrow();
assertEquals(1, code.maxLocals());
assertEquals(2, code.maxStack());
}
}
private static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int); private static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int);
private static final MethodTypeDesc MTD_int_String = MethodTypeDesc.of(CD_int, CD_String); private static final MethodTypeDesc MTD_int_String = MethodTypeDesc.of(CD_int, CD_String);
private static final MethodTypeDesc MTD_long_int = MethodTypeDesc.of(CD_long, CD_int);
@ParameterizedTest @ParameterizedTest
@EnumSource(ClassFile.StackMapsOption.class) @EnumSource(ClassFile.StackMapsOption.class)