test/tools/javac/flow/LVTHarness.java

Thu, 10 Oct 2013 14:58:04 +0200

author
ihse
date
Thu, 10 Oct 2013 14:58:04 +0200
changeset 2094
343aeb2033f0
parent 2046
1fe358ea75ff
child 2178
cc80c03c41e4
permissions
-rw-r--r--

8001931: The new build system whitespace cleanup
Reviewed-by: tbell, simonis, erikj

     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  */
    24 /*
    25  * @test
    26  * @bug 7047734
    27  * @summary The LVT is not generated correctly during some try/catch scenarios
    28  * @library /tools/javac/lib
    29  * @build JavacTestingAbstractProcessor LVTHarness
    30  * @run main LVTHarness
    31  */
    33 import java.io.File;
    34 import java.io.IOException;
    35 import java.lang.annotation.Annotation;
    36 import java.util.Set;
    37 import java.util.Arrays;
    38 import java.util.ArrayList;
    39 import java.util.Collections;
    40 import java.util.HashMap;
    41 import java.util.HashSet;
    42 import java.util.List;
    43 import java.util.Map;
    45 import javax.annotation.processing.RoundEnvironment;
    46 import javax.lang.model.element.Element;
    47 import javax.lang.model.element.TypeElement;
    48 import javax.tools.JavaCompiler;
    49 import javax.tools.JavaFileObject;
    50 import javax.tools.StandardJavaFileManager;
    51 import javax.tools.ToolProvider;
    53 import com.sun.source.util.JavacTask;
    54 import com.sun.tools.classfile.Attribute;
    55 import com.sun.tools.classfile.ClassFile;
    56 import com.sun.tools.classfile.ConstantPool;
    57 import com.sun.tools.classfile.ConstantPoolException;
    58 import com.sun.tools.classfile.Code_attribute;
    59 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
    60 import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
    61 import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
    62 import com.sun.tools.classfile.LocalVariableTable_attribute;
    63 import com.sun.tools.classfile.Method;
    65 import static javax.tools.StandardLocation.*;
    66 import static com.sun.tools.classfile.LocalVariableTable_attribute.Entry;
    67 import static javax.tools.JavaFileObject.Kind.SOURCE;
    69 public class LVTHarness {
    71     static int nerrors = 0;
    73     static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
    74     static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
    76     public static void main(String[] args) throws Exception {
    78         String testDir = System.getProperty("test.src");
    79         fm.setLocation(SOURCE_PATH, Arrays.asList(new File(testDir, "tests")));
    81         // Make sure classes are written to scratch dir.
    82         fm.setLocation(CLASS_OUTPUT, Arrays.asList(new File(".")));
    84         for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(SOURCE), true)) {
    85             new LVTHarness(jfo).check();
    86         }
    87         if (nerrors > 0) {
    88             throw new AssertionError("Errors were found");
    89         }
    90     }
    93     JavaFileObject jfo;
    94     Map<ElementKey, AliveRanges> aliveRangeMap = new HashMap<>();
    95     Set<String> declaredKeys = new HashSet<>();
    96     List<ElementKey> seenAliveRanges = new ArrayList<>();
    98     protected LVTHarness(JavaFileObject jfo) {
    99         this.jfo = jfo;
   100     }
   102     protected void check() throws Exception {
   104         JavacTask ct = (JavacTask) comp.getTask(null, fm, null, Arrays.asList("-g"),
   105                                                 null, Arrays.asList(jfo));
   106         System.err.println("compiling code " + jfo);
   107         ct.setProcessors(Collections.singleton(new AliveRangeFinder()));
   108         if (!ct.call()) {
   109             throw new AssertionError("Error during compilation");
   110         }
   113         File javaFile = new File(jfo.getName());
   114         File classFile = new File(javaFile.getName().replace(".java", ".class"));
   115         checkClassFile(classFile);
   117         //check all candidates have been used up
   118         for (Map.Entry<ElementKey, AliveRanges> entry : aliveRangeMap.entrySet()) {
   119             if (!seenAliveRanges.contains(entry.getKey())) {
   120                 error("Redundant @AliveRanges annotation on method " +
   121                         entry.getKey().elem);
   122             }
   123         }
   124     }
   126     void checkClassFile(File file)
   127             throws IOException, ConstantPoolException, InvalidDescriptor {
   128         ClassFile classFile = ClassFile.read(file);
   129         ConstantPool constantPool = classFile.constant_pool;
   131         //lets get all the methods in the class file.
   132         for (Method method : classFile.methods) {
   133             for (ElementKey elementKey: aliveRangeMap.keySet()) {
   134                 String methodDesc = method.getName(constantPool) +
   135                         method.descriptor.getParameterTypes(constantPool);
   136                 if (methodDesc.equals(elementKey.elem.toString())) {
   137                     checkMethod(constantPool, method, aliveRangeMap.get(elementKey));
   138                     seenAliveRanges.add(elementKey);
   139                 }
   140             }
   141         }
   142     }
   144     void checkMethod(ConstantPool constantPool, Method method, AliveRanges ranges)
   145             throws InvalidIndex, UnexpectedEntry {
   146         Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code);
   147         LocalVariableTable_attribute lvt =
   148             (LocalVariableTable_attribute) (code.attributes.get(Attribute.LocalVariableTable));
   149         List<String> infoFromRanges = convertToStringList(ranges);
   150         List<String> infoFromLVT = convertToStringList(constantPool, lvt);
   152         // infoFromRanges most be contained in infoFromLVT
   153         int i = 0;
   154         int j = 0;
   155         while (i < infoFromRanges.size() && j < infoFromLVT.size()) {
   156             int comparison = infoFromRanges.get(i).compareTo(infoFromLVT.get(j));
   157             if (comparison == 0) {
   158                 i++; j++;
   159             } else if (comparison > 0) {
   160                 j++;
   161             } else {
   162                 break;
   163             }
   164         }
   166         if (i < infoFromRanges.size()) {
   167             error(infoFromLVT, infoFromRanges);
   168         }
   169     }
   171     List<String> convertToStringList(AliveRanges ranges) {
   172         List<String> result = new ArrayList<>();
   173         for (Annotation anno : ranges.value()) {
   174             AliveRange range = (AliveRange)anno;
   175             String str = formatLocalVariableData(range.varName(),
   176                     range.bytecodeStart(), range.bytecodeLength());
   177             result.add(str);
   178         }
   179         Collections.sort(result);
   180         return result;
   181     }
   183     List<String> convertToStringList(ConstantPool constantPool,
   184             LocalVariableTable_attribute lvt) throws InvalidIndex, UnexpectedEntry {
   185         List<String> result = new ArrayList<>();
   186         for (Entry entry : lvt.local_variable_table) {
   187             String str = formatLocalVariableData(constantPool.getUTF8Value(entry.name_index),
   188                     entry.start_pc, entry.length);
   189             result.add(str);
   190         }
   191         Collections.sort(result);
   192         return result;
   193     }
   195     String formatLocalVariableData(String varName, int start, int length) {
   196         StringBuilder sb = new StringBuilder()
   197                     .append("var name: ").append(varName)
   198                     .append(" start: ").append(start)
   199                     .append(" length: ").append(length);
   200         return sb.toString();
   201     }
   203     protected void error(List<String> infoFromLVT, List<String> infoFromRanges) {
   204         nerrors++;
   205         System.err.printf("Error occurred while checking file: %s\n", jfo.getName());
   206         System.err.println("The range info from the annotations is");
   207         printStringListToErrOutput(infoFromRanges);
   208         System.err.println();
   209         System.err.println("And the range info from the class file is");
   210         printStringListToErrOutput(infoFromLVT);
   211         System.err.println();
   212     }
   214     void printStringListToErrOutput(List<String> list) {
   215         for (String s : list) {
   216             System.err.println("\t" + s);
   217         }
   218     }
   220     protected void error(String msg) {
   221         nerrors++;
   222         System.err.printf("Error occurred while checking file: %s\nreason: %s\n",
   223                 jfo.getName(), msg);
   224     }
   226     class AliveRangeFinder extends JavacTestingAbstractProcessor {
   228         @Override
   229         public boolean process(Set<? extends TypeElement> annotations,
   230             RoundEnvironment roundEnv) {
   231             if (roundEnv.processingOver())
   232                 return true;
   234             TypeElement aliveRangeAnno = elements.getTypeElement("AliveRanges");
   236             if (!annotations.contains(aliveRangeAnno)) {
   237                 error("no @AliveRanges annotation found in test class");
   238             }
   240             for (Element elem: roundEnv.getElementsAnnotatedWith(aliveRangeAnno)) {
   241                 Annotation annotation = elem.getAnnotation(AliveRanges.class);
   242                 aliveRangeMap.put(new ElementKey(elem), (AliveRanges)annotation);
   243             }
   244             return true;
   245         }
   246     }
   248     class ElementKey {
   250         String key;
   251         Element elem;
   253         public ElementKey(Element elem) {
   254             this.elem = elem;
   255             this.key = computeKey(elem);
   256         }
   258         @Override
   259         public boolean equals(Object obj) {
   260             if (obj instanceof ElementKey) {
   261                 ElementKey other = (ElementKey)obj;
   262                 return other.key.equals(key);
   263             }
   264             return false;
   265         }
   267         @Override
   268         public int hashCode() {
   269             return key.hashCode();
   270         }
   272         String computeKey(Element e) {
   273             StringBuilder buf = new StringBuilder();
   274             while (e != null) {
   275                 buf.append(e.toString());
   276                 e = e.getEnclosingElement();
   277             }
   278             buf.append(jfo.getName());
   279             return buf.toString();
   280         }
   282         @Override
   283         public String toString() {
   284             return "Key{" + key + "}";
   285         }
   286     }
   288 }

mercurial