Skip to content

Commit

Permalink
8339214: Remove misleading CodeBuilder.loadConstant(Opcode, ConstantD…
Browse files Browse the repository at this point in the history
…esc)
  • Loading branch information
liach committed Aug 29, 2024
1 parent 777ed2b commit 160e32a
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 197 deletions.
29 changes: 6 additions & 23 deletions src/java.base/share/classes/java/lang/classfile/CodeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -612,23 +612,6 @@ default CodeBuilder conversion(TypeKind fromType, TypeKind toType) {
};
}

/**
* Generate an instruction pushing a constant onto the operand stack
* @see Opcode.Kind#CONSTANT
* @param opcode the constant instruction opcode
* @param value the constant value
* @return this builder
* @since 23
*/
default CodeBuilder loadConstant(Opcode opcode, ConstantDesc value) {
BytecodeHelpers.validateValue(opcode, value);
return with(switch (opcode) {
case SIPUSH, BIPUSH -> ConstantInstruction.ofArgument(opcode, ((Number)value).intValue());
case LDC, LDC_W, LDC2_W -> ConstantInstruction.ofLoad(opcode, BytecodeHelpers.constantEntry(constantPool(), value));
default -> ConstantInstruction.ofIntrinsic(opcode);
});
}

/**
* Generate an instruction pushing a constant onto the operand stack
* @param value the constant value
Expand Down Expand Up @@ -939,12 +922,12 @@ default CodeBuilder bastore() {
}

/**
* Generate an instruction pushing a byte onto the operand stack
* @param b the byte
* Generate an instruction pushing an int in the range of byte onto the operand stack.
* @param b the int in the range of byte
* @return this builder
*/
default CodeBuilder bipush(int b) {
return loadConstant(Opcode.BIPUSH, b);
return with(ConstantInstruction.ofArgument(Opcode.BIPUSH, b));
}

