jdk/test/sun/tools/java/CFCTest.java
changeset 16854 9371f5046d02
child 27565 729f9700483a
equal deleted inserted replaced
16853:3540ed1c1806 16854:9371f5046d02
       
     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 }