mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8341272: Factory to create wide iinc instruction with small arguments
Reviewed-by: liach, asotona
This commit is contained in:
parent
336894857b
commit
669977f7c4
@ -31,6 +31,8 @@ import java.lang.classfile.Instruction;
|
||||
import java.lang.classfile.Opcode;
|
||||
|
||||
import jdk.internal.classfile.impl.AbstractInstruction;
|
||||
import jdk.internal.classfile.impl.BytecodeHelpers;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
||||
/**
|
||||
* Models a local variable increment instruction in the {@code code} array of a
|
||||
@ -82,6 +84,37 @@ public sealed interface IncrementInstruction extends Instruction
|
||||
* @throws IllegalArgumentException if {@code slot} or {@code constant} is out of range
|
||||
*/
|
||||
static IncrementInstruction of(int slot, int constant) {
|
||||
return new AbstractInstruction.UnboundIncrementInstruction(slot, constant);
|
||||
var opcode = BytecodeHelpers.validateAndIsWideIinc(slot, constant) ? Opcode.IINC_W: Opcode.IINC;
|
||||
return new AbstractInstruction.UnboundIncrementInstruction(opcode, slot, constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return an increment instruction}
|
||||
* <p>
|
||||
* {@code slot} must be {@link java.lang.classfile##u1 u1} and
|
||||
* {@code constant} must be within {@code [-128, 127]} for
|
||||
* {@link Opcode#IINC iinc}, or {@code slot} must be
|
||||
* {@link java.lang.classfile##u2 u2} and {@code constant} must be
|
||||
* within {@code [-32768, 32767]} for {@link Opcode#IINC_W wide iinc}.
|
||||
*
|
||||
* @apiNote
|
||||
* The explicit {@code op} argument allows creating {@code wide} or
|
||||
* regular increment instructions when {@code slot} and
|
||||
* {@code constant} can be encoded with more optimized
|
||||
* increment instructions.
|
||||
*
|
||||
* @param op the opcode for the specific type of increment instruction,
|
||||
* which must be of kind {@link Opcode.Kind#INCREMENT}
|
||||
* @param slot the local variable slot to increment
|
||||
* @param constant the increment constant
|
||||
* @throws IllegalArgumentException if the opcode kind is not
|
||||
* {@link Opcode.Kind#INCREMENT} or {@code slot} or
|
||||
* {@code constant} is out of range
|
||||
* @since 27
|
||||
*/
|
||||
static IncrementInstruction of(Opcode op, int slot, int constant) {
|
||||
Util.checkKind(op, Opcode.Kind.INCREMENT);
|
||||
BytecodeHelpers.validateIncrement(op, slot, constant);
|
||||
return new AbstractInstruction.UnboundIncrementInstruction(op, slot, constant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -832,10 +832,8 @@ public abstract sealed class AbstractInstruction
|
||||
final int slot;
|
||||
final int constant;
|
||||
|
||||
public UnboundIncrementInstruction(int slot, int constant) {
|
||||
super(BytecodeHelpers.validateAndIsWideIinc(slot, constant)
|
||||
? Opcode.IINC_W
|
||||
: Opcode.IINC);
|
||||
public UnboundIncrementInstruction(Opcode op, int slot, int constant) {
|
||||
super(op);
|
||||
this.slot = slot;
|
||||
this.constant = constant;
|
||||
}
|
||||
|
||||
@ -450,6 +450,13 @@ public class BytecodeHelpers {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void validateIncrement(Opcode opcode, int slot, int constant) {
|
||||
if (validateAndIsWideIinc(slot, constant) && opcode != Opcode.IINC_W) {
|
||||
throw new IllegalArgumentException(
|
||||
"IINC: operands require wide encoding for %s".formatted(opcode));
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateRet(Opcode opcode, int slot) {
|
||||
if (opcode == Opcode.RET && (slot & ~0xFF) == 0 ||
|
||||
opcode == Opcode.RET_W && (slot & ~0xFFFF) == 0)
|
||||
|
||||
@ -195,6 +195,7 @@ class InstructionValidationTest {
|
||||
ensureFailFast(i, cob -> cob.iinc(i, 1));
|
||||
}
|
||||
check(fails, () -> IncrementInstruction.of(i, 1));
|
||||
check(fails, () -> IncrementInstruction.of(IINC_W, i, 1));
|
||||
check(fails, () -> DiscontinuedInstruction.RetInstruction.of(i));
|
||||
check(fails, () -> DiscontinuedInstruction.RetInstruction.of(RET_W, i));
|
||||
check(fails, () -> LocalVariable.of(i, "test", CD_Object, dummyLabel, dummyLabel));
|
||||
@ -208,6 +209,7 @@ class InstructionValidationTest {
|
||||
check(fails, () -> LoadInstruction.of(u1Op, i));
|
||||
for (var u1Op : List.of(ASTORE, ISTORE, LSTORE, FSTORE, DSTORE))
|
||||
check(fails, () -> StoreInstruction.of(u1Op, i));
|
||||
check(fails, () -> IncrementInstruction.of(IINC, i, 1));
|
||||
check(fails, () -> DiscontinuedInstruction.RetInstruction.of(RET, i));
|
||||
}
|
||||
|
||||
@ -250,6 +252,13 @@ class InstructionValidationTest {
|
||||
IncrementInstruction.of(0, 2);
|
||||
IncrementInstruction.of(0, Short.MAX_VALUE);
|
||||
IncrementInstruction.of(0, Short.MIN_VALUE);
|
||||
IncrementInstruction.of(IINC, 0, 2);
|
||||
IncrementInstruction.of(IINC, 0, Byte.MIN_VALUE);
|
||||
IncrementInstruction.of(IINC, 0, Byte.MAX_VALUE);
|
||||
IncrementInstruction.of(IINC_W, 0, 2);
|
||||
IncrementInstruction.of(IINC_W, 0, Short.MIN_VALUE);
|
||||
IncrementInstruction.of(IINC_W, 0, Short.MAX_VALUE);
|
||||
|
||||
for (int i : new int[] {Short.MIN_VALUE - 1, Short.MAX_VALUE + 1}) {
|
||||
assertThrows(IllegalArgumentException.class, () -> IncrementInstruction.of(0, i));
|
||||
TestUtil.runCodeHandler(cob -> {
|
||||
@ -257,6 +266,12 @@ class InstructionValidationTest {
|
||||
cob.return_();
|
||||
});
|
||||
}
|
||||
for (int i : new int[] {Byte.MIN_VALUE - 1, Byte.MAX_VALUE + 1}) {
|
||||
assertThrows(IllegalArgumentException.class, () -> IncrementInstruction.of(IINC, 0, i));
|
||||
}
|
||||
for (int i : new int[] {Short.MIN_VALUE - 1, Short.MAX_VALUE + 1}) {
|
||||
assertThrows(IllegalArgumentException.class, () -> IncrementInstruction.of(IINC_W, 0, i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user