1 /* 2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* 26 * @test 27 * @summary classes with major version < JDK_6 (50) should not be included in CDS 28 * @requires vm.cds 29 * @library /test/lib 30 * @modules java.base/jdk.internal.org.objectweb.asm 31 * java.base/jdk.internal.misc 32 * java.management 33 * jdk.jartool/sun.tools.jar 34 * @compile test-classes/Hello.java 35 * @run build TestCommon JarBuilder 36 * @run driver OldClassTest 37 */ 38 39 import java.io.File; 40 import java.io.FileOutputStream; 41 import jdk.test.lib.process.OutputAnalyzer; 42 import java.nio.file.Files; 43 44 import java.util.*; 45 import jdk.internal.org.objectweb.asm.*; 46 47 public class OldClassTest implements Opcodes { 48 49 public static void main(String[] args) throws Exception { 50 File jarSrcFile = new File(JarBuilder.getOrCreateHelloJar()); 51 52 File dir = new File(System.getProperty("test.classes", ".")); 53 File jarFile = new File(dir, "OldClassTest_old.jar"); 54 String jar = jarFile.getPath(); 55 56 if (!jarFile.exists() || jarFile.lastModified() < jarSrcFile.lastModified()) { 57 createTestJarFile(jarSrcFile, jarFile); 58 } else { 59 System.out.println("Already up-to-date: " + jarFile); 60 } 61 62 String appClasses[] = TestCommon.list("Hello"); 63 64 // CASE 1: pre-JDK 6 compiled classes should be excluded from the dump 65 OutputAnalyzer output = TestCommon.dump(jar, appClasses); 66 TestCommon.checkExecReturn(output, 0, true, "Pre JDK 6 class not supported by CDS"); 67 68 TestCommon.run( 69 "-cp", jar, 70 "Hello") 71 .assertNormalExit("Hello Unicode world (Old)"); 72 73 // CASE 2: if we exlcude old version of this class, we should not pick up 74 // the newer version of this class in a subsequent classpath element. 75 String classpath = jar + File.pathSeparator + jarSrcFile.getPath(); 76 output = TestCommon.dump(classpath, appClasses); 77 TestCommon.checkExecReturn(output, 0, true, "Pre JDK 6 class not supported by CDS"); 78 79 TestCommon.run( 80 "-cp", classpath, 81 "Hello") 82 .assertNormalExit("Hello Unicode world (Old)"); 83 } 84 85 static void createTestJarFile(File jarSrcFile, File jarFile) throws Exception { 86 jarFile.delete(); 87 Files.copy(jarSrcFile.toPath(), jarFile.toPath()); 88 89 File dir = new File(System.getProperty("test.classes", ".")); 90 File outdir = new File(dir, "old_class_test_classes"); 91 outdir.delete(); 92 outdir.mkdir(); 93 94 writeClassFile(new File(outdir, "Hello.class"), makeOldHello()); 95 96 JarBuilder.update(jarFile.getPath(), outdir.getPath()); 97 } 98 99 static void writeClassFile(File file, byte bytecodes[]) throws Exception { 100 try (FileOutputStream fos = new FileOutputStream(file)) { 101 fos.write(bytecodes); 102 } 103 } 104 105 /* makeOldHello() was obtained using JDK8. We use a method name > 128 that would 106 trigger a call to java.lang.Character.isJavaIdentifierStart() during class 107 file parsing. 108 109 cat > Hello.java <<EOF 110 public class Hello { 111 public static void main(String args[]) { 112 System.out.println(\u1234()); 113 } 114 static String \u1234() { 115 return "Hello Unicode world (Old)"; 116 } 117 } 118 EOF 119 javac Hello.java 120 java jdk.internal.org.objectweb.asm.util.ASMifier Hello.class 121 122 */ 123 124 static byte[] makeOldHello() throws Exception { 125 ClassWriter cw = new ClassWriter(0); 126 FieldVisitor fv; 127 MethodVisitor mv; 128 AnnotationVisitor av0; 129 130 cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "Hello", null, "java/lang/Object", null); 131 132 { 133 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 134 mv.visitCode(); 135 mv.visitVarInsn(ALOAD, 0); 136 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 137 mv.visitInsn(RETURN); 138 mv.visitMaxs(1, 1); 139 mv.visitEnd(); 140 } 141 { 142 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); 143 mv.visitCode(); 144 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 145 mv.visitMethodInsn(INVOKESTATIC, "Hello", "\u1234", "()Ljava/lang/String;", false); 146 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 147 mv.visitInsn(RETURN); 148 mv.visitMaxs(2, 1); 149 mv.visitEnd(); 150 } 151 { 152 mv = cw.visitMethod(ACC_STATIC, "\u1234", "()Ljava/lang/String;", null, null); 153 mv.visitCode(); 154 mv.visitLdcInsn("Hello Unicode world (Old)"); 155 mv.visitInsn(ARETURN); 156 mv.visitMaxs(1, 0); 157 mv.visitEnd(); 158 } 159 cw.visitEnd(); 160 161 return cw.toByteArray(); 162 } 163 }