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