changeset 2044:979f55cda0e2

8065674: javac generates incorrect LVT table for trivial cases Reviewed-by: jjg Contributed-by: vicente.romero@oracle.com
author robm
date Wed, 26 Nov 2014 17:03:13 +0000
parents 20376611cb3b
children 04b56f4312b6
files src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/share/classes/com/sun/tools/javac/jvm/Code.java test/tools/javac/flow/DARanges.java test/tools/javac/flow/LVTHarness.java test/tools/javac/flow/tests/TestCaseConditional.java test/tools/javac/flow/tests/TestCaseDoLoop.java test/tools/javac/flow/tests/TestCaseFor.java test/tools/javac/flow/tests/TestCaseForEach.java test/tools/javac/flow/tests/TestCaseIf.java test/tools/javac/flow/tests/TestCaseIfElse.java test/tools/javac/flow/tests/TestCaseLocalInInnerBlock.java test/tools/javac/flow/tests/TestCaseSwitch.java test/tools/javac/flow/tests/TestCaseTry.java test/tools/javac/flow/tests/TestCaseWhile.java
diffstat 14 files changed, 901 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Nov 20 14:01:11 2014 -0800
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Nov 26 17:03:13 2014 +0000
@@ -1012,25 +1012,29 @@
 
         if (code.varBufferSize > 0) {
             int alenIdx = writeAttr(names.LocalVariableTable);
-            databuf.appendChar(code.varBufferSize);
+            databuf.appendChar(code.getLVTSize());
 
             for (int i=0; i<code.varBufferSize; i++) {
                 Code.LocalVar var = code.varBuffer[i];
-
-                // write variable info
-                Assert.check(var.start_pc >= 0
-                        && var.start_pc <= code.cp);
-                databuf.appendChar(var.start_pc);
-                Assert.check(var.length >= 0
-                        && (var.start_pc + var.length) <= code.cp);
-                databuf.appendChar(var.length);
-                VarSymbol sym = var.sym;
-                databuf.appendChar(pool.put(sym.name));
-                Type vartype = sym.erasure(types);
-                if (needsLocalVariableTypeEntry(sym.type))
-                    nGenericVars++;
-                databuf.appendChar(pool.put(typeSig(vartype)));
-                databuf.appendChar(var.reg);
+                for (Code.LocalVar.Range r: var.aliveRanges) {
+                    // write variable info
+                    if (!(r.start_pc >= 0 && r.start_pc <= code.cp)) {
+                        throw new AssertionError();
+                    }
+                    databuf.appendChar(r.start_pc);
+                    if (!(r.length >= 0 && (r.start_pc + r.length) <= code.cp)) {
+                        throw new AssertionError();
+                    }
+                    databuf.appendChar(r.length);
+                    VarSymbol sym = var.sym;
+                    databuf.appendChar(pool.put(sym.name));
+                    Type vartype = sym.erasure(types);
+                    databuf.appendChar(pool.put(typeSig(vartype)));
+                    databuf.appendChar(var.reg);
+                    if (needsLocalVariableTypeEntry(var.sym.type)) {
+                        nGenericVars++;
+                    }
+                }
             }
             endAttr(alenIdx);
             acount++;
@@ -1046,13 +1050,15 @@
                 VarSymbol sym = var.sym;
                 if (!needsLocalVariableTypeEntry(sym.type))
                     continue;
-                count++;
-                // write variable info
-                databuf.appendChar(var.start_pc);
-                databuf.appendChar(var.length);
-                databuf.appendChar(pool.put(sym.name));
-                databuf.appendChar(pool.put(typeSig(sym.type)));
-                databuf.appendChar(var.reg);
+                for (Code.LocalVar.Range r : var.aliveRanges) {
+                    // write variable info
+                    databuf.appendChar(r.start_pc);
+                    databuf.appendChar(r.length);
+                    databuf.appendChar(pool.put(sym.name));
+                    databuf.appendChar(pool.put(typeSig(sym.type)));
+                    databuf.appendChar(var.reg);
+                    count++;
+                }
             }
             Assert.check(count == nGenericVars);
             endAttr(alenIdx);
