1 /* 2 * Copyright (c) 2013, 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 * @test 26 * @bug 8011805 27 * @summary Update sun.tools.java class file reading/writing support to include 28 * the new constant pool entries (including invokedynamic) 29 * @modules jdk.rmic/sun.rmi.rmic 30 * jdk.rmic/sun.tools.java 31 * @run main CFCTest 32 */ 33 34 import java.io.DataInputStream; 35 import java.io.EOFException; 36 import java.io.File; 37 import java.io.FileInputStream; 38 import java.io.IOException; 39 import sun.tools.java.ClassDeclaration; 40 import sun.tools.java.Identifier; 41 import sun.rmi.rmic.BatchEnvironment; 42 43 public class CFCTest { 44 45 /* Constant table */ 46 private static final int CONSTANT_UTF8 = 1; 47 private static final int CONSTANT_INTEGER = 3; 48 private static final int CONSTANT_FLOAT = 4; 49 private static final int CONSTANT_LONG = 5; 50 private static final int CONSTANT_DOUBLE = 6; 51 private static final int CONSTANT_CLASS = 7; 52 private static final int CONSTANT_STRING = 8; 53 private static final int CONSTANT_FIELD = 9; 54 private static final int CONSTANT_METHOD = 10; 55 private static final int CONSTANT_INTERFACEMETHOD = 11; 56 private static final int CONSTANT_NAMEANDTYPE = 12; 57 private static final int CONSTANT_METHODHANDLE = 15; 58 private static final int CONSTANT_METHODTYPE = 16; 59 private static final int CONSTANT_INVOKEDYNAMIC = 18; 60 61 String testClassName = this.getClass().getCanonicalName(); 62 String testClassPath = System.getProperty("test.classes", "."); 63 64 interface I { 65 int get(); 66 } 67 68 public static void main(String[] args) throws Exception { 69 new CFCTest().testNewConstants(); 70 } 71 72 void testNewConstants() throws Exception { 73 // Presence of lambda causes new constant pool constant types to be used 74 I lam = () -> 88; 75 if (lam.get() == 88) { 76 System.out.println("Sanity passed: Lambda worked."); 77 } else { 78 throw new RuntimeException("Sanity failed: bad lambda execution"); 79 } 80 81 // Verify that all the new constant pool constant types are present 82 String clsName = testClassPath + File.separator + testClassName + ".class"; 83 ClassConstantChecker ccc = new ClassConstantChecker(clsName); 84 ccc.checkFound(CONSTANT_METHODHANDLE); 85 ccc.checkFound(CONSTANT_METHODTYPE); 86 ccc.checkFound(CONSTANT_INVOKEDYNAMIC); 87 88 // Heart of test: read the class file with the new constant types 89 exerciseClassDefinition(); 90 System.out.println("ClassDefinition read without failure.\n"); 91 } 92 93 /** 94 * Failure is seen when getClassDefinition causes class read 95 */ 96 void exerciseClassDefinition() throws Exception { 97 BatchEnvironment env = new BatchEnvironment(System.out, 98 BatchEnvironment.createClassPath(testClassPath, null), 99 null); 100 try { 101 ClassDeclaration decl = env.getClassDeclaration( 102 Identifier.lookup(testClassName)); 103 decl.getClassDefinition(env); 104 } finally { 105 env.flushErrors(); 106 env.shutdown(); 107 } 108 } 109 110 private class ClassConstantChecker { 111 112 private DataInputStream in; 113 private boolean[] found; 114 115 ClassConstantChecker(String clsName) throws IOException { 116 in = new DataInputStream(new FileInputStream(clsName)); 117 found = new boolean[CONSTANT_INVOKEDYNAMIC + 20]; 118 try { 119 check(); 120 } finally { 121 in.close(); 122 } 123 } 124 125 void checkFound(int tag) throws Exception { 126 if (found[tag]) { 127 System.out.printf("Constant pool tag found: %d\n", tag); 128 } else { 129 throw new RuntimeException("Insufficient test, constant pool tag NOT found: " + tag); 130 } 131 } 132 133 private void skip(int n) throws IOException { 134 if (in.skipBytes(n) != n) { 135 throw new EOFException(); 136 } 137 } 138 139 private void check() throws IOException { 140 skip(8); // magic, version 141 int count = in.readUnsignedShort(); 142 for (int i = 1; i < count; i++) { 143 int j = i; 144 // JVM 4.4 cp_info.tag 145 int tag = in.readByte(); 146 found[tag] = true; 147 switch (tag) { 148 case CONSTANT_UTF8: 149 in.readUTF(); 150 break; 151 case CONSTANT_LONG: 152 case CONSTANT_DOUBLE: 153 skip(8); 154 break; 155 case CONSTANT_CLASS: 156 case CONSTANT_STRING: 157 skip(2); 158 break; 159 case CONSTANT_INTEGER: 160 case CONSTANT_FLOAT: 161 case CONSTANT_FIELD: 162 case CONSTANT_METHOD: 163 case CONSTANT_INTERFACEMETHOD: 164 case CONSTANT_NAMEANDTYPE: 165 skip(4); 166 break; 167 168 case CONSTANT_METHODHANDLE: 169 skip(3); 170 break; 171 case CONSTANT_METHODTYPE: 172 skip(2); 173 break; 174 case CONSTANT_INVOKEDYNAMIC: 175 skip(4); 176 break; 177 178 case 0: 179 default: 180 throw new ClassFormatError("invalid constant type: " + tag); 181 } 182 } 183 } 184 } 185 }