8343436: Regression in StackMapGenerator after JDK-8339205
Reviewed-by: liach
This commit is contained in:
parent
2432c4f862
commit
f9e1c62dcd
@ -349,7 +349,6 @@ public final class StackMapGenerator {
|
||||
var it = handlers.listIterator();
|
||||
while (it.hasNext()) {
|
||||
var e = it.next();
|
||||
var labelContext = this.labelContext;
|
||||
int handlerStart = labelContext.labelToBci(e.tryStart());
|
||||
int handlerEnd = labelContext.labelToBci(e.tryEnd());
|
||||
if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
|
||||
@ -391,15 +390,14 @@ public final class StackMapGenerator {
|
||||
return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) {
|
||||
@Override
|
||||
public void writeBody(BufWriterImpl b) {
|
||||
var gen = StackMapGenerator.this;
|
||||
b.writeU2(gen.framesCount);
|
||||
Frame prevFrame = gen.new Frame(gen.classHierarchy);
|
||||
prevFrame.setLocalsFromArg(gen.methodName, gen.methodDesc, gen.isStatic, gen.thisType);
|
||||
b.writeU2(framesCount);
|
||||
Frame prevFrame = new Frame(classHierarchy);
|
||||
prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType);
|
||||
prevFrame.trimAndCompress();
|
||||
for (int i = 0; i < gen.framesCount; i++) {
|
||||
var fr = gen.frames[i];
|
||||
for (int i = 0; i < framesCount; i++) {
|
||||
var fr = frames[i];
|
||||
fr.trimAndCompress();
|
||||
fr.writeTo(b, prevFrame, gen.cp);
|
||||
fr.writeTo(b, prevFrame, cp);
|
||||
prevFrame = fr;
|
||||
}
|
||||
}
|
||||
@ -462,7 +460,6 @@ public final class StackMapGenerator {
|
||||
processExceptionHandlerTargets(bci, this_uninit);
|
||||
verified_exc_handlers = true;
|
||||
}
|
||||
var currentFrame = this.currentFrame;
|
||||
switch (opcode) {
|
||||
case NOP -> {}
|
||||
case RETURN -> {
|
||||
@ -503,27 +500,27 @@ public final class StackMapGenerator {
|
||||
case ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 ->
|
||||
currentFrame.pushStack(currentFrame.getLocal(opcode - ALOAD_0));
|
||||
case IALOAD, BALOAD, CALOAD, SALOAD ->
|
||||
currentFrame.decStack2PushStack(Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
|
||||
case LALOAD ->
|
||||
currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case FALOAD ->
|
||||
currentFrame.decStack2PushStack(Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
|
||||
case DALOAD ->
|
||||
currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
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 ->
|
||||
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 ->
|
||||
currentFrame.decStack().setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(1).setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE);
|
||||
case LSTORE ->
|
||||
currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 ->
|
||||
currentFrame.decStack(2).setLocal2(opcode - LSTORE_0, Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
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 ->
|
||||
currentFrame.decStack().setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(1).setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE);
|
||||
case DSTORE ->
|
||||
currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 ->
|
||||
@ -537,75 +534,98 @@ public final class StackMapGenerator {
|
||||
case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE ->
|
||||
currentFrame.decStack(3);
|
||||
case POP, MONITORENTER, MONITOREXIT ->
|
||||
currentFrame.decStack();
|
||||
currentFrame.decStack(1);
|
||||
case POP2 ->
|
||||
currentFrame.decStack(2);
|
||||
case DUP ->
|
||||
currentFrame.dup();
|
||||
case DUP_X1 ->
|
||||
currentFrame.dup_x1();
|
||||
case DUP_X2 ->
|
||||
currentFrame.dup_x2();
|
||||
case DUP2 ->
|
||||
currentFrame.dup2();
|
||||
case DUP2_X1 ->
|
||||
currentFrame.dup2_x1();
|
||||
case DUP2_X2 ->
|
||||
currentFrame.dup2_x2();
|
||||
case SWAP ->
|
||||
currentFrame.swap();
|
||||
currentFrame.pushStack(type1 = currentFrame.popStack()).pushStack(type1);
|
||||
case DUP_X1 -> {
|
||||
type1 = currentFrame.popStack();
|
||||
type2 = currentFrame.popStack();
|
||||
currentFrame.pushStack(type1).pushStack(type2).pushStack(type1);
|
||||
}
|
||||
case DUP_X2 -> {
|
||||
type1 = currentFrame.popStack();
|
||||
type2 = currentFrame.popStack();
|
||||
type3 = currentFrame.popStack();
|
||||
currentFrame.pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1);
|
||||
}
|
||||
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 ->
|
||||
currentFrame.decStack2PushStack(Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
|
||||
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 ->
|
||||
currentFrame.decStack4PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
currentFrame.decStack(4).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case LNEG ->
|
||||
currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
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 ->
|
||||
currentFrame.decStack2PushStack(Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
|
||||
case FNEG ->
|
||||
currentFrame.decStack1PushStack(Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE);
|
||||
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 ->
|
||||
currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case IINC ->
|
||||
currentFrame.checkLocal(bcs.getIndex());
|
||||
case I2L ->
|
||||
currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case L2I ->
|
||||
currentFrame.decStack2PushStack(Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE);
|
||||
case I2F ->
|
||||
currentFrame.decStack1PushStack(Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE);
|
||||
case I2D ->
|
||||
currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case L2F ->
|
||||
currentFrame.decStack2PushStack(Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
|
||||
case L2D ->
|
||||
currentFrame.decStack2PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case F2I ->
|
||||
currentFrame.decStack1PushStack(Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE);
|
||||
case F2L ->
|
||||
currentFrame.decStack1PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case F2D ->
|
||||
currentFrame.decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case D2L ->
|
||||
currentFrame.decStack2PushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case D2F ->
|
||||
currentFrame.decStack2PushStack(Type.FLOAT_TYPE);
|
||||
currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE);
|
||||
case I2B, I2C, I2S ->
|
||||
currentFrame.decStack1PushStack(Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE);
|
||||
case LCMP, DCMPL, DCMPG ->
|
||||
currentFrame.decStack4PushStack(Type.INTEGER_TYPE);
|
||||
currentFrame.decStack(4).pushStack(Type.INTEGER_TYPE);
|
||||
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 ->
|
||||
checkJumpTarget(currentFrame.decStack(2), bcs.dest());
|
||||
case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL ->
|
||||
checkJumpTarget(currentFrame.decStack(), bcs.dest());
|
||||
checkJumpTarget(currentFrame.decStack(1), bcs.dest());
|
||||
case GOTO -> {
|
||||
checkJumpTarget(currentFrame, bcs.dest());
|
||||
ncf = true;
|
||||
@ -623,7 +643,7 @@ public final class StackMapGenerator {
|
||||
ncf = true;
|
||||
}
|
||||
case IRETURN, FRETURN, ARETURN, ATHROW -> {
|
||||
currentFrame.decStack();
|
||||
currentFrame.decStack(1);
|
||||
ncf = true;
|
||||
}
|
||||
case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD ->
|
||||
@ -633,16 +653,17 @@ public final class StackMapGenerator {
|
||||
case NEW ->
|
||||
currentFrame.pushStack(Type.uninitializedType(bci));
|
||||
case NEWARRAY ->
|
||||
currentFrame.decStack1PushStack(getNewarrayType(bcs.getIndex()));
|
||||
currentFrame.decStack(1).pushStack(getNewarrayType(bcs.getIndex()));
|
||||
case ANEWARRAY ->
|
||||
processAnewarray(bcs.getIndexU2());
|
||||
case CHECKCAST ->
|
||||
currentFrame.decStack1PushStack(cpIndexToType(bcs.getIndexU2(), cp));
|
||||
currentFrame.decStack(1).pushStack(cpIndexToType(bcs.getIndexU2(), cp));
|
||||
case MULTIANEWARRAY -> {
|
||||
type1 = cpIndexToType(bcs.getIndexU2(), cp);
|
||||
currentFrame.decStack(
|
||||
bcs.getU1Unchecked(bcs.bci() + 3) /* dim */
|
||||
);
|
||||
int dim = bcs.getU1Unchecked(bcs.bci() + 3);
|
||||
for (int i = 0; i < dim; i++) {
|
||||
currentFrame.popStack();
|
||||
}
|
||||
currentFrame.pushStack(type1);
|
||||
}
|
||||
case JSR, JSR_W, RET ->
|
||||
@ -657,7 +678,6 @@ public final class StackMapGenerator {
|
||||
}
|
||||
|
||||
private void processExceptionHandlerTargets(int bci, boolean this_uninit) {
|
||||
var currentFrame = this.currentFrame;
|
||||
for (var ex : rawHandlers) {
|
||||
if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) {
|
||||
int flags = currentFrame.flags;
|
||||
@ -670,10 +690,7 @@ public final class StackMapGenerator {
|
||||
}
|
||||
|
||||
private void processLdc(int index) {
|
||||
var e = cp.entryByIndex(index);
|
||||
byte tag = e.tag();
|
||||
var currentFrame = this.currentFrame;
|
||||
switch (tag) {
|
||||
switch (cp.entryByIndex(index).tag()) {
|
||||
case TAG_UTF8 ->
|
||||
currentFrame.pushStack(Type.OBJECT_TYPE);
|
||||
case TAG_STRING ->
|
||||
@ -693,9 +710,9 @@ public final class StackMapGenerator {
|
||||
case TAG_METHOD_TYPE ->
|
||||
currentFrame.pushStack(Type.METHOD_TYPE);
|
||||
case TAG_DYNAMIC ->
|
||||
currentFrame.pushStack(ClassReaderImpl.checkType(e, index, ConstantDynamicEntry.class).asSymbol().constantType());
|
||||
currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType());
|
||||
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 defaultOffset = bcs.getIntUnchecked(alignedBci);
|
||||
int keys, delta;
|
||||
currentFrame.decStack();
|
||||
currentFrame.popStack();
|
||||
if (bcs.opcode() == TABLESWITCH) {
|
||||
int low = bcs.getIntUnchecked(alignedBci + 4);
|
||||
int high = bcs.getIntUnchecked(alignedBci + 2 * 4);
|
||||
@ -748,7 +765,8 @@ public final class StackMapGenerator {
|
||||
currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1);
|
||||
}
|
||||
case GETFIELD -> {
|
||||
currentFrame.dec1PushStack(desc);
|
||||
currentFrame.decStack(1);
|
||||
currentFrame.pushStack(desc);
|
||||
}
|
||||
case PUTFIELD -> {
|
||||
currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2);
|
||||
@ -786,7 +804,7 @@ public final class StackMapGenerator {
|
||||
throw generatorError("Bad operand type when invoking <init>");
|
||||
}
|
||||
} else {
|
||||
currentFrame.decStack();
|
||||
currentFrame.decStack(1);
|
||||
}
|
||||
}
|
||||
currentFrame.pushStack(mDesc.returnType());
|
||||
@ -799,17 +817,10 @@ public final class StackMapGenerator {
|
||||
}
|
||||
|
||||
private void processAnewarray(int index) {
|
||||
currentFrame.decStack();
|
||||
currentFrame.popStack();
|
||||
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}
|
||||
* @param msg error message
|
||||
@ -889,7 +900,6 @@ public final class StackMapGenerator {
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw generatorError("Detected branch target out of bytecode range", bci);
|
||||
}
|
||||
|
||||
for (int i = 0; i < rawHandlers.size(); i++) try {
|
||||
addFrame(rawHandlers.get(i).handler());
|
||||
} 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));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (desc == CD_long) return pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
@ -1063,109 +978,27 @@ public final class StackMapGenerator {
|
||||
: 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) {
|
||||
int stackSize = this.stackSize;
|
||||
checkStack(stackSize);
|
||||
stack[stackSize] = type;
|
||||
this.stackSize = stackSize + 1;
|
||||
stack[stackSize++] = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
Frame pushStack(Type type1, Type type2) {
|
||||
int stackSize = this.stackSize;
|
||||
checkStack(stackSize + 1);
|
||||
stack[stackSize] = type1;
|
||||
stack[stackSize + 1] = type2;
|
||||
this.stackSize = stackSize + 2;
|
||||
stack[stackSize++] = type1;
|
||||
stack[stackSize++] = type2;
|
||||
return this;
|
||||
}
|
||||
|
||||
Type popStack() {
|
||||
int stackSize = this.stackSize - 1;
|
||||
if (stackSize < 0) throw stackUnderflow();
|
||||
this.stackSize = stackSize;
|
||||
return stack[stackSize];
|
||||
}
|
||||
|
||||
Frame decStack() {
|
||||
if (--stackSize < 0) throw stackUnderflow();
|
||||
return this;
|
||||
if (stackSize < 1) throw generatorError("Operand stack underflow");
|
||||
return stack[--stackSize];
|
||||
}
|
||||
|
||||
Frame decStack(int size) {
|
||||
stackSize -= size;
|
||||
if (stackSize < 0) throw stackUnderflow();
|
||||
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;
|
||||
if (stackSize < 0) throw generatorError("Operand stack underflow");
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1194,59 +1027,34 @@ public final class StackMapGenerator {
|
||||
Frame checkLocal(int index) {
|
||||
if (index >= frameMaxLocals) frameMaxLocals = index + 1;
|
||||
if (locals == null) {
|
||||
initLocals(index);
|
||||
locals = new Type[index + FRAME_DEFAULT_CAPACITY];
|
||||
Arrays.fill(locals, Type.TOP_TYPE);
|
||||
} 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (index >= frameMaxStack) frameMaxStack = index + 1;
|
||||
if (stack == null) {
|
||||
initStack(index);
|
||||
stack = new Type[index + FRAME_DEFAULT_CAPACITY];
|
||||
Arrays.fill(stack, Type.TOP_TYPE);
|
||||
} 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) {
|
||||
checkLocal(index);
|
||||
var locals = this.locals;
|
||||
localsChanged |= !type.equals(locals[index]);
|
||||
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) {
|
||||
int localsSize = 0;
|
||||
// Pre-emptively create a locals array that encompass all parameter slots
|
||||
@ -1347,7 +1155,8 @@ public final class StackMapGenerator {
|
||||
Type old = getLocalRawInternal(index);
|
||||
if (old == Type.DOUBLE_TYPE || old == Type.LONG_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, type);
|
||||
@ -1365,7 +1174,8 @@ public final class StackMapGenerator {
|
||||
if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) {
|
||||
setLocalRawInternal(index - 1, Type.TOP_TYPE);
|
||||
}
|
||||
setLocalRawInternal(index, type1, type2);
|
||||
setLocalRawInternal(index, type1);
|
||||
setLocalRawInternal(index + 1, type2);
|
||||
if (index >= localsSize - 1) {
|
||||
localsSize = index + 2;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @summary Testing Classfile stack maps generator.
|
||||
* @bug 8305990 8320222 8320618 8335475 8338623 8338661
|
||||
* @bug 8305990 8320222 8320618 8335475 8338623 8338661 8343436
|
||||
* @build testdata.*
|
||||
* @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_String = MethodTypeDesc.of(CD_int, CD_String);
|
||||
private static final MethodTypeDesc MTD_long_int = MethodTypeDesc.of(CD_long, CD_int);
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(ClassFile.StackMapsOption.class)
|
||||
|
Loading…
Reference in New Issue
Block a user