--- a/src/share/classes/com/sun/tools/javac/jvm/Code.java	Thu Nov 20 14:01:11 2014 -0800
+++ b/src/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Nov 26 17:03:13 2014 +0000
@@ -1151,7 +1151,9 @@
     public int entryPoint(State state) {
         int pc = curPc();
         alive = true;
-        this.state = state.dup();
+        State newState = state.dup();
+        setDefined(newState.defined);
+        this.state = newState;
         Assert.check(state.stacksize <= max_stack);
         if (debugCode) System.err.println("entry point " + state);
         pendingStackMap = needStackMap;
@@ -1164,7 +1166,9 @@
     public int entryPoint(State state, Type pushed) {
         int pc = curPc();
         alive = true;
-        this.state = state.dup();
+        State newState = state.dup();
+        setDefined(newState.defined);
+        this.state = newState;
         Assert.check(state.stacksize <= max_stack);
         this.state.push(pushed);
         if (debugCode) System.err.println("entry point " + state);
@@ -1452,6 +1456,10 @@
                 chain.pc + 3 == target && target == cp && !fixedPc) {
                 // If goto the next instruction, the jump is not needed:
                 // compact the code.
+                if (varDebugInfo) {
+                    adjustAliveRanges(cp, -3);
+                }
+
                 cp = cp - 3;
                 target = target - 3;
                 if (chain.next == null) {
@@ -1736,8 +1744,7 @@
                     sym = sym.clone(sym.owner);
                     sym.type = newtype;
                     LocalVar newlv = lvar[i] = new LocalVar(sym);
-                    // should the following be initialized to cp?
-                    newlv.start_pc = lv.start_pc;
+                    newlv.aliveRanges = lv.aliveRanges;
                 }
             }
         }
@@ -1825,18 +1832,118 @@
     static class LocalVar {
         final VarSymbol sym;
         final char reg;
-        char start_pc = Character.MAX_VALUE;
-        char length = Character.MAX_VALUE;
+
+        class Range {
+            char start_pc = Character.MAX_VALUE;
+            char length = Character.MAX_VALUE;
+
+            Range() {}
+
+            Range(char start) {
+                this.start_pc = start;
+            }
+
+            Range(char start, char length) {
+                this.start_pc = start;
+                this.length = length;
+            }
+
+            boolean closed() {
+                return start_pc != Character.MAX_VALUE && length != Character.MAX_VALUE;
+            }
+
+            @Override
+            public String toString() {
+                int currentStartPC = start_pc;
+                int currentLength = length;
+                return "startpc = " + currentStartPC + " length " + currentLength;
+            }
+        }
+
+        java.util.List<Range> aliveRanges = new java.util.ArrayList<Range>();
+
         LocalVar(VarSymbol v) {
             this.sym = v;
             this.reg = (char)v.adr;
         }
+
         public LocalVar dup() {
             return new LocalVar(sym);
         }
+
+        Range firstRange() {
+            return aliveRanges.isEmpty() ? null : aliveRanges.get(0);
+        }
+
+        Range lastRange() {
+            return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1);
+        }
+
+        void removeLastRange() {
+            Range lastRange = lastRange();
+            if (lastRange != null) {
+                aliveRanges.remove(lastRange);
+            }
+        }
+
+        @Override
         public String toString() {
-            return "" + sym + " in register " + ((int)reg) + " starts at pc=" + ((int)start_pc) + " length=" + ((int)length);
+            if (aliveRanges == null) {
+                return "empty local var";
+            }
+            StringBuilder sb = new StringBuilder().append(sym)
+                    .append(" in register ").append((int)reg).append(" \n");
+            for (Range r : aliveRanges) {
+                sb.append(" starts at pc=").append(Integer.toString(((int)r.start_pc)))
+                    .append(" length=").append(Integer.toString(((int)r.length)))
+                    .append("\n");
+            }
+            return sb.toString();
         }
