vromero@2027: /* vromero@2406: * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. vromero@2027: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. vromero@2027: * vromero@2027: * This code is free software; you can redistribute it and/or modify it vromero@2027: * under the terms of the GNU General Public License version 2 only, as vromero@2027: * published by the Free Software Foundation. vromero@2027: * vromero@2027: * This code is distributed in the hope that it will be useful, but WITHOUT vromero@2027: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or vromero@2027: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License vromero@2027: * version 2 for more details (a copy is included in the LICENSE file that vromero@2027: * accompanied this code). vromero@2027: * vromero@2027: * You should have received a copy of the GNU General Public License version vromero@2027: * 2 along with this work; if not, write to the Free Software Foundation, vromero@2027: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. vromero@2027: * vromero@2027: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA vromero@2027: * or visit www.oracle.com if you need additional information or have any vromero@2027: * questions. vromero@2027: */ vromero@2027: vromero@2027: /* vromero@2027: * @test vromero@2406: * @bug 7047734 8027660 8037937 vromero@2406: * @summary The LVT is not generated correctly during some try/catch scenarios vromero@2178: * javac crash while creating LVT entry for a local variable defined in vromero@2178: * an inner block vromero@2027: * @library /tools/javac/lib vromero@2027: * @build JavacTestingAbstractProcessor LVTHarness vromero@2027: * @run main LVTHarness vromero@2027: */ vromero@2027: vromero@2027: import java.io.File; vromero@2027: import java.io.IOException; vromero@2027: import java.lang.annotation.Annotation; vromero@2027: import java.util.Set; vromero@2027: import java.util.Arrays; vromero@2027: import java.util.ArrayList; vromero@2027: import java.util.Collections; vromero@2027: import java.util.HashMap; vromero@2027: import java.util.HashSet; vromero@2027: import java.util.List; vromero@2027: import java.util.Map; vromero@2027: vromero@2027: import javax.annotation.processing.RoundEnvironment; vromero@2027: import javax.lang.model.element.Element; vromero@2027: import javax.lang.model.element.TypeElement; vromero@2027: import javax.tools.JavaCompiler; vromero@2027: import javax.tools.JavaFileObject; vromero@2027: import javax.tools.StandardJavaFileManager; vromero@2027: import javax.tools.ToolProvider; vromero@2027: vromero@2027: import com.sun.source.util.JavacTask; vromero@2027: import com.sun.tools.classfile.Attribute; vromero@2027: import com.sun.tools.classfile.ClassFile; vromero@2027: import com.sun.tools.classfile.ConstantPool; vromero@2027: import com.sun.tools.classfile.ConstantPoolException; vromero@2027: import com.sun.tools.classfile.Code_attribute; vromero@2027: import com.sun.tools.classfile.ConstantPool.InvalidIndex; vromero@2027: import com.sun.tools.classfile.ConstantPool.UnexpectedEntry; vromero@2027: import com.sun.tools.classfile.Descriptor.InvalidDescriptor; vromero@2027: import com.sun.tools.classfile.LocalVariableTable_attribute; vromero@2027: import com.sun.tools.classfile.Method; vromero@2027: vromero@2027: import static javax.tools.StandardLocation.*; vromero@2027: import static com.sun.tools.classfile.LocalVariableTable_attribute.Entry; alundblad@2046: import static javax.tools.JavaFileObject.Kind.SOURCE; vromero@2027: vromero@2027: public class LVTHarness { vromero@2027: vromero@2027: static int nerrors = 0; vromero@2027: vromero@2027: static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); vromero@2027: static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); vromero@2027: vromero@2027: public static void main(String[] args) throws Exception { alundblad@2046: alundblad@2046: String testDir = System.getProperty("test.src"); alundblad@2046: fm.setLocation(SOURCE_PATH, Arrays.asList(new File(testDir, "tests"))); alundblad@2046: alundblad@2046: // Make sure classes are written to scratch dir. alundblad@2046: fm.setLocation(CLASS_OUTPUT, Arrays.asList(new File("."))); alundblad@2046: alundblad@2046: for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(SOURCE), true)) { vromero@2027: new LVTHarness(jfo).check(); vromero@2027: } vromero@2027: if (nerrors > 0) { vromero@2027: throw new AssertionError("Errors were found"); vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: vromero@2027: JavaFileObject jfo; alundblad@2046: Map aliveRangeMap = new HashMap<>(); vromero@2027: Set declaredKeys = new HashSet<>(); vromero@2027: List seenAliveRanges = new ArrayList<>(); vromero@2027: vromero@2027: protected LVTHarness(JavaFileObject jfo) { vromero@2027: this.jfo = jfo; vromero@2027: } vromero@2027: vromero@2027: protected void check() throws Exception { alundblad@2046: alundblad@2046: JavacTask ct = (JavacTask) comp.getTask(null, fm, null, Arrays.asList("-g"), alundblad@2046: null, Arrays.asList(jfo)); alundblad@2046: System.err.println("compiling code " + jfo); vromero@2027: ct.setProcessors(Collections.singleton(new AliveRangeFinder())); vromero@2027: if (!ct.call()) { vromero@2027: throw new AssertionError("Error during compilation"); vromero@2027: } vromero@2027: alundblad@2046: alundblad@2046: File javaFile = new File(jfo.getName()); alundblad@2046: File classFile = new File(javaFile.getName().replace(".java", ".class")); alundblad@2046: checkClassFile(classFile); vromero@2027: vromero@2027: //check all candidates have been used up vromero@2027: for (Map.Entry entry : aliveRangeMap.entrySet()) { vromero@2027: if (!seenAliveRanges.contains(entry.getKey())) { vromero@2027: error("Redundant @AliveRanges annotation on method " + vromero@2406: entry.getKey().elem + " with key " + entry.getKey()); vromero@2027: } vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: void checkClassFile(File file) vromero@2027: throws IOException, ConstantPoolException, InvalidDescriptor { vromero@2027: ClassFile classFile = ClassFile.read(file); vromero@2027: ConstantPool constantPool = classFile.constant_pool; vromero@2027: vromero@2027: //lets get all the methods in the class file. vromero@2027: for (Method method : classFile.methods) { vromero@2027: for (ElementKey elementKey: aliveRangeMap.keySet()) { vromero@2027: String methodDesc = method.getName(constantPool) + vromero@2406: method.descriptor.getParameterTypes(constantPool).replace(" ", ""); vromero@2027: if (methodDesc.equals(elementKey.elem.toString())) { vromero@2027: checkMethod(constantPool, method, aliveRangeMap.get(elementKey)); vromero@2027: seenAliveRanges.add(elementKey); vromero@2027: } vromero@2027: } vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: void checkMethod(ConstantPool constantPool, Method method, AliveRanges ranges) vromero@2027: throws InvalidIndex, UnexpectedEntry { vromero@2027: Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code); vromero@2027: LocalVariableTable_attribute lvt = vromero@2027: (LocalVariableTable_attribute) (code.attributes.get(Attribute.LocalVariableTable)); vromero@2027: List infoFromRanges = convertToStringList(ranges); vromero@2027: List infoFromLVT = convertToStringList(constantPool, lvt); vromero@2027: vromero@2027: // infoFromRanges most be contained in infoFromLVT vromero@2027: int i = 0; vromero@2027: int j = 0; vromero@2027: while (i < infoFromRanges.size() && j < infoFromLVT.size()) { vromero@2027: int comparison = infoFromRanges.get(i).compareTo(infoFromLVT.get(j)); vromero@2027: if (comparison == 0) { vromero@2027: i++; j++; vromero@2027: } else if (comparison > 0) { vromero@2027: j++; vromero@2027: } else { vromero@2027: break; vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: if (i < infoFromRanges.size()) { vromero@2027: error(infoFromLVT, infoFromRanges); vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: List convertToStringList(AliveRanges ranges) { vromero@2027: List result = new ArrayList<>(); vromero@2027: for (Annotation anno : ranges.value()) { vromero@2027: AliveRange range = (AliveRange)anno; vromero@2027: String str = formatLocalVariableData(range.varName(), vromero@2027: range.bytecodeStart(), range.bytecodeLength()); vromero@2027: result.add(str); vromero@2027: } vromero@2027: Collections.sort(result); vromero@2027: return result; vromero@2027: } vromero@2027: vromero@2027: List convertToStringList(ConstantPool constantPool, vromero@2027: LocalVariableTable_attribute lvt) throws InvalidIndex, UnexpectedEntry { vromero@2027: List result = new ArrayList<>(); vromero@2027: for (Entry entry : lvt.local_variable_table) { vromero@2027: String str = formatLocalVariableData(constantPool.getUTF8Value(entry.name_index), vromero@2027: entry.start_pc, entry.length); vromero@2027: result.add(str); vromero@2027: } vromero@2027: Collections.sort(result); vromero@2027: return result; vromero@2027: } vromero@2027: vromero@2027: String formatLocalVariableData(String varName, int start, int length) { vromero@2027: StringBuilder sb = new StringBuilder() vromero@2027: .append("var name: ").append(varName) vromero@2027: .append(" start: ").append(start) vromero@2027: .append(" length: ").append(length); vromero@2027: return sb.toString(); vromero@2027: } vromero@2027: vromero@2027: protected void error(List infoFromLVT, List infoFromRanges) { vromero@2027: nerrors++; vromero@2027: System.err.printf("Error occurred while checking file: %s\n", jfo.getName()); vromero@2027: System.err.println("The range info from the annotations is"); vromero@2027: printStringListToErrOutput(infoFromRanges); vromero@2027: System.err.println(); vromero@2027: System.err.println("And the range info from the class file is"); vromero@2027: printStringListToErrOutput(infoFromLVT); vromero@2027: System.err.println(); vromero@2027: } vromero@2027: vromero@2027: void printStringListToErrOutput(List list) { vromero@2027: for (String s : list) { vromero@2027: System.err.println("\t" + s); vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: protected void error(String msg) { vromero@2027: nerrors++; vromero@2027: System.err.printf("Error occurred while checking file: %s\nreason: %s\n", vromero@2027: jfo.getName(), msg); vromero@2027: } vromero@2027: vromero@2027: class AliveRangeFinder extends JavacTestingAbstractProcessor { vromero@2027: vromero@2027: @Override vromero@2027: public boolean process(Set annotations, vromero@2027: RoundEnvironment roundEnv) { vromero@2027: if (roundEnv.processingOver()) vromero@2027: return true; vromero@2027: vromero@2027: TypeElement aliveRangeAnno = elements.getTypeElement("AliveRanges"); vromero@2027: vromero@2027: if (!annotations.contains(aliveRangeAnno)) { vromero@2027: error("no @AliveRanges annotation found in test class"); vromero@2027: } vromero@2027: vromero@2027: for (Element elem: roundEnv.getElementsAnnotatedWith(aliveRangeAnno)) { vromero@2027: Annotation annotation = elem.getAnnotation(AliveRanges.class); vromero@2027: aliveRangeMap.put(new ElementKey(elem), (AliveRanges)annotation); vromero@2027: } vromero@2027: return true; vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: class ElementKey { vromero@2027: vromero@2027: String key; vromero@2027: Element elem; vromero@2027: vromero@2027: public ElementKey(Element elem) { vromero@2027: this.elem = elem; vromero@2027: this.key = computeKey(elem); vromero@2027: } vromero@2027: vromero@2027: @Override vromero@2027: public boolean equals(Object obj) { vromero@2027: if (obj instanceof ElementKey) { vromero@2027: ElementKey other = (ElementKey)obj; vromero@2027: return other.key.equals(key); vromero@2027: } vromero@2027: return false; vromero@2027: } vromero@2027: vromero@2027: @Override vromero@2027: public int hashCode() { vromero@2027: return key.hashCode(); vromero@2027: } vromero@2027: vromero@2027: String computeKey(Element e) { vromero@2027: StringBuilder buf = new StringBuilder(); vromero@2027: while (e != null) { vromero@2027: buf.append(e.toString()); vromero@2027: e = e.getEnclosingElement(); vromero@2027: } vromero@2027: buf.append(jfo.getName()); vromero@2027: return buf.toString(); vromero@2027: } vromero@2027: vromero@2027: @Override vromero@2027: public String toString() { vromero@2027: return "Key{" + key + "}"; vromero@2027: } vromero@2027: } vromero@2027: vromero@2027: }