From cd5d0ff5b29065222ffafbc4fb04b90f6f8909e2 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 9 May 2023 09:14:18 +0000 Subject: [PATCH] 8304031: Classfile API cannot encode Primitive Class as Condy Reviewed-by: asotona --- .../constantpool/ConstantPoolBuilder.java | 5 +- .../classfile/impl/BytecodeHelpers.java | 2 +- .../classfile/PrimitiveClassConstantTest.java | 81 +++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 test/jdk/jdk/classfile/PrimitiveClassConstantTest.java diff --git a/src/java.base/share/classes/jdk/internal/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/constantpool/ConstantPoolBuilder.java index e95ad65d0b0..0442b361291 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/constantpool/ConstantPoolBuilder.java @@ -157,6 +157,9 @@ public sealed interface ConstantPoolBuilder * @param classDesc the symbolic descriptor for the class */ default ClassEntry classEntry(ClassDesc classDesc) { + if (classDesc.isPrimitive()) { + throw new IllegalArgumentException("Cannot be encoded as ClassEntry: " + classDesc.displayName()); + } return classEntry(utf8Entry(classDesc.isArray() ? classDesc.descriptorString() : Util.toInternalName(classDesc))); } @@ -503,7 +506,7 @@ public sealed interface ConstantPoolBuilder if (c instanceof Long l) return longEntry(l); if (c instanceof Float f) return floatEntry(f); if (c instanceof Double d) return doubleEntry(d); - if (c instanceof ClassDesc cd) return classEntry(cd); + if (c instanceof ClassDesc cd && !cd.isPrimitive()) return classEntry(cd); if (c instanceof MethodTypeDesc mtd) return methodTypeEntry(mtd); if (c instanceof DirectMethodHandleDesc dmhd) return methodHandleEntry(dmhd); if (c instanceof DynamicConstantDesc dcd) return constantDynamicEntry(dcd); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 8e3ec3016eb..2353fa905a0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -325,7 +325,7 @@ public class BytecodeHelpers { if (constantValue instanceof String value) { return constantPool.stringEntry(value); } - if (constantValue instanceof ClassDesc value) { + if (constantValue instanceof ClassDesc value && !value.isPrimitive()) { return constantPool.classEntry(value); } if (constantValue instanceof Long value) { diff --git a/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java b/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java new file mode 100644 index 00000000000..f4e14c3da43 --- /dev/null +++ b/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8304031 + * @summary Testing that primitive class descs are encoded properly as loadable constants. + * @run junit PrimitiveClassConstantTest + */ + +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.function.Supplier; +import jdk.internal.classfile.Classfile; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static java.lang.constant.ConstantDescs.CD_Class; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_long; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; +import static jdk.internal.classfile.Classfile.ACC_PUBLIC; + +public final class PrimitiveClassConstantTest { + + @Test + public void test() throws Throwable { + ClassDesc ape = ClassDesc.of("Ape"); + var lookup = MethodHandles.lookup(); + Class a = lookup.defineClass(Classfile.build(ape, clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(Supplier.class.describeConstable().orElseThrow()); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody("get", MethodTypeDesc.of(CD_Object), ACC_PUBLIC, cob -> { + cob.constantInstruction(CD_int); + cob.areturn(); + }); + clb.withMethodBody("get2", MethodTypeDesc.of(CD_Class), ACC_PUBLIC, cob -> { + Assertions.assertThrows(IllegalArgumentException.class, () -> cob.constantPool().classEntry(CD_long)); + var t = cob.constantPool().loadableConstantEntry(CD_long); + cob.ldc(t); + cob.areturn(); + }); + })); + Supplier t = (Supplier) lookup.findConstructor(a, MethodType.methodType(void.class)) + .asType(MethodType.methodType(Supplier.class)) + .invokeExact(); + Assertions.assertSame(int.class, t.get()); + } + +}