+
+        public void openRange(char start) {
+            if (!hasOpenRange()) {
+                aliveRanges.add(new Range(start));
+            }
+        }
+
+        public void closeRange(char length) {
+            if (isLastRangeInitialized() && length > 0) {
+                Range range = lastRange();
+                if (range != null) {
+                    if (range.length == Character.MAX_VALUE) {
+                        range.length = length;
+                    }
+                }
+            } else {
+                removeLastRange();
+            }
+        }
+
+        public boolean hasOpenRange() {
+            if (aliveRanges.isEmpty()) {
+                return false;
+            }
+            return lastRange().length == Character.MAX_VALUE;
+        }
+
+        public boolean isLastRangeInitialized() {
+            if (aliveRanges.isEmpty()) {
+                return false;
+            }
+            return lastRange().start_pc != Character.MAX_VALUE;
+        }
+
+        public Range getWidestRange() {
+            if (aliveRanges.isEmpty()) {
+                return new Range();
+            } else {
+                Range firstRange = firstRange();
+                Range lastRange = lastRange();
+                char length = (char)(lastRange.length + (lastRange.start_pc - firstRange.start_pc));
+                return new Range(firstRange.start_pc, length);
+            }
+         }
     };
 
     /** Local variables, indexed by register. */
@@ -1858,6 +1965,30 @@
         state.defined.excl(adr);
     }
 
+    void adjustAliveRanges(int oldCP, int delta) {
+        for (LocalVar localVar: lvar) {
+            if (localVar != null) {
+                for (LocalVar.Range range: localVar.aliveRanges) {
+                    if (range.closed() && range.start_pc + range.length >= oldCP) {
+                        range.length += delta;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Calculates the size of the LocalVariableTable.
+     */
+    public int getLVTSize() {
+        int result = varBufferSize;
+        for (int i = 0; i < varBufferSize; i++) {
+            LocalVar var = varBuffer[i];
+            result += var.aliveRanges.size() - 1;
+        }
+        return result;
+    }
+
     /** Set the current variable defined state. */
     public void setDefined(Bits newDefined) {
         if (alive && newDefined != state.defined) {
@@ -1883,8 +2014,7 @@
         } else {
             state.defined.incl(adr);
             if (cp < Character.MAX_VALUE) {
-                if (v.start_pc == Character.MAX_VALUE)
-                    v.start_pc = (char)cp;
+                v.openRange((char)cp);
             }
         }
     }
@@ -1894,15 +2024,15 @@
         state.defined.excl(adr);
         if (adr < lvar.length &&
             lvar[adr] != null &&
-            lvar[adr].start_pc != Character.MAX_VALUE) {
+            lvar[adr].isLastRangeInitialized()) {
             LocalVar v = lvar[adr];
-            char length = (char)(curPc() - v.start_pc);
+            char length = (char)(curPc()- v.lastRange().start_pc);
             if (length > 0 && length < Character.MAX_VALUE) {
                 lvar[adr] = v.dup();
-                v.length = length;
+                v.closeRange(length);
                 putVar(v);
             } else {
-                v.start_pc = Character.MAX_VALUE;
+                v.removeLastRange();
             }
         }
     }
@@ -1912,10 +2042,10 @@
         LocalVar v = lvar[adr];
         if (v != null) {
             lvar[adr] = null;
-            if (v.start_pc != Character.MAX_VALUE) {
-                char length = (char)(curPc() - v.start_pc);
+            if (v.isLastRangeInitialized()) {
+                char length = (char)(curPc()- v.lastRange().start_pc);
                 if (length < Character.MAX_VALUE) {
-                    v.length = length;
+                    v.closeRange(length);
                     putVar(v);
                 }
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/DARanges.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD})
+@interface DARange {
+    String varName();
+    int bytecodeStart();
+    int bytecodeLength();
+}
+
+@Target({ElementType.METHOD})
+@interface DARanges {DARange[] value();}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/LVTHarness.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2014, 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 8058708
+ * @summary The LVT is not generated correctly during some try/catch scenarios
+ *          javac crash while creating LVT entry for a local variable defined in
+ *          an inner block
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor LVTHarness
+ * @run main LVTHarness
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPool.InvalidIndex;
+import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.LocalVariableTable_attribute;
+import com.sun.tools.classfile.Method;
+
+import static javax.tools.StandardLocation.*;
+import static com.sun.tools.classfile.LocalVariableTable_attribute.Entry;
+import static javax.tools.JavaFileObject.Kind.SOURCE;
+
+public class LVTHarness {
+
+    static int nerrors = 0;
+
+    static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+    static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+    public static void main(String[] args) throws Exception {
+
+        String testDir = System.getProperty("test.src");
+        fm.setLocation(SOURCE_PATH, Arrays.asList(new File(testDir, "tests")));
+
+        // Make sure classes are written to scratch dir.
+        fm.setLocation(CLASS_OUTPUT, Arrays.asList(new File(".")));
+
+        for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(SOURCE), true)) {
+            new LVTHarness(jfo).check();
+        }
+        if (nerrors > 0) {
+            throw new AssertionError("Errors were found");
+        }
+    }
+
+
+    JavaFileObject jfo;
+    Map<ElementKey, DARanges> aliveRangeMap = new HashMap<ElementKey, DARanges>();
+    Set<String> declaredKeys = new HashSet<String>();
+    List<ElementKey> seenDARanges = new ArrayList<ElementKey>();
+
+    protected LVTHarness(JavaFileObject jfo) {
+        this.jfo = jfo;
+    }
+
+    protected void check() throws Exception {
+
+        JavacTask ct = (JavacTask) comp.getTask(null, fm, null, Arrays.asList("-g"),
+                                                null, Arrays.asList(jfo));
+        System.err.println("compiling code " + jfo);
+        ct.setProcessors(Collections.singleton(new DARangeFinder()));
+        if (!ct.call()) {
+            throw new AssertionError("Error during compilation");
+        }
+
+
+        File javaFile = new File(jfo.getName());
+        File classFile = new File(javaFile.getName().replace(".java", ".class"));
+        checkClassFile(classFile);
+
+        //check all candidates have been used up
+        for (Map.Entry<ElementKey, DARanges> entry : aliveRangeMap.entrySet()) {
+            if (!seenDARanges.contains(entry.getKey())) {
+                error("Redundant @DARanges annotation on method " +
+                        entry.getKey().elem + " with key " + entry.getKey());
+            }
+        }
+    }
+
+    void checkClassFile(File file)
+            throws IOException, ConstantPoolException, InvalidDescriptor {
+        ClassFile classFile = ClassFile.read(file);
+        ConstantPool constantPool = classFile.constant_pool;
+
+        //lets get all the methods in the class file.
+        for (Method method : classFile.methods) {
+            for (ElementKey elementKey: aliveRangeMap.keySet()) {
+                String methodDesc = method.getName(constantPool) +
+                        method.descriptor.getParameterTypes(constantPool).replace(" ", "");
+                if (methodDesc.equals(elementKey.elem.toString())) {
+                    checkMethod(constantPool, method, aliveRangeMap.get(elementKey));
+                    seenDARanges.add(elementKey);
+                }
+            }
+        }
+    }
+
+    void checkMethod(ConstantPool constantPool, Method method, DARanges ranges)
+            throws InvalidIndex, UnexpectedEntry {
+        Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code);
+        LocalVariableTable_attribute lvt =
+            (LocalVariableTable_attribute) (code.attributes.get(Attribute.LocalVariableTable));
+        List<String> infoFromRanges = convertToStringList(ranges);
+        List<String> infoFromLVT = convertToStringList(constantPool, lvt);
+
+        // infoFromRanges most be contained in infoFromLVT
+        int i = 0;
+        int j = 0;
+        while (i < infoFromRanges.size() && j < infoFromLVT.size()) {
+            int comparison = infoFromRanges.get(i).compareTo(infoFromLVT.get(j));
+            if (comparison == 0) {
+                i++; j++;
+            } else if (comparison > 0) {
+                j++;
+            } else {
+                break;
+            }
+        }
+
+        if (i < infoFromRanges.size()) {
+            error(infoFromLVT, infoFromRanges);
+        }
+    }
+
+    List<String> convertToStringList(DARanges ranges) {
+        List<String> result = new ArrayList<String>();
+        for (Annotation anno : ranges.value()) {
+            DARange range = (DARange)anno;
+            String str = formatLocalVariableData(range.varName(),
+                    range.bytecodeStart(), range.bytecodeLength());
+            result.add(str);
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    List<String> convertToStringList(ConstantPool constantPool,
+            LocalVariableTable_attribute lvt) throws InvalidIndex, UnexpectedEntry {
+        List<String> result = new ArrayList<String>();
+        for (Entry entry : lvt.local_variable_table) {
+            String str = formatLocalVariableData(constantPool.getUTF8Value(entry.name_index),
+                    entry.start_pc, entry.length);
+            result.add(str);
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    String formatLocalVariableData(String varName, int start, int length) {
+        StringBuilder sb = new StringBuilder()
+                    .append("var name: ").append(varName)
+                    .append(" start: ").append(start)
+                    .append(" length: ").append(length);
+        return sb.toString();
+    }
+
+    protected void error(List<String> infoFromLVT, List<String> infoFromRanges) {
+        nerrors++;
+        System.err.printf("Error occurred while checking file: %s\n", jfo.getName());
+        System.err.println("The range info from the annotations is");
+        printStringListToErrOutput(infoFromRanges);
+        System.err.println();
+        System.err.println("And the range info from the class file is");
+        printStringListToErrOutput(infoFromLVT);
+        System.err.println();
+    }
+
+    void printStringListToErrOutput(List<String> list) {
+        for (String s : list) {
+            System.err.println("\t" + s);
+        }
+    }
+
+    protected void error(String msg) {
+        nerrors++;
+        System.err.printf("Error occurred while checking file: %s\nreason: %s\n",
+                jfo.getName(), msg);
+    }
+
+    class DARangeFinder extends JavacTestingAbstractProcessor {
+
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations,
+            RoundEnvironment roundEnv) {
+            if (roundEnv.processingOver())
+                return true;
+
+            TypeElement aliveRangeAnno = elements.getTypeElement("DARanges");
+
+            if (!annotations.contains(aliveRangeAnno)) {
+                error("no @DARanges annotation found in test class");
+            }
+
+            for (Element elem: roundEnv.getElementsAnnotatedWith(aliveRangeAnno)) {
+                Annotation annotation = elem.getAnnotation(DARanges.class);
+                aliveRangeMap.put(new ElementKey(elem), (DARanges)annotation);
+            }
+            return true;
+        }
+    }
+
+    class ElementKey {
+
+        String key;
+        Element elem;
+
+        public ElementKey(Element elem) {
+            this.elem = elem;
+            this.key = computeKey(elem);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ElementKey) {
+                ElementKey other = (ElementKey)obj;
+                return other.key.equals(key);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return key.hashCode();
+        }
+
+        String computeKey(Element e) {
+            StringBuilder buf = new StringBuilder();
+            while (e != null) {
+                buf.append(e.toString());
+                e = e.getEnclosingElement();
+            }
+            buf.append(jfo.getName());
+            return buf.toString();
+        }
+
+        @Override
+        public String toString() {
+            return "Key{" + key + "}";
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseConditional.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,15 @@
+public class TestCaseConditional {
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=5, bytecodeLength=33),
+        @DARange(varName="oo", bytecodeStart=23, bytecodeLength=15)
+    })
+    void m(String[] args) {
+        Boolean o;
+        Boolean oo = ((o = Boolean.TRUE).booleanValue()) ?
+                o = Boolean.TRUE :
+                Boolean.FALSE;
+        oo.hashCode();
+        o = Boolean.FALSE;
+        o.hashCode();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseDoLoop.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,15 @@
+public class TestCaseDoLoop {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=3, bytecodeLength=15),
+        @DARange(varName="args", bytecodeStart=0, bytecodeLength=18)
+    })
+    void m(String[] args) {
+        Object o;
+        do {
+            o = "";
+            o.hashCode();
+        } while (args[0] != null);
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseFor.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,29 @@
+public class TestCaseFor {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=10, bytecodeLength=11),
+        @DARange(varName="o", bytecodeStart=24, bytecodeLength=1)
+    })
+    void m1(String[] args) {
+        Object o;
+        for (int i = 0; i < 5; i++) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=10, bytecodeLength=11),
+        @DARange(varName="o", bytecodeStart=24, bytecodeLength=1)
+    })
+    void m2(String[] args) {
+        Object o;
+        for (int i = 0; i < 5; i++) {
+            o = "";
+            o.hashCode();
+            continue;
+        }
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseForEach.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,15 @@
+public class TestCaseForEach {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=25, bytecodeLength=11),
+        @DARange(varName="o", bytecodeStart=39, bytecodeLength=1)
+    })
+    void m(String[] args) {
+        Object o;
+        for (String s : args) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseIf.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,84 @@
+public class TestCaseIf {
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=9, bytecodeLength=5),
+        @DARange(varName="o", bytecodeStart=17, bytecodeLength=1)
+    })
+    void m0(String[] args) {
+        Object o;
+        if (args[0] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=10, bytecodeLength=5),
+        @DARange(varName="o", bytecodeStart=18, bytecodeLength=1)
+    })
+    void m1() {
+        Object o;
+        int i = 5;
+        if (i == 5) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=10, bytecodeLength=5),
+        @DARange(varName="o", bytecodeStart=18, bytecodeLength=1)
+    })
+    void m2() {
+        Object o;
+        int i = 5;
+        if (!(i == 5)) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=15, bytecodeLength=5),
+        @DARange(varName="o", bytecodeStart=23, bytecodeLength=1)
+    })
+    void m3(String[] args) {
+        Object o;
+        if (args[0] != null && args[1] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=15, bytecodeLength=5),
+        @DARange(varName="o", bytecodeStart=23, bytecodeLength=1)
+    })
+    void m4(String[] args) {
+        Object o;
+        if (args[0] != null || args[1] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="finalLocal", bytecodeStart=11, bytecodeLength=6),
+        @DARange(varName="used", bytecodeStart=13, bytecodeLength=4)
+    })
+    void m5(Object o) {
+        if (o != null) {
+            Object notUsed;
+            Object used;
+            if (o != null) {
+                final Object finalLocal = null;
+                used = null;
+                if (o == null) {}
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseIfElse.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,69 @@
+public class TestCaseIfElse {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=9, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=20, bytecodeLength=9)
+    })
+    void m0(String[] args) {
+        Object o;
+        if (args[0] != null) {
+            o = "then";
+            o.hashCode();
+        } else {
+            o = "else";
+            o.hashCode();
+        }
+        o = "finish";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=10, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=21, bytecodeLength=9)
+    })
+    void m1() {
+        Object o;
+        int i = 5;
+        if (i == 5) {
+            o = "then";
+            o.hashCode();
+        } else {
+            o = "else";
+            o.hashCode();
+        }
+        o = "finish";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=10, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=21, bytecodeLength=9)
+    })
+    void m2() {
+        Object o;
+        int i = 5;
+        if (i != 5) {
+            o = "then";
+            o.hashCode();
+        } else {
+            o = "else";
+            o.hashCode();
+        }
+        o = "finish";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=11, bytecodeLength=3),
+        @DARange(varName="o", bytecodeStart=17, bytecodeLength=2)
+    })
+    Object m3(boolean cond1, boolean cond2) {
+        Object o;
+        if (cond1) {
+            if (cond2) {
+                o = "then";
+            } else {
+                o = "else";
+                return null;
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseLocalInInnerBlock.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,20 @@
+public class TestCaseLocalInInnerBlock {
+
+    @DARanges({
+        @DARange(varName="fm", bytecodeStart=23, bytecodeLength=10),
+        @DARange(varName="newWidth", bytecodeStart=2, bytecodeLength=33),
+        @DARange(varName="tc", bytecodeStart=5, bytecodeLength=30)
+    })
+    int m() {
+        int newWidth = 0;
+        String tc = "b";
+        if (tc != null) {
+            String fm;
+            if (tc.trim() != null) {
+            } else if ((fm = "b") != null) {
+                newWidth += fm.length();
+            }
+        }
+        return newWidth;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseSwitch.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,86 @@
+public class TestCaseSwitch {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=31, bytecodeLength=16),
+        @DARange(varName="o", bytecodeStart=50, bytecodeLength=15),
+        @DARange(varName="o", bytecodeStart=68, bytecodeLength=1),
+        @DARange(varName="oo", bytecodeStart=39, bytecodeLength=8),
+        @DARange(varName="uu", bytecodeStart=59, bytecodeLength=6)
+    })
+    void m1(String[] args) {
+        Object o;
+        switch (args.length) {
+            case 0:
+                    o = "0";
+                    o.hashCode();
+                    Object oo = "oo";
+                    oo.hashCode();
+                    break;
+            case 1:
+                    o = "1";
+                    o.hashCode();
+                    Object uu = "uu";
+                    uu.hashCode();
+                    break;
+        }
+        o = "return";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=35, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=46, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=78, bytecodeLength=5),
+        @DARange(varName="o", bytecodeStart=86, bytecodeLength=1),
+        @DARange(varName="oo", bytecodeStart=56, bytecodeLength=16)
+    })
+    void m3(int i) {
+        Object o;
+        switch (i) {
+            case 0:
+                    o = "0";
+                    o.hashCode();
+                    break;
+            case 1:
+                    o = "1";
+                    o.hashCode();
+                    break;
+            case 2:
+                int oo = i;
+                if (oo > 1) {
+                    System.out.println("greater");
+                }
+                break;
+            case 3:
+                int uu = i;
+            default:
+                    o = "default";
+                    o.hashCode();
+        }
+        o = "finish";
+    }
+
+    @DARanges({
+        @DARange(varName="oCache", bytecodeStart=30, bytecodeLength=6),
+        @DARange(varName="cache", bytecodeStart=41, bytecodeLength=3),
+        @DARange(varName="cache", bytecodeStart=54, bytecodeLength=2),
+        @DARange(varName="service", bytecodeStart=39, bytecodeLength=5)
+    })
+    public Object m(int i) {
+        Object cache;
+        switch (i) {
+            case 0:
+                Object oCache = null;
+                if (oCache != null) {
+                    return oCache;
+                }
+            case 1:
+                Object service = null;
+                cache = null;
+                break;
+            default:
+                throw new AssertionError("");
+            }
+        return cache;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseTry.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,55 @@
+public class TestCaseTry {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=3, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=15, bytecodeLength=1)
+    })
+    void m0(String[] args) {
+        Object o;
+        try {
+            o = "";
+            o.hashCode();
+        } catch (RuntimeException e) {}
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=3, bytecodeLength=16),
+        @DARange(varName="o", bytecodeStart=23, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=35, bytecodeLength=11)
+    })
+    void m1() {
+        Object o;
+        try {
+            o = "";
+            o.hashCode();
+        } catch (RuntimeException e) {
+        }
+        finally {
+            o = "finally";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=3, bytecodeLength=16),
+        @DARange(varName="o", bytecodeStart=23, bytecodeLength=16),
+        @DARange(varName="o", bytecodeStart=43, bytecodeLength=11)
+    })
+    void m2() {
+        Object o;
+        try {
+            o = "";
+            o.hashCode();
+        } catch (RuntimeException e) {
+            o = "catch";
+            o.hashCode();
+        }
+        finally {
+            o = "finally";
+            o.hashCode();
+        }
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseWhile.java	Wed Nov 26 17:03:13 2014 +0000
@@ -0,0 +1,15 @@
+public class TestCaseWhile {
+
+    @DARanges({
+        @DARange(varName="o", bytecodeStart=9, bytecodeLength=8),
+        @DARange(varName="o", bytecodeStart=20, bytecodeLength=1)
+    })
+    void m(String[] args) {
+        Object o;
+        while (args[0] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+}