/* * Copyright (c) 2013, 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. * * 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 8011805 * @summary Update sun.tools.java class file reading/writing support to include the new constant pool entries (including invokedynamic) */ import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import sun.tools.java.ClassDeclaration; import sun.tools.java.Identifier; import sun.rmi.rmic.BatchEnvironment; public class CFCTest { /* Constant table */ private static final int CONSTANT_UTF8 = 1; private static final int CONSTANT_INTEGER = 3; private static final int CONSTANT_FLOAT = 4; private static final int CONSTANT_LONG = 5; private static final int CONSTANT_DOUBLE = 6; private static final int CONSTANT_CLASS = 7; private static final int CONSTANT_STRING = 8; private static final int CONSTANT_FIELD = 9; private static final int CONSTANT_METHOD = 10; private static final int CONSTANT_INTERFACEMETHOD = 11; private static final int CONSTANT_NAMEANDTYPE = 12; private static final int CONSTANT_METHODHANDLE = 15; private static final int CONSTANT_METHODTYPE = 16; private static final int CONSTANT_INVOKEDYNAMIC = 18; String testClassName = this.getClass().getCanonicalName(); String testClassPath = System.getProperty("test.classes", "."); interface I { int get(); } public static void main(String[] args) throws Exception { new CFCTest().testNewConstants(); } void testNewConstants() throws Exception { // Presence of lambda causes new constant pool constant types to be used I lam = () -> 88; if (lam.get() == 88) { System.out.println("Sanity passed: Lambda worked."); } else { throw new RuntimeException("Sanity failed: bad lambda execution"); } // Verify that all the new constant pool constant types are present String clsName = testClassPath + File.separator + testClassName + ".class"; ClassConstantChecker ccc = new ClassConstantChecker(clsName); ccc.checkFound(CONSTANT_METHODHANDLE); ccc.checkFound(CONSTANT_METHODTYPE); ccc.checkFound(CONSTANT_INVOKEDYNAMIC); // Heart of test: read the class file with the new constant types exerciseClassDefinition(); System.out.println("ClassDefinition read without failure.\n"); } /** * Failure is seen when getClassDefinition causes class read */ void exerciseClassDefinition() throws Exception { BatchEnvironment env = new BatchEnvironment(System.out, BatchEnvironment.createClassPath(testClassPath, null, null), null); try { ClassDeclaration decl = env.getClassDeclaration( Identifier.lookup(testClassName)); decl.getClassDefinition(env); } finally { env.flushErrors(); env.shutdown(); } } private class ClassConstantChecker { private DataInputStream in; private boolean[] found; ClassConstantChecker(String clsName) throws IOException { in = new DataInputStream(new FileInputStream(clsName)); found = new boolean[CONSTANT_INVOKEDYNAMIC + 20]; try { check(); } finally { in.close(); } } void checkFound(int tag) throws Exception { if (found[tag]) { System.out.printf("Constant pool tag found: %d\n", tag); } else { throw new RuntimeException("Insufficient test, constant pool tag NOT found: " + tag); } } private void skip(int n) throws IOException { if (in.skipBytes(n) != n) { throw new EOFException(); } } private void check() throws IOException { skip(8); // magic, version int count = in.readUnsignedShort(); for (int i = 1; i < count; i++) { int j = i; // JVM 4.4 cp_info.tag int tag = in.readByte(); found[tag] = true; switch (tag) { case CONSTANT_UTF8: in.readUTF(); break; case CONSTANT_LONG: case CONSTANT_DOUBLE: skip(8); break; case CONSTANT_CLASS: case CONSTANT_STRING: skip(2); break; case CONSTANT_INTEGER: case CONSTANT_FLOAT: case CONSTANT_FIELD: case CONSTANT_METHOD: case CONSTANT_INTERFACEMETHOD: case CONSTANT_NAMEANDTYPE: skip(4); break; case CONSTANT_METHODHANDLE: skip(3); break; case CONSTANT_METHODTYPE: skip(2); break; case CONSTANT_INVOKEDYNAMIC: skip(4); break; case 0: default: throw new ClassFormatError("invalid constant type: " + tag); } } } } }