/**
Expand Down Expand Up @@ -2404,12 +2387,12 @@ default CodeBuilder sastore() {
}

/**
* Generate an instruction pushing a short onto the operand stack
* @param s the short
* Generate an instruction pushing an int in the range of short onto the operand stack.
* @param s the int in the range of short
* @return this builder
*/
default CodeBuilder sipush(int s) {
return loadConstant(Opcode.SIPUSH, s);
return with(ConstantInstruction.ofArgument(Opcode.SIPUSH, s));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -33,6 +33,7 @@
import java.lang.classfile.TypeKind;
import java.lang.classfile.constantpool.LoadableConstantEntry;
import jdk.internal.classfile.impl.AbstractInstruction;
import jdk.internal.classfile.impl.BytecodeHelpers;
import jdk.internal.classfile.impl.Util;
import jdk.internal.javac.PreviewFeature;

Expand Down Expand Up @@ -152,8 +153,13 @@ static IntrinsicConstantInstruction ofIntrinsic(Opcode op) {
*/
static ArgumentConstantInstruction ofArgument(Opcode op, int value) {
Util.checkKind(op, Opcode.Kind.CONSTANT);
if (op != Opcode.BIPUSH && op != Opcode.SIPUSH)
if (op == Opcode.BIPUSH) {
BytecodeHelpers.validateBipush(value);
} else if (op == Opcode.SIPUSH) {
BytecodeHelpers.validateSipush(value);
} else {
throw new IllegalArgumentException(String.format("Wrong opcode specified; found %s, expected BIPUSH or SIPUSH", op));
}
return new AbstractInstruction.UnboundArgumentConstantInstruction(op, value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,40 +230,20 @@ public static Opcode convertOpcode(TypeKind from, TypeKind to) {
};
}

static void validateSipush(long value) {
if (value < Short.MIN_VALUE || Short.MAX_VALUE < value)
public static void validateSipush(int value) {
if (value != (short) value)
throw new IllegalArgumentException(
"SIPUSH: value must be within: Short.MIN_VALUE <= value <= Short.MAX_VALUE, found: "
.concat(Long.toString(value)));
}

static void validateBipush(long value) {
if (value < Byte.MIN_VALUE || Byte.MAX_VALUE < value)
public static void validateBipush(int value) {
if (value != (byte) value)
throw new IllegalArgumentException(
"BIPUSH: value must be within: Byte.MIN_VALUE <= value <= Byte.MAX_VALUE, found: "
.concat(Long.toString(value)));
}

static void validateSipush(ConstantDesc d) {
if (d instanceof Integer iVal) {
validateSipush(iVal.longValue());
} else if (d instanceof Long lVal) {
validateSipush(lVal.longValue());
} else {
throw new IllegalArgumentException("SIPUSH: not an integral number: ".concat(d.toString()));
}
}

static void validateBipush(ConstantDesc d) {
if (d instanceof Integer iVal) {
validateBipush(iVal.longValue());
} else if (d instanceof Long lVal) {
validateBipush(lVal.longValue());
} else {
throw new IllegalArgumentException("BIPUSH: not an integral number: ".concat(d.toString()));
}
}

public static MethodHandleEntry handleDescToHandleInfo(ConstantPoolBuilder constantPool, DirectMethodHandleDesc bootstrapMethod) {
ClassEntry bsOwner = constantPool.classEntry(bootstrapMethod.owner());
NameAndTypeEntry bsNameAndType = constantPool.nameAndTypeEntry(constantPool.utf8Entry(bootstrapMethod.methodName()),
Expand Down Expand Up @@ -294,32 +274,6 @@ static ConstantDynamicEntry handleConstantDescToHandleInfo(ConstantPoolBuilder c
desc.constantType()));
}

public static void validateValue(Opcode opcode, ConstantDesc v) {
switch (opcode) {
case ACONST_NULL -> {
if (v != null && v != ConstantDescs.NULL)
throw new IllegalArgumentException("value must be null or ConstantDescs.NULL with opcode ACONST_NULL");
}
case SIPUSH ->
validateSipush(v);
case BIPUSH ->
validateBipush(v);
case LDC, LDC_W, LDC2_W -> {
if (v == null)
throw new IllegalArgumentException("`null` must use ACONST_NULL");
}
default -> {
var exp = opcode.constantValue();
if (exp == null)
throw new IllegalArgumentException("Can not use Opcode: " + opcode + " with constant()");
if (v == null || !(v.equals(exp) || (exp instanceof Long l && v.equals(l.intValue())))) {
var t = (exp instanceof Long) ? "L" : (exp instanceof Float) ? "f" : (exp instanceof Double) ? "d" : "";
throw new IllegalArgumentException("value must be " + exp + t + " with opcode " + opcode.name());
}
}
}
}

public static Opcode ldcOpcode(LoadableConstantEntry entry) {
return entry.typeKind().slotSize() == 2 ? Opcode.LDC2_W
: entry.index() > 0xff ? Opcode.LDC_W
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ public CodeTransform asCodeTransform() {
cob.localVariableType(c.slot(), c.name().stringValue(),
mapSignature(c.signatureSymbol()), c.startScope(), c.endScope());
case LoadConstantInstruction ldc ->
cob.loadConstant(ldc.opcode(),
mapConstantValue(ldc.constantValue()));
cob.ldc(mapConstantValue(ldc.constantValue()));
case RuntimeVisibleTypeAnnotationsAttribute aa ->
cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(
mapTypeAnnotations(aa.annotations())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -828,21 +828,6 @@ public CodeBuilder branch(Opcode op, Label target) {
return this;
}

@Override
public CodeBuilder loadConstant(Opcode opcode, ConstantDesc value) {
BytecodeHelpers.validateValue(opcode, value);
// avoid non-local enum switch for bootstrap
if (opcode == BIPUSH || opcode == SIPUSH) {
writeArgumentConstant(opcode, ((Number) value).intValue());
} else if (opcode == LDC || opcode == LDC_W || opcode == LDC2_W) {
writeLoadConstant(opcode, BytecodeHelpers.constantEntry(constantPool(), value));
} else {
// intrinsics
writeBytecode(opcode);
}
return this;
}

@Override
public CodeBuilder nop() {
writeBytecode(NOP);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) {
// write begin event
getEventConfiguration(blockCodeBuilder);
// stack: [EW], [EW], [EventConfiguration]
blockCodeBuilder.loadConstant(Opcode.LDC2_W, eventTypeId);
blockCodeBuilder.loadConstant(eventTypeId);
// stack: [EW], [EW], [EventConfiguration] [long]
invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.method());
// stack: [EW], [integer]
Expand Down Expand Up @@ -676,7 +676,7 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex
// stack: [EW] [EW]
getEventConfiguration(blockCodeBuilder);
// stack: [EW] [EW] [EC]
blockCodeBuilder.loadConstant(Opcode.LDC2_W, eventTypeId);
blockCodeBuilder.loadConstant(eventTypeId);
invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.method());
// stack: [EW] [int]
blockCodeBuilder.ifeq(excluded);
Expand Down
2 changes: 1 addition & 1 deletion test/jdk/jdk/classfile/AdaptCodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void testSevenOfThirteenIterator() throws Exception {
if ((val instanceof Integer) && ((Integer) val) == 13) {
val = 7;
}
codeB.loadConstant(i.opcode(), val);
codeB.loadConstant(val);
}
default -> codeB.with(codeE);
}
Expand Down
6 changes: 3 additions & 3 deletions test/jdk/jdk/classfile/LDCTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ void testLDCisConvertedToLDCW() throws Exception {
for (int i = 0; i <= 256/2 + 2; i++) { // two entries per String
StringEntry s = cpb.stringEntry("string" + i);
}
c0.loadConstant(LDC, "string0")
.loadConstant(LDC, "string131")
.loadConstant(LDC, "string50")
c0.ldc("string0")
.ldc("string131")
.ldc("string50")
.loadConstant(-0.0f)
.loadConstant(-0.0d)
//non-LDC test cases
Expand Down
116 changes: 19 additions & 97 deletions test/jdk/jdk/classfile/OpcodesValidationTest.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -23,107 +23,29 @@

/*
* @test
* @summary Testing ClassFile constant instruction opcodes.
* @summary Testing ClassFile constant instruction argument validation.
* @run junit OpcodesValidationTest
*/
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDesc;
import static java.lang.constant.ConstantDescs.CD_void;
import java.lang.constant.MethodTypeDesc;
import java.lang.classfile.instruction.ConstantInstruction;
import org.junit.jupiter.api.Test;

import java.lang.reflect.AccessFlag;
import java.lang.classfile.ClassFile;
import java.lang.classfile.Opcode;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import static org.junit.jupiter.api.Assertions.*;
import static java.lang.classfile.Opcode.*;
import java.util.stream.Stream;

public class OpcodesValidationTest {

record Case(Opcode opcode, Object constant) {}

static Stream<Case> positiveCases() {
return Stream.of(
new Case(ACONST_NULL, null),
new Case(SIPUSH, (int)Short.MIN_VALUE),
new Case(SIPUSH, (int)Short.MAX_VALUE),
new Case(BIPUSH, (int)Byte.MIN_VALUE),
new Case(BIPUSH, (int)Byte.MAX_VALUE),
new Case(ICONST_M1, -1),
new Case(ICONST_0, 0),
new Case(ICONST_1, 1),
new Case(ICONST_2, 2),
new Case(ICONST_3, 3),
new Case(ICONST_4, 4),
new Case(ICONST_5, 5),
new Case(LCONST_0, 0l),
new Case(LCONST_0, 0),
new Case(LCONST_1, 1l),
new Case(LCONST_1, 1),
new Case(FCONST_0, 0.0f),
new Case(FCONST_1, 1.0f),
new Case(FCONST_2, 2.0f),
new Case(DCONST_0, 0.0d),
new Case(DCONST_1, 1.0d)
);
}

static Stream<Case> negativeCases() {
return Stream.of(
new Case(ACONST_NULL, 0),
new Case(SIPUSH, (int)Short.MIN_VALUE - 1),
new Case(SIPUSH, (int)Short.MAX_VALUE + 1),
new Case(BIPUSH, (int)Byte.MIN_VALUE - 1),
new Case(BIPUSH, (int)Byte.MAX_VALUE + 1),
new Case(ICONST_M1, -1l),
new Case(ICONST_0, 0l),
new Case(ICONST_1, 1l),
new Case(ICONST_2, 2l),
new Case(ICONST_3, 3l),
new Case(ICONST_4, 4l),
new Case(ICONST_5, 5l),
new Case(LCONST_0, null),
new Case(LCONST_0, 1l),
new Case(LCONST_1, 1.0d),
new Case(LCONST_1, 0),
new Case(FCONST_0, 0.0d),
new Case(FCONST_1, 1.01f),
new Case(FCONST_2, 2),
new Case(DCONST_0, 0.0f),
new Case(DCONST_1, 1.0f),
new Case(DCONST_1, 1)
);
}

@TestFactory
Stream<DynamicTest> testPositiveCases() {
return positiveCases().map(c -> dynamicTest(c.toString(), () -> testPositiveCase(c.opcode, c.constant)));
}

private void testPositiveCase(Opcode opcode, Object constant) {
ClassFile.of().build(ClassDesc.of("MyClass"),
cb -> cb.withFlags(AccessFlag.PUBLIC)
.withMethod("<init>", MethodTypeDesc.of(CD_void), 0,
mb -> mb.withCode(
codeb -> codeb.loadConstant(opcode, (ConstantDesc) constant))));
}


@TestFactory
Stream<DynamicTest> testNegativeCases() {
return negativeCases().map(c -> dynamicTest(
c.toString(),
() -> assertThrows(IllegalArgumentException.class, () -> testNegativeCase(c.opcode, c.constant))
));
}

private void testNegativeCase(Opcode opcode, Object constant) {
ClassFile.of().build(ClassDesc.of("MyClass"),
cb -> cb.withFlags(AccessFlag.PUBLIC)
.withMethod("<init>", MethodTypeDesc.of(CD_void), 0,
mb -> mb .withCode(
codeb -> codeb.loadConstant(opcode, (ConstantDesc)constant))));
class OpcodesValidationTest {

@Test
void testArgumentConstant() {
assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, 0));
assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, Short.MIN_VALUE));
assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, Short.MAX_VALUE));
assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, 0));
assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, Byte.MIN_VALUE));
assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, Byte.MAX_VALUE));

assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(SIPUSH, (int)Short.MIN_VALUE - 1));
assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(SIPUSH, (int)Short.MAX_VALUE + 1));
assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(BIPUSH, (int)Byte.MIN_VALUE - 1));
assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(BIPUSH, (int)Byte.MAX_VALUE + 1));
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -77,7 +77,7 @@ public static void toBuilder(CodeElement model, CodeBuilder cb) {
case OperatorInstruction im ->
cb.with(OperatorInstruction.of(im.opcode()));
case ConstantInstruction im ->
cb.loadConstant(im.opcode(), im.constantValue());
cb.loadConstant(im.constantValue());
case MonitorInstruction im ->
cb.with(MonitorInstruction.of(im.opcode()));
case NopInstruction im ->
Expand Down

0 comments on commit 160e32a

Please sign in to comment.