8325485: IncrementInstructions.of(int, int) is not storing the args
Reviewed-by: liach, jlahoda
This commit is contained in:
parent
b9331cd25c
commit
8907eda779
src/java.base/share/classes/jdk/internal/classfile/impl
test/jdk/jdk/classfile
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -860,7 +860,7 @@ public abstract sealed class AbstractInstruction
|
||||
|
||||
@Override
|
||||
public int constant() {
|
||||
return 0;
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8325485
|
||||
* @summary Testing ClassFile on small Corpus.
|
||||
* @build helpers.* testdata.*
|
||||
* @run junit/othervm/timeout=480 -Djunit.jupiter.execution.parallel.enabled=true CorpusTest
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -485,7 +485,7 @@ public record ClassRecord(
|
||||
|
||||
int hash(int from, int length) {
|
||||
int result = 1;
|
||||
for (int i = from; i < length; i++) {
|
||||
for (int i = from; i < from + length; i++) {
|
||||
int elementHash = (codeToIndexMap[i] ^ (codeToIndexMap[i] >>> 32));
|
||||
result = 31 * result + elementHash;
|
||||
}
|
||||
@ -557,7 +557,7 @@ public record ClassRecord(
|
||||
yield local.slot();
|
||||
}
|
||||
else {
|
||||
yield code.hash(p[0] + 1, ins.sizeInBytes());
|
||||
yield code.hash(p[0] + 1, ins.sizeInBytes() - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -69,394 +69,15 @@ class RebuildingTransformation {
|
||||
for (var me : mm) {
|
||||
switch (me) {
|
||||
case AccessFlags af -> mb.withFlags(af.flagsMask());
|
||||
case CodeModel com -> mb.withCode(cb -> cb.transforming(CodeStackTracker.of(), cob -> {
|
||||
var labels = new HashMap<Label, Label>();
|
||||
for (var coe : com) {
|
||||
switch (coe) {
|
||||
case ArrayLoadInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case ByteType -> cob.baload();
|
||||
case ShortType -> cob.saload();
|
||||
case IntType -> cob.iaload();
|
||||
case FloatType -> cob.faload();
|
||||
case LongType -> cob.laload();
|
||||
case DoubleType -> cob.daload();
|
||||
case ReferenceType -> cob.aaload();
|
||||
case CharType -> cob.caload();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case ArrayStoreInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case ByteType -> cob.bastore();
|
||||
case ShortType -> cob.sastore();
|
||||
case IntType -> cob.iastore();
|
||||
case FloatType -> cob.fastore();
|
||||
case LongType -> cob.lastore();
|
||||
case DoubleType -> cob.dastore();
|
||||
case ReferenceType -> cob.aastore();
|
||||
case CharType -> cob.castore();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case BranchInstruction i -> {
|
||||
var target = labels.computeIfAbsent(i.target(), l -> cob.newLabel());
|
||||
switch (i.opcode()) {
|
||||
case GOTO -> cob.goto_(target);
|
||||
case GOTO_W -> cob.goto_w(target);
|
||||
case IF_ACMPEQ -> cob.if_acmpeq(target);
|
||||
case IF_ACMPNE -> cob.if_acmpne(target);
|
||||
case IF_ICMPEQ -> cob.if_icmpeq(target);
|
||||
case IF_ICMPGE -> cob.if_icmpge(target);
|
||||
case IF_ICMPGT -> cob.if_icmpgt(target);
|
||||
case IF_ICMPLE -> cob.if_icmple(target);
|
||||
case IF_ICMPLT -> cob.if_icmplt(target);
|
||||
case IF_ICMPNE -> cob.if_icmpne(target);
|
||||
case IFNONNULL -> cob.if_nonnull(target);
|
||||
case IFNULL -> cob.if_null(target);
|
||||
case IFEQ -> cob.ifeq(target);
|
||||
case IFGE -> cob.ifge(target);
|
||||
case IFGT -> cob.ifgt(target);
|
||||
case IFLE -> cob.ifle(target);
|
||||
case IFLT -> cob.iflt(target);
|
||||
case IFNE -> cob.ifne(target);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case ConstantInstruction i -> {
|
||||
if (i.constantValue() == null)
|
||||
if (pathSwitch.nextBoolean()) cob.aconst_null();
|
||||
else cob.constantInstruction(null);
|
||||
else switch (i.constantValue()) {
|
||||
case Integer iVal -> {
|
||||
if (iVal == 1 && pathSwitch.nextBoolean()) cob.iconst_1();
|
||||
else if (iVal == 2 && pathSwitch.nextBoolean()) cob.iconst_2();
|
||||
else if (iVal == 3 && pathSwitch.nextBoolean()) cob.iconst_3();
|
||||
else if (iVal == 4 && pathSwitch.nextBoolean()) cob.iconst_4();
|
||||
else if (iVal == 5 && pathSwitch.nextBoolean()) cob.iconst_5();
|
||||
else if (iVal == -1 && pathSwitch.nextBoolean()) cob.iconst_m1();
|
||||
else if (iVal >= -128 && iVal <= 127 && pathSwitch.nextBoolean()) cob.bipush(iVal);
|
||||
else if (iVal >= -32768 && iVal <= 32767 && pathSwitch.nextBoolean()) cob.sipush(iVal);
|
||||
else cob.constantInstruction(iVal);
|
||||
}
|
||||
case Long lVal -> {
|
||||
if (lVal == 0 && pathSwitch.nextBoolean()) cob.lconst_0();
|
||||
else if (lVal == 1 && pathSwitch.nextBoolean()) cob.lconst_1();
|
||||
else cob.constantInstruction(lVal);
|
||||
}
|
||||
case Float fVal -> {
|
||||
if (fVal == 0.0 && pathSwitch.nextBoolean()) cob.fconst_0();
|
||||
else if (fVal == 1.0 && pathSwitch.nextBoolean()) cob.fconst_1();
|
||||
else if (fVal == 2.0 && pathSwitch.nextBoolean()) cob.fconst_2();
|
||||
else cob.constantInstruction(fVal);
|
||||
}
|
||||
case Double dVal -> {
|
||||
if (dVal == 0.0d && pathSwitch.nextBoolean()) cob.dconst_0();
|
||||
else if (dVal == 1.0d && pathSwitch.nextBoolean()) cob.dconst_1();
|
||||
else cob.constantInstruction(dVal);
|
||||
}
|
||||
default -> cob.constantInstruction(i.constantValue());
|
||||
}
|
||||
}
|
||||
case ConvertInstruction i -> {
|
||||
switch (i.fromType()) {
|
||||
case DoubleType -> {
|
||||
switch (i.toType()) {
|
||||
case FloatType -> cob.d2f();
|
||||
case IntType -> cob.d2i();
|
||||
case LongType -> cob.d2l();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case FloatType -> {
|
||||
switch (i.toType()) {
|
||||
case DoubleType -> cob.f2d();
|
||||
case IntType -> cob.f2i();
|
||||
case LongType -> cob.f2l();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case IntType -> {
|
||||
switch (i.toType()) {
|
||||
case ByteType -> cob.i2b();
|
||||
case CharType -> cob.i2c();
|
||||
case DoubleType -> cob.i2d();
|
||||
case FloatType -> cob.i2f();
|
||||
case LongType -> cob.i2l();
|
||||
case ShortType -> cob.i2s();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case LongType -> {
|
||||
switch (i.toType()) {
|
||||
case DoubleType -> cob.l2d();
|
||||
case FloatType -> cob.l2f();
|
||||
case IntType -> cob.l2i();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case DiscontinuedInstruction.JsrInstruction i ->
|
||||
cob.with(DiscontinuedInstruction.JsrInstruction.of(i.opcode(), labels.computeIfAbsent(i.target(), l -> cob.newLabel())));
|
||||
case DiscontinuedInstruction.RetInstruction i ->
|
||||
cob.with(DiscontinuedInstruction.RetInstruction.of(i.opcode(), i.slot()));
|
||||
case FieldInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
switch (i.opcode()) {
|
||||
case GETFIELD -> cob.getfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case GETSTATIC -> cob.getstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case PUTFIELD -> cob.putfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case PUTSTATIC -> cob.putstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
} else {
|
||||
switch (i.opcode()) {
|
||||
case GETFIELD -> cob.getfield(i.field());
|
||||
case GETSTATIC -> cob.getstatic(i.field());
|
||||
case PUTFIELD -> cob.putfield(i.field());
|
||||
case PUTSTATIC -> cob.putstatic(i.field());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
case InvokeDynamicInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) cob.invokedynamic(i.invokedynamic().asSymbol());
|
||||
else cob.invokedynamic(i.invokedynamic());
|
||||
}
|
||||
case InvokeInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
if (i.isInterface()) {
|
||||
switch (i.opcode()) {
|
||||
case INVOKEINTERFACE -> cob.invokeinterface(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true);
|
||||
case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
} else {
|
||||
switch (i.opcode()) {
|
||||
case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case INVOKEVIRTUAL -> cob.invokevirtual(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (i.method()) {
|
||||
case InterfaceMethodRefEntry en -> {
|
||||
switch (i.opcode()) {
|
||||
case INVOKEINTERFACE -> cob.invokeinterface(en);
|
||||
case INVOKESPECIAL -> cob.invokespecial(en);
|
||||
case INVOKESTATIC -> cob.invokestatic(en);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case MethodRefEntry en -> {
|
||||
switch (i.opcode()) {
|
||||
case INVOKESPECIAL -> cob.invokespecial(en);
|
||||
case INVOKESTATIC -> cob.invokestatic(en);
|
||||
case INVOKEVIRTUAL -> cob.invokevirtual(en);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
case LoadInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case IntType -> cob.iload(i.slot());
|
||||
case FloatType -> cob.fload(i.slot());
|
||||
case LongType -> cob.lload(i.slot());
|
||||
case DoubleType -> cob.dload(i.slot());
|
||||
case ReferenceType -> cob.aload(i.slot());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case StoreInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case IntType -> cob.istore(i.slot());
|
||||
case FloatType -> cob.fstore(i.slot());
|
||||
case LongType -> cob.lstore(i.slot());
|
||||
case DoubleType -> cob.dstore(i.slot());
|
||||
case ReferenceType -> cob.astore(i.slot());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case IncrementInstruction i ->
|
||||
cob.iinc(i.slot(), i.constant());
|
||||
case LookupSwitchInstruction i ->
|
||||
cob.lookupswitch(labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()),
|
||||
i.cases().stream().map(sc ->
|
||||
SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList());
|
||||
case MonitorInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case MONITORENTER -> cob.monitorenter();
|
||||
case MONITOREXIT -> cob.monitorexit();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case NewMultiArrayInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
cob.multianewarray(i.arrayType().asSymbol(), i.dimensions());
|
||||
} else {
|
||||
cob.multianewarray(i.arrayType(), i.dimensions());
|
||||
}
|
||||
}
|
||||
case NewObjectInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
cob.new_(i.className().asSymbol());
|
||||
} else {
|
||||
cob.new_(i.className());
|
||||
}
|
||||
}
|
||||
case NewPrimitiveArrayInstruction i ->
|
||||
cob.newarray(i.typeKind());
|
||||
case NewReferenceArrayInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
cob.anewarray(i.componentType().asSymbol());
|
||||
} else {
|
||||
cob.anewarray(i.componentType());
|
||||
}
|
||||
}
|
||||
case NopInstruction i ->
|
||||
cob.nop();
|
||||
case OperatorInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case IADD -> cob.iadd();
|
||||
case LADD -> cob.ladd();
|
||||
case FADD -> cob.fadd();
|
||||
case DADD -> cob.dadd();
|
||||
case ISUB -> cob.isub();
|
||||
case LSUB -> cob.lsub();
|
||||
case FSUB -> cob.fsub();
|
||||
case DSUB -> cob.dsub();
|
||||
case IMUL -> cob.imul();
|
||||
case LMUL -> cob.lmul();
|
||||
case FMUL -> cob.fmul();
|
||||
case DMUL -> cob.dmul();
|
||||
case IDIV -> cob.idiv();
|
||||
case LDIV -> cob.ldiv();
|
||||
case FDIV -> cob.fdiv();
|
||||
case DDIV -> cob.ddiv();
|
||||
case IREM -> cob.irem();
|
||||
case LREM -> cob.lrem();
|
||||
case FREM -> cob.frem();
|
||||
case DREM -> cob.drem();
|
||||
case INEG -> cob.ineg();
|
||||
case LNEG -> cob.lneg();
|
||||
case FNEG -> cob.fneg();
|
||||
case DNEG -> cob.dneg();
|
||||
case ISHL -> cob.ishl();
|
||||
case LSHL -> cob.lshl();
|
||||
case ISHR -> cob.ishr();
|
||||
case LSHR -> cob.lshr();
|
||||
case IUSHR -> cob.iushr();
|
||||
case LUSHR -> cob.lushr();
|
||||
case IAND -> cob.iand();
|
||||
case LAND -> cob.land();
|
||||
case IOR -> cob.ior();
|
||||
case LOR -> cob.lor();
|
||||
case IXOR -> cob.ixor();
|
||||
case LXOR -> cob.lxor();
|
||||
case LCMP -> cob.lcmp();
|
||||
case FCMPL -> cob.fcmpl();
|
||||
case FCMPG -> cob.fcmpg();
|
||||
case DCMPL -> cob.dcmpl();
|
||||
case DCMPG -> cob.dcmpg();
|
||||
case ARRAYLENGTH -> cob.arraylength();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case ReturnInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case IntType -> cob.ireturn();
|
||||
case FloatType -> cob.freturn();
|
||||
case LongType -> cob.lreturn();
|
||||
case DoubleType -> cob.dreturn();
|
||||
case ReferenceType -> cob.areturn();
|
||||
case VoidType -> cob.return_();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case StackInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case POP -> cob.pop();
|
||||
case POP2 -> cob.pop2();
|
||||
case DUP -> cob.dup();
|
||||
case DUP_X1 -> cob.dup_x1();
|
||||
case DUP_X2 -> cob.dup_x2();
|
||||
case DUP2 -> cob.dup2();
|
||||
case DUP2_X1 -> cob.dup2_x1();
|
||||
case DUP2_X2 -> cob.dup2_x2();
|
||||
case SWAP -> cob.swap();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case TableSwitchInstruction i ->
|
||||
cob.tableswitch(i.lowValue(), i.highValue(),
|
||||
labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()),
|
||||
i.cases().stream().map(sc ->
|
||||
SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList());
|
||||
case ThrowInstruction i -> cob.athrow();
|
||||
case TypeCheckInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
switch (i.opcode()) {
|
||||
case CHECKCAST -> cob.checkcast(i.type().asSymbol());
|
||||
case INSTANCEOF -> cob.instanceof_(i.type().asSymbol());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
} else {
|
||||
switch (i.opcode()) {
|
||||
case CHECKCAST -> cob.checkcast(i.type());
|
||||
case INSTANCEOF -> cob.instanceof_(i.type());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
case CharacterRange pi ->
|
||||
cob.characterRange(labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()),
|
||||
pi.characterRangeStart(), pi.characterRangeEnd(), pi.flags());
|
||||
case ExceptionCatch pi ->
|
||||
pi.catchType().ifPresentOrElse(
|
||||
catchType -> cob.exceptionCatch(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()),
|
||||
catchType.asSymbol()),
|
||||
() -> cob.exceptionCatchAll(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.handler(), l -> cob.newLabel())));
|
||||
case LabelTarget pi ->
|
||||
cob.labelBinding(labels.computeIfAbsent(pi.label(), l -> cob.newLabel()));
|
||||
case LineNumber pi ->
|
||||
cob.lineNumber(pi.line());
|
||||
case LocalVariable pi ->
|
||||
cob.localVariable(pi.slot(), pi.name().stringValue(), pi.typeSymbol(),
|
||||
labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()));
|
||||
case LocalVariableType pi ->
|
||||
cob.localVariableType(pi.slot(), pi.name().stringValue(),
|
||||
Signature.parseFrom(pi.signatureSymbol().signatureString()),
|
||||
labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute a ->
|
||||
cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels)));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute a ->
|
||||
cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels)));
|
||||
case StackMapTableAttribute a ->
|
||||
throw new AssertionError("Unexpected StackMapTableAttribute here");
|
||||
case CustomAttribute a ->
|
||||
throw new AssertionError("Unexpected custom attribute: " + a.attributeName());
|
||||
}
|
||||
}
|
||||
com.findAttribute(Attributes.STACK_MAP_TABLE).ifPresent(smta ->
|
||||
cob.with(StackMapTableAttribute.of(smta.entries().stream().map(fr ->
|
||||
StackMapFrameInfo.of(labels.computeIfAbsent(fr.target(), l -> cob.newLabel()),
|
||||
transformFrameTypeInfos(fr.locals(), cob, labels),
|
||||
transformFrameTypeInfos(fr.stack(), cob, labels))).toList())));
|
||||
}));
|
||||
case CodeModel com -> mb.withCode(cob1 ->
|
||||
cob1.transforming(CodeStackTracker.of(), cob2 ->
|
||||
// second pass transforms unbound to unbound instructions
|
||||
cob2.transforming(new CodeRebuildingTransform(), cob3 ->
|
||||
// first pass transforms bound to unbound instructions
|
||||
cob3.transforming(new CodeRebuildingTransform(), cob4 -> {
|
||||
com.forEachElement(cob4::with);
|
||||
com.findAttribute(Attributes.STACK_MAP_TABLE).ifPresent(cob4::with);
|
||||
}))));
|
||||
case AnnotationDefaultAttribute a -> mb.with(AnnotationDefaultAttribute.of(transformAnnotationValue(a.defaultValue())));
|
||||
case DeprecatedAttribute a -> mb.with(DeprecatedAttribute.of());
|
||||
case ExceptionsAttribute a -> mb.with(ExceptionsAttribute.ofSymbols(a.exceptions().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new)));
|
||||
@ -589,4 +210,394 @@ class RebuildingTransformation {
|
||||
};
|
||||
}).toList();
|
||||
}
|
||||
|
||||
static class CodeRebuildingTransform implements CodeTransform {
|
||||
|
||||
final HashMap<Label, Label> labels = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cob, CodeElement coe) {
|
||||
switch (coe) {
|
||||
case ArrayLoadInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case ByteType -> cob.baload();
|
||||
case ShortType -> cob.saload();
|
||||
case IntType -> cob.iaload();
|
||||
case FloatType -> cob.faload();
|
||||
case LongType -> cob.laload();
|
||||
case DoubleType -> cob.daload();
|
||||
case ReferenceType -> cob.aaload();
|
||||
case CharType -> cob.caload();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case ArrayStoreInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case ByteType -> cob.bastore();
|
||||
case ShortType -> cob.sastore();
|
||||
case IntType -> cob.iastore();
|
||||
case FloatType -> cob.fastore();
|
||||
case LongType -> cob.lastore();
|
||||
case DoubleType -> cob.dastore();
|
||||
case ReferenceType -> cob.aastore();
|
||||
case CharType -> cob.castore();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case BranchInstruction i -> {
|
||||
var target = labels.computeIfAbsent(i.target(), l -> cob.newLabel());
|
||||
switch (i.opcode()) {
|
||||
case GOTO -> cob.goto_(target);
|
||||
case GOTO_W -> cob.goto_w(target);
|
||||
case IF_ACMPEQ -> cob.if_acmpeq(target);
|
||||
case IF_ACMPNE -> cob.if_acmpne(target);
|
||||
case IF_ICMPEQ -> cob.if_icmpeq(target);
|
||||
case IF_ICMPGE -> cob.if_icmpge(target);
|
||||
case IF_ICMPGT -> cob.if_icmpgt(target);
|
||||
case IF_ICMPLE -> cob.if_icmple(target);
|
||||
case IF_ICMPLT -> cob.if_icmplt(target);
|
||||
case IF_ICMPNE -> cob.if_icmpne(target);
|
||||
case IFNONNULL -> cob.if_nonnull(target);
|
||||
case IFNULL -> cob.if_null(target);
|
||||
case IFEQ -> cob.ifeq(target);
|
||||
case IFGE -> cob.ifge(target);
|
||||
case IFGT -> cob.ifgt(target);
|
||||
case IFLE -> cob.ifle(target);
|
||||
case IFLT -> cob.iflt(target);
|
||||
case IFNE -> cob.ifne(target);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case ConstantInstruction i -> {
|
||||
if (i.constantValue() == null)
|
||||
if (pathSwitch.nextBoolean()) cob.aconst_null();
|
||||
else cob.constantInstruction(null);
|
||||
else switch (i.constantValue()) {
|
||||
case Integer iVal -> {
|
||||
if (iVal == 1 && pathSwitch.nextBoolean()) cob.iconst_1();
|
||||
else if (iVal == 2 && pathSwitch.nextBoolean()) cob.iconst_2();
|
||||
else if (iVal == 3 && pathSwitch.nextBoolean()) cob.iconst_3();
|
||||
else if (iVal == 4 && pathSwitch.nextBoolean()) cob.iconst_4();
|
||||
else if (iVal == 5 && pathSwitch.nextBoolean()) cob.iconst_5();
|
||||
else if (iVal == -1 && pathSwitch.nextBoolean()) cob.iconst_m1();
|
||||
else if (iVal >= -128 && iVal <= 127 && pathSwitch.nextBoolean()) cob.bipush(iVal);
|
||||
else if (iVal >= -32768 && iVal <= 32767 && pathSwitch.nextBoolean()) cob.sipush(iVal);
|
||||
else cob.constantInstruction(iVal);
|
||||
}
|
||||
case Long lVal -> {
|
||||
if (lVal == 0 && pathSwitch.nextBoolean()) cob.lconst_0();
|
||||
else if (lVal == 1 && pathSwitch.nextBoolean()) cob.lconst_1();
|
||||
else cob.constantInstruction(lVal);
|
||||
}
|
||||
case Float fVal -> {
|
||||
if (fVal == 0.0 && pathSwitch.nextBoolean()) cob.fconst_0();
|
||||
else if (fVal == 1.0 && pathSwitch.nextBoolean()) cob.fconst_1();
|
||||
else if (fVal == 2.0 && pathSwitch.nextBoolean()) cob.fconst_2();
|
||||
else cob.constantInstruction(fVal);
|
||||
}
|
||||
case Double dVal -> {
|
||||
if (dVal == 0.0d && pathSwitch.nextBoolean()) cob.dconst_0();
|
||||
else if (dVal == 1.0d && pathSwitch.nextBoolean()) cob.dconst_1();
|
||||
else cob.constantInstruction(dVal);
|
||||
}
|
||||
default -> cob.constantInstruction(i.constantValue());
|
||||
}
|
||||
}
|
||||
case ConvertInstruction i -> {
|
||||
switch (i.fromType()) {
|
||||
case DoubleType -> {
|
||||
switch (i.toType()) {
|
||||
case FloatType -> cob.d2f();
|
||||
case IntType -> cob.d2i();
|
||||
case LongType -> cob.d2l();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case FloatType -> {
|
||||
switch (i.toType()) {
|
||||
case DoubleType -> cob.f2d();
|
||||
case IntType -> cob.f2i();
|
||||
case LongType -> cob.f2l();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case IntType -> {
|
||||
switch (i.toType()) {
|
||||
case ByteType -> cob.i2b();
|
||||
case CharType -> cob.i2c();
|
||||
case DoubleType -> cob.i2d();
|
||||
case FloatType -> cob.i2f();
|
||||
case LongType -> cob.i2l();
|
||||
case ShortType -> cob.i2s();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case LongType -> {
|
||||
switch (i.toType()) {
|
||||
case DoubleType -> cob.l2d();
|
||||
case FloatType -> cob.l2f();
|
||||
case IntType -> cob.l2i();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case DiscontinuedInstruction.JsrInstruction i ->
|
||||
cob.with(DiscontinuedInstruction.JsrInstruction.of(i.opcode(), labels.computeIfAbsent(i.target(), l -> cob.newLabel())));
|
||||
case DiscontinuedInstruction.RetInstruction i ->
|
||||
cob.with(DiscontinuedInstruction.RetInstruction.of(i.opcode(), i.slot()));
|
||||
case FieldInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
switch (i.opcode()) {
|
||||
case GETFIELD -> cob.getfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case GETSTATIC -> cob.getstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case PUTFIELD -> cob.putfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case PUTSTATIC -> cob.putstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
} else {
|
||||
switch (i.opcode()) {
|
||||
case GETFIELD -> cob.getfield(i.field());
|
||||
case GETSTATIC -> cob.getstatic(i.field());
|
||||
case PUTFIELD -> cob.putfield(i.field());
|
||||
case PUTSTATIC -> cob.putstatic(i.field());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
case InvokeDynamicInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) cob.invokedynamic(i.invokedynamic().asSymbol());
|
||||
else cob.invokedynamic(i.invokedynamic());
|
||||
}
|
||||
case InvokeInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
if (i.isInterface()) {
|
||||
switch (i.opcode()) {
|
||||
case INVOKEINTERFACE -> cob.invokeinterface(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true);
|
||||
case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
} else {
|
||||
switch (i.opcode()) {
|
||||
case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
case INVOKEVIRTUAL -> cob.invokevirtual(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (i.method()) {
|
||||
case InterfaceMethodRefEntry en -> {
|
||||
switch (i.opcode()) {
|
||||
case INVOKEINTERFACE -> cob.invokeinterface(en);
|
||||
case INVOKESPECIAL -> cob.invokespecial(en);
|
||||
case INVOKESTATIC -> cob.invokestatic(en);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case MethodRefEntry en -> {
|
||||
switch (i.opcode()) {
|
||||
case INVOKESPECIAL -> cob.invokespecial(en);
|
||||
case INVOKESTATIC -> cob.invokestatic(en);
|
||||
case INVOKEVIRTUAL -> cob.invokevirtual(en);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
case LoadInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case IntType -> cob.iload(i.slot());
|
||||
case FloatType -> cob.fload(i.slot());
|
||||
case LongType -> cob.lload(i.slot());
|
||||
case DoubleType -> cob.dload(i.slot());
|
||||
case ReferenceType -> cob.aload(i.slot());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case StoreInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case IntType -> cob.istore(i.slot());
|
||||
case FloatType -> cob.fstore(i.slot());
|
||||
case LongType -> cob.lstore(i.slot());
|
||||
case DoubleType -> cob.dstore(i.slot());
|
||||
case ReferenceType -> cob.astore(i.slot());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case IncrementInstruction i ->
|
||||
cob.iinc(i.slot(), i.constant());
|
||||
case LookupSwitchInstruction i ->
|
||||
cob.lookupswitch(labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()),
|
||||
i.cases().stream().map(sc ->
|
||||
SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList());
|
||||
case MonitorInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case MONITORENTER -> cob.monitorenter();
|
||||
case MONITOREXIT -> cob.monitorexit();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case NewMultiArrayInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
cob.multianewarray(i.arrayType().asSymbol(), i.dimensions());
|
||||
} else {
|
||||
cob.multianewarray(i.arrayType(), i.dimensions());
|
||||
}
|
||||
}
|
||||
case NewObjectInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
cob.new_(i.className().asSymbol());
|
||||
} else {
|
||||
cob.new_(i.className());
|
||||
}
|
||||
}
|
||||
case NewPrimitiveArrayInstruction i ->
|
||||
cob.newarray(i.typeKind());
|
||||
case NewReferenceArrayInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
cob.anewarray(i.componentType().asSymbol());
|
||||
} else {
|
||||
cob.anewarray(i.componentType());
|
||||
}
|
||||
}
|
||||
case NopInstruction i ->
|
||||
cob.nop();
|
||||
case OperatorInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case IADD -> cob.iadd();
|
||||
case LADD -> cob.ladd();
|
||||
case FADD -> cob.fadd();
|
||||
case DADD -> cob.dadd();
|
||||
case ISUB -> cob.isub();
|
||||
case LSUB -> cob.lsub();
|
||||
case FSUB -> cob.fsub();
|
||||
case DSUB -> cob.dsub();
|
||||
case IMUL -> cob.imul();
|
||||
case LMUL -> cob.lmul();
|
||||
case FMUL -> cob.fmul();
|
||||
case DMUL -> cob.dmul();
|
||||
case IDIV -> cob.idiv();
|
||||
case LDIV -> cob.ldiv();
|
||||
case FDIV -> cob.fdiv();
|
||||
case DDIV -> cob.ddiv();
|
||||
case IREM -> cob.irem();
|
||||
case LREM -> cob.lrem();
|
||||
case FREM -> cob.frem();
|
||||
case DREM -> cob.drem();
|
||||
case INEG -> cob.ineg();
|
||||
case LNEG -> cob.lneg();
|
||||
case FNEG -> cob.fneg();
|
||||
case DNEG -> cob.dneg();
|
||||
case ISHL -> cob.ishl();
|
||||
case LSHL -> cob.lshl();
|
||||
case ISHR -> cob.ishr();
|
||||
case LSHR -> cob.lshr();
|
||||
case IUSHR -> cob.iushr();
|
||||
case LUSHR -> cob.lushr();
|
||||
case IAND -> cob.iand();
|
||||
case LAND -> cob.land();
|
||||
case IOR -> cob.ior();
|
||||
case LOR -> cob.lor();
|
||||
case IXOR -> cob.ixor();
|
||||
case LXOR -> cob.lxor();
|
||||
case LCMP -> cob.lcmp();
|
||||
case FCMPL -> cob.fcmpl();
|
||||
case FCMPG -> cob.fcmpg();
|
||||
case DCMPL -> cob.dcmpl();
|
||||
case DCMPG -> cob.dcmpg();
|
||||
case ARRAYLENGTH -> cob.arraylength();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case ReturnInstruction i -> {
|
||||
switch (i.typeKind()) {
|
||||
case IntType -> cob.ireturn();
|
||||
case FloatType -> cob.freturn();
|
||||
case LongType -> cob.lreturn();
|
||||
case DoubleType -> cob.dreturn();
|
||||
case ReferenceType -> cob.areturn();
|
||||
case VoidType -> cob.return_();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case StackInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case POP -> cob.pop();
|
||||
case POP2 -> cob.pop2();
|
||||
case DUP -> cob.dup();
|
||||
case DUP_X1 -> cob.dup_x1();
|
||||
case DUP_X2 -> cob.dup_x2();
|
||||
case DUP2 -> cob.dup2();
|
||||
case DUP2_X1 -> cob.dup2_x1();
|
||||
case DUP2_X2 -> cob.dup2_x2();
|
||||
case SWAP -> cob.swap();
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
case TableSwitchInstruction i ->
|
||||
cob.tableswitch(i.lowValue(), i.highValue(),
|
||||
labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()),
|
||||
i.cases().stream().map(sc ->
|
||||
SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList());
|
||||
case ThrowInstruction i -> cob.athrow();
|
||||
case TypeCheckInstruction i -> {
|
||||
if (pathSwitch.nextBoolean()) {
|
||||
switch (i.opcode()) {
|
||||
case CHECKCAST -> cob.checkcast(i.type().asSymbol());
|
||||
case INSTANCEOF -> cob.instanceof_(i.type().asSymbol());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
} else {
|
||||
switch (i.opcode()) {
|
||||
case CHECKCAST -> cob.checkcast(i.type());
|
||||
case INSTANCEOF -> cob.instanceof_(i.type());
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
case CharacterRange pi ->
|
||||
cob.characterRange(labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()),
|
||||
pi.characterRangeStart(), pi.characterRangeEnd(), pi.flags());
|
||||
case ExceptionCatch pi ->
|
||||
pi.catchType().ifPresentOrElse(
|
||||
catchType -> cob.exceptionCatch(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()),
|
||||
catchType.asSymbol()),
|
||||
() -> cob.exceptionCatchAll(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.handler(), l -> cob.newLabel())));
|
||||
case LabelTarget pi ->
|
||||
cob.labelBinding(labels.computeIfAbsent(pi.label(), l -> cob.newLabel()));
|
||||
case LineNumber pi ->
|
||||
cob.lineNumber(pi.line());
|
||||
case LocalVariable pi ->
|
||||
cob.localVariable(pi.slot(), pi.name().stringValue(), pi.typeSymbol(),
|
||||
labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()));
|
||||
case LocalVariableType pi ->
|
||||
cob.localVariableType(pi.slot(), pi.name().stringValue(),
|
||||
Signature.parseFrom(pi.signatureSymbol().signatureString()),
|
||||
labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
|
||||
labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute a ->
|
||||
cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels)));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute a ->
|
||||
cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels)));
|
||||
case StackMapTableAttribute a ->
|
||||
cob.with(StackMapTableAttribute.of(a.entries().stream().map(fr ->
|
||||
StackMapFrameInfo.of(labels.computeIfAbsent(fr.target(), l -> cob.newLabel()),
|
||||
transformFrameTypeInfos(fr.locals(), cob, labels),
|
||||
transformFrameTypeInfos(fr.stack(), cob, labels))).toList()));
|
||||
case CustomAttribute a ->
|
||||
throw new AssertionError("Unexpected custom attribute: " + a.attributeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user