diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index ca5bf8a765634..7e298de30600f 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -285,24 +285,6 @@ String classData(Object arg) { return name; } - List<Object> classDataValues() { - final List<ClassData> cd = classData; - return switch(cd.size()) { - case 0 -> List.of(); - case 1 -> List.of(cd.get(0).value); - case 2 -> List.of(cd.get(0).value, cd.get(1).value); - case 3 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value); - case 4 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value, cd.get(3).value); - default -> { - Object[] data = new Object[classData.size()]; - for (int i = 0; i < classData.size(); i++) { - data[i] = classData.get(i).value; - } - yield List.of(data); - } - }; - } - private static String debugString(Object arg) { if (arg instanceof MethodHandle mh) { MemberName member = mh.internalMemberName(); @@ -360,6 +342,32 @@ private void methodEpilogue() { mv.visitEnd(); } + /** + * Returns the class data object that will be passed to `Lookup.defineHiddenClassWithClassData`. + * The classData is loaded in the <clinit> method of the generated class. + * If the class data contains only one single object, this method returns that single object. + * If the class data contains more than one objects, this method returns a List. + * + * This method returns null if no class data. + */ + private Object classDataValues() { + final List<ClassData> cd = classData; + return switch (cd.size()) { + case 0 -> null; // special case (classData is not used by <clinit>) + case 1 -> cd.get(0).value; // special case (single object) + case 2 -> List.of(cd.get(0).value, cd.get(1).value); + case 3 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value); + case 4 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value, cd.get(3).value); + default -> { + Object[] data = new Object[classData.size()]; + for (int i = 0; i < classData.size(); i++) { + data[i] = classData.get(i).value; + } + yield List.of(data); + } + }; + } + /* * <clinit> to initialize the static final fields with the live class data * LambdaForms can't use condy due to bootstrapping issue. @@ -379,18 +387,23 @@ static void clinit(ClassWriter cw, String className, List<ClassData> classData) mv.visitLdcInsn(Type.getType("L" + className + ";")); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandles", "classData", "(Ljava/lang/Class;)Ljava/lang/Object;", false); - // we should optimize one single element case that does not need to create a List - mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/List"); - mv.visitVarInsn(Opcodes.ASTORE, 0); - int index = 0; - for (ClassData p : classData) { - // initialize the static field - mv.visitVarInsn(Opcodes.ALOAD, 0); - emitIconstInsn(mv, index++); - mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/List", - "get", "(I)Ljava/lang/Object;", true); + if (classData.size() == 1) { + ClassData p = classData.get(0); mv.visitTypeInsn(Opcodes.CHECKCAST, p.desc.substring(1, p.desc.length()-1)); mv.visitFieldInsn(Opcodes.PUTSTATIC, className, p.name, p.desc); + } else { + mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/List"); + mv.visitVarInsn(Opcodes.ASTORE, 0); + int index = 0; + for (ClassData p : classData) { + // initialize the static field + mv.visitVarInsn(Opcodes.ALOAD, 0); + emitIconstInsn(mv, index++); + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/List", + "get", "(I)Ljava/lang/Object;", true); + mv.visitTypeInsn(Opcodes.CHECKCAST, p.desc.substring(1, p.desc.length()-1)); + mv.visitFieldInsn(Opcodes.PUTSTATIC, className, p.name, p.desc); + } } mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(2, 1);