changeset 2458:87096d22cc83

Merge
author jjg
date Sat, 27 Apr 2013 08:13:07 -0700
parents e6243e8b84de f3f3ac1273e8
children b3e962b6a660
files make/build.xml src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/Flow.java src/share/classes/com/sun/tools/javac/jvm/Code.java
diffstat 9 files changed, 801 insertions(+), 180 deletions(-) [+]
line wrap: on
line diff
--- a/make/build.xml	Thu Apr 25 17:57:04 2013 -0700
+++ b/make/build.xml	Sat Apr 27 08:13:07 2013 -0700
@@ -717,6 +717,29 @@
     <target name="sjavac" depends="build-sjavac,jtreg-sjavac,findbugs-sjavac"/>
 
     <!--
+    **** crules targets.
+    -->
+
+    <target name="build-crules" depends="-def-compilecrules,-def-build-jar-with-services">
+        <compilecrules/>
+        <build-jar-with-services
+                    name="crules"
+                    includes="crules/* crules/resources/*"
+                    classes.dir="${build.toolclasses.dir}"
+                    lib.dir="${build.toolclasses.dir}"
+                    jarmainclass=""
+                    jarclasspath="crules.jar"
+                    service.type="com.sun.source.util.Plugin"
+                    service.provider="crules.MutableFieldsAnalyzer"/>
+        <build-tool name="crules"/>
+    </target>
+
+    <target name="check-coding-rules" depends="build-bootstrap-javac,-create-import-jdk-stubs,build-crules">
+        <build-classes includes="${javac.includes}"
+            plugin.options="-J-Xbootclasspath/a:${build.toolclasses.dir}/crules.jar -Xplugin:mutable_fields_analyzer" />
+    </target>
+
+    <!--
     **** Create import JDK stubs.
     -->
 
@@ -811,6 +834,31 @@
         </macrodef>
     </target>
 
+    <target name="-def-build-jar-with-services">
+        <macrodef name="build-jar-with-services">
+            <attribute name="name"/>
+            <attribute name="includes"/>
+            <attribute name="classes.dir" default="${build.classes.dir}"/>
+            <attribute name="lib.dir" default="${dist.lib.dir}"/>
+            <attribute name="jarmainclass" default="com.sun.tools.@{name}.Main"/>
+            <attribute name="jarclasspath" default=""/>
+            <attribute name="service.type" default=""/>
+            <attribute name="service.provider" default=""/>
+            <sequential>
+                <mkdir dir="${build.toolclasses.dir}"/>
+                <jar destfile="@{lib.dir}/@{name}.jar"
+                     basedir="@{classes.dir}"
+                     includes="@{includes}">
+                    <service type="@{service.type}" provider="@{service.provider}"/>
+                    <manifest>
+                        <attribute name="Main-Class" value="@{jarmainclass}"/>
+                        <attribute name="Class-Path" value="@{jarclasspath}"/>
+                    </manifest>
+                </jar>
+            </sequential>
+        </macrodef>
+    </target>
+
     <target name="-def-build-classes" depends="-def-pcompile">
         <macrodef name="build-classes">
             <attribute name="includes"/>
@@ -826,6 +874,7 @@
             <attribute name="target" default="${javac.target}"/>
             <attribute name="release" default="${release}"/>
             <attribute name="full.version" default="${full.version}"/>
+            <attribute name="plugin.options" default=""/>
             <sequential>
                 <echo level="verbose" message="build-classes: excludes=@{excludes}"/>
                 <echo level="verbose" message="build-classes: bootclasspath.opt=@{bootclasspath.opt}"/>
@@ -868,6 +917,7 @@
                     <compilerarg line="${javac.no.jdk.warnings}"/>
                     <compilerarg line="${javac.version.opt}"/>
                     <compilerarg line="${javac.lint.opts}"/>
+                    <compilerarg line="@{plugin.options}"/>
                 </javac>
                 <copy todir="@{classes.dir}" includeemptydirs="false">
                     <fileset dir="${src.classes.dir}" includes="@{includes}" excludes="@{excludes}">
@@ -935,6 +985,32 @@
                  classpath="${build.toolclasses.dir}/"/>
     </target>
 
+    <target name="-def-compilecrules">
+        <macrodef name="compilecrules">
+            <sequential>
+                <mkdir dir="${build.toolclasses.dir}"/>
+                <javac fork="true"
+                       source="${boot.javac.source}"
+                       target="${boot.javac.target}"
+                       executable="${boot.java.home}/bin/javac"
+                       srcdir="${make.tools.dir}"
+                       includes="crules/*"
+                       destdir="${build.toolclasses.dir}/"
+                       classpath="${ant.core.lib}"
+                       bootclasspath="${boot.java.home}/jre/lib/rt.jar"
+                       includeantruntime="false">
+                    <compilerarg value="-Xbootclasspath/p:${build.bootstrap.dir}/classes"/>
+                    <compilerarg line="${javac.lint.opts}"/>
+                </javac>
+                <copy todir="${build.toolclasses.dir}/" includeemptydirs="false">
+                    <fileset dir="${make.tools.dir}">
+                        <include name="**/*.properties"/>
+                    </fileset>
+                </copy>
+            </sequential>
+        </macrodef>
+    </target>
+
     <target name="-def-genstubs" depends="build-bootstrap-javac" if="require.import.jdk.stubs">
         <mkdir dir="${build.toolclasses.dir}"/>
         <javac fork="true"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/tools/crules/AbstractCodingRulesAnalyzer.java	Sat Apr 27 08:13:07 2013 -0700
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+package crules;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.Plugin;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.api.BasicJavacTask;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+
+import static com.sun.source.util.TaskEvent.Kind;
+
+public abstract class AbstractCodingRulesAnalyzer implements Plugin {
+
+    protected Log log;
+    protected Trees trees;
+    protected TreeScanner treeVisitor;
+    protected Kind eventKind;
+    protected Messages messages;
+
+    public void init(JavacTask task, String... args) {
+        BasicJavacTask impl = (BasicJavacTask)task;
+        Context context = impl.getContext();
+        log = Log.instance(context);
+        trees = Trees.instance(task);
+        messages = new Messages();
+        task.addTaskListener(new PostAnalyzeTaskListener());
+    }
+
+    public class PostAnalyzeTaskListener implements TaskListener {
+
+        @Override
+        public void started(TaskEvent taskEvent) {}
+
+        @Override
+        public void finished(TaskEvent taskEvent) {
+            if (taskEvent.getKind().equals(eventKind)) {
+                TypeElement typeElem = taskEvent.getTypeElement();
+                Tree tree = trees.getTree(typeElem);
+                if (tree != null) {
+                    JavaFileObject prevSource = log.currentSourceFile();
+                    try {
+                        log.useSource(taskEvent.getCompilationUnit().getSourceFile());
+                        treeVisitor.scan((JCTree)tree);
+                    } finally {
+                        log.useSource(prevSource);
+                    }
+                }
+            }
+        }
+    }
+
+    class Messages {
+        ResourceBundle bundle;
+
+        Messages() {
+            String name = getClass().getPackage().getName() + ".resources.crules";
+            bundle = ResourceBundle.getBundle(name, Locale.ENGLISH);
+        }
+
+        public void error(JCTree tree, String code, Object... args) {
+            String msg = (code == null) ? (String) args[0] : localize(code, args);
+            log.error(tree, "proc.messager", msg.toString());
+        }
+
+        private String localize(String code, Object... args) {
+            String msg = bundle.getString(code);
+            if (msg == null) {
+                StringBuilder sb = new StringBuilder();
+                sb.append("message file broken: code=").append(code);
+                if (args.length > 0) {
+                    sb.append(" arguments={0}");
+                    for (int i = 1; i < args.length; i++) {
+                        sb.append(", {").append(i).append("}");
+                    }
+                }
+                msg = sb.toString();
+            }
+            return MessageFormat.format(msg, args);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/tools/crules/MutableFieldsAnalyzer.java	Sat Apr 27 08:13:07 2013 -0700
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+package crules;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.tree.TreeScanner;
+
+import static com.sun.source.util.TaskEvent.Kind;
+import static com.sun.tools.javac.code.Flags.*;
+import static com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+
+public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer {
+
+    public MutableFieldsAnalyzer() {
+        treeVisitor = new MutableFieldsVisitor();
+        eventKind = Kind.ANALYZE;
+    }
+
+    public String getName() {
+        return "mutable_fields_analyzer";
+    }
+
+    private boolean ignoreField(String className, String field) {
+        List<String> currentFieldsToIgnore =
+                classFieldsToIgnoreMap.get(className);
+        if (currentFieldsToIgnore != null) {
+            for (String fieldToIgnore : currentFieldsToIgnore) {
+                if (field.equals(fieldToIgnore)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    class MutableFieldsVisitor extends TreeScanner {
+
+        @Override
+        public void visitVarDef(JCVariableDecl tree) {
+            boolean isJavacPack = tree.sym.outermostClass().fullname.toString()
+                    .contains(packageToCheck);
+            if (isJavacPack &&
+                (tree.sym.flags() & SYNTHETIC) == 0 &&
+                tree.sym.owner.kind == Kinds.TYP) {
+                if (!ignoreField(tree.sym.owner.flatName().toString(),
+                        tree.getName().toString())) {
+                    boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
+                    boolean nonFinalStaticEnumField =
+                            (tree.sym.flags() & (ENUM | FINAL)) == 0;
+                    boolean nonFinalStaticField =
+                            (tree.sym.flags() & STATIC) != 0 &&
+                            (tree.sym.flags() & FINAL) == 0;
+                    if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) {
+                        messages.error(tree, "crules.err.var.must.be.final", tree);
+                    }
+                }
+            }
+            super.visitVarDef(tree);
+        }
+
+    }
+
+    private static final String packageToCheck = "com.sun.tools.javac";
+
+    private static final Map<String, List<String>> classFieldsToIgnoreMap =
+                new HashMap<String, List<String>>();
+
+    static {
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.JCDiagnostic",
+                    Arrays.asList("fragmentFormatter"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.JavacMessages",
+                    Arrays.asList("defaultBundle", "defaultMessages"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.file.ZipFileIndexCache",
+                    Arrays.asList("sharedInstance"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.main.JavaCompiler",
+                    Arrays.asList("versionRB"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.code.Type",
+                    Arrays.asList("moreInfo"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.SharedNameTable",
+                    Arrays.asList("freelist"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.Log",
+                    Arrays.asList("useRawMessages"));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/tools/crules/resources/crules.properties	Sat Apr 27 08:13:07 2013 -0700
@@ -0,0 +1,28 @@
+#
+# 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.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# 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.
+#
+
+# 0: symbol
+crules.err.var.must.be.final=\
+    Static variable {0} must be final
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Apr 25 17:57:04 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Sat Apr 27 08:13:07 2013 -0700
@@ -1078,7 +1078,8 @@
                 mask = MethodFlags;
             }
             // Imply STRICTFP if owner has STRICTFP set.
-            if (((flags|implicit) & Flags.ABSTRACT) == 0)
+            if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
+                ((flags) & Flags.DEFAULT) != 0)
                 implicit |= sym.owner.flags_field & STRICTFP;
             break;
         case TYP:
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Apr 25 17:57:04 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Apr 27 08:13:07 2013 -0700
@@ -35,7 +35,6 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
 import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.comp.Resolve;
 import com.sun.tools.javac.tree.JCTree.*;
 
 import static com.sun.tools.javac.code.Flags.*;
@@ -277,6 +276,15 @@
     }
 
     /**
+     * Utility method to reset several Bits instances.
+     */
+    private void resetBits(Bits... bits) {
+        for (Bits b : bits) {
+            b.reset();
+        }
+    }
+
+    /**
      * Base visitor class for all visitors implementing dataflow analysis logic.
      * This class define the shared logic for handling jumps (break/continue statements).
      */
@@ -1294,11 +1302,11 @@
 
         /** The set of definitely assigned variables.
          */
-        Bits inits;
+        final Bits inits;
 
         /** The set of definitely unassigned variables.
          */
-        Bits uninits;
+        final Bits uninits;
 
         /** The set of variables that are definitely unassigned everywhere
          *  in current try block. This variable is maintained lazily; it is
@@ -1308,15 +1316,15 @@
          *  anywhere in current try block, intersect uninitsTry and
          *  uninits.
          */
-        Bits uninitsTry;
+        final Bits uninitsTry;
 
         /** When analyzing a condition, inits and uninits are null.
          *  Instead we have:
          */
-        Bits initsWhenTrue;
-        Bits initsWhenFalse;
-        Bits uninitsWhenTrue;
-        Bits uninitsWhenFalse;
+        final Bits initsWhenTrue;
+        final Bits initsWhenFalse;
+        final Bits uninitsWhenTrue;
+        final Bits uninitsWhenFalse;
 
         /** A mapping from addresses to variable symbols.
          */
@@ -1348,15 +1356,25 @@
         /** The starting position of the analysed tree */
         int startPos;
 
+        AssignAnalyzer() {
+            inits = new Bits();
+            uninits = new Bits();
+            uninitsTry = new Bits();
+            initsWhenTrue = new Bits(true);
+            initsWhenFalse = new Bits(true);
+            uninitsWhenTrue = new Bits(true);
+            uninitsWhenFalse = new Bits(true);
+        }
+
         class AssignPendingExit extends BaseAnalyzer.PendingExit {
 
-            Bits exit_inits;
-            Bits exit_uninits;
+            final Bits exit_inits = new Bits(true);
+            final Bits exit_uninits = new Bits(true);
 
-            AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
+            AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
                 super(tree);
-                this.exit_inits = inits.dup();
-                this.exit_uninits = uninits.dup();
+                this.exit_inits.assign(inits);
+                this.exit_uninits.assign(uninits);
             }
 
             void resolveJump() {
@@ -1476,19 +1494,20 @@
         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
          */
         void split(boolean setToNull) {
-            initsWhenFalse = inits.dup();
-            uninitsWhenFalse = uninits.dup();
-            initsWhenTrue = inits;
-            uninitsWhenTrue = uninits;
-            if (setToNull)
-                inits = uninits = null;
+            initsWhenFalse.assign(inits);
+            uninitsWhenFalse.assign(uninits);
+            initsWhenTrue.assign(inits);
+            uninitsWhenTrue.assign(uninits);
+            if (setToNull) {
+                resetBits(inits, uninits);
+            }
         }
 
         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
          */
         void merge() {
-            inits = initsWhenFalse.andSet(initsWhenTrue);
-            uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
+            inits.assign(initsWhenFalse.andSet(initsWhenTrue));
+            uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
         }
 
     /* ************************************************************************
@@ -1501,7 +1520,7 @@
         void scanExpr(JCTree tree) {
             if (tree != null) {
                 scan(tree);
-                if (inits == null) merge();
+                if (inits.isReset()) merge();
             }
         }
 
@@ -1518,28 +1537,29 @@
          */
         void scanCond(JCTree tree) {
             if (tree.type.isFalse()) {
-                if (inits == null) merge();
-                initsWhenTrue = inits.dup();
+                if (inits.isReset()) merge();
+                initsWhenTrue.assign(inits);
                 initsWhenTrue.inclRange(firstadr, nextadr);
-                uninitsWhenTrue = uninits.dup();
+                uninitsWhenTrue.assign(uninits);
                 uninitsWhenTrue.inclRange(firstadr, nextadr);
-                initsWhenFalse = inits;
-                uninitsWhenFalse = uninits;
+                initsWhenFalse.assign(inits);
+                uninitsWhenFalse.assign(uninits);
             } else if (tree.type.isTrue()) {
-                if (inits == null) merge();
-                initsWhenFalse = inits.dup();
+                if (inits.isReset()) merge();
+                initsWhenFalse.assign(inits);
                 initsWhenFalse.inclRange(firstadr, nextadr);
-                uninitsWhenFalse = uninits.dup();
+                uninitsWhenFalse.assign(uninits);
                 uninitsWhenFalse.inclRange(firstadr, nextadr);
-                initsWhenTrue = inits;
-                uninitsWhenTrue = uninits;
+                initsWhenTrue.assign(inits);
+                uninitsWhenTrue.assign(uninits);
             } else {
                 scan(tree);
-                if (inits != null)
+                if (!inits.isReset())
                     split(tree.type != syms.unknownType);
             }
-            if (tree.type != syms.unknownType)
-                inits = uninits = null;
+            if (tree.type != syms.unknownType) {
+                resetBits(inits, uninits);
+            }
         }
 
         /* ------------ Visitor methods for various sorts of trees -------------*/
@@ -1619,8 +1639,8 @@
         public void visitMethodDef(JCMethodDecl tree) {
             if (tree.body == null) return;
 
-            Bits initsPrev = inits.dup();
-            Bits uninitsPrev = uninits.dup();
+            final Bits initsPrev = new Bits(inits);
+            final Bits uninitsPrev = new Bits(uninits);
             int nextadrPrev = nextadr;
             int firstadrPrev = firstadr;
             int returnadrPrev = returnadr;
@@ -1658,14 +1678,14 @@
                     exits = exits.tail;
                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
                     if (isInitialConstructor) {
-                        inits = exit.exit_inits;
+                        inits.assign(exit.exit_inits);
                         for (int i = firstadr; i < nextadr; i++)
                             checkInit(exit.tree.pos(), vars[i]);
                     }
                 }
             } finally {
-                inits = initsPrev;
-                uninits = uninitsPrev;
+                inits.assign(initsPrev);
+                uninits.assign(uninitsPrev);
                 nextadr = nextadrPrev;
                 firstadr = firstadrPrev;
                 returnadr = returnadrPrev;
@@ -1698,31 +1718,31 @@
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
-            Bits initsSkip = null;
-            Bits uninitsSkip = null;
+            final Bits initsSkip = new Bits(true);
+            final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
             do {
-                Bits uninitsEntry = uninits.dup();
+                final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
                 scanCond(tree.cond);
                 if (!flowKind.isFinal()) {
-                    initsSkip = initsWhenFalse;
-                    uninitsSkip = uninitsWhenFalse;
+                    initsSkip.assign(initsWhenFalse);
+                    uninitsSkip.assign(uninitsWhenFalse);
                 }
                 if (log.nerrors !=  prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
+                    new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
                     break;
-                inits = initsWhenTrue;
-                uninits = uninitsEntry.andSet(uninitsWhenTrue);
+                inits.assign(initsWhenTrue);
+                uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits = initsSkip;
-            uninits = uninitsSkip;
+            inits.assign(initsSkip);
+            uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
@@ -1730,34 +1750,34 @@
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
-            Bits initsSkip = null;
-            Bits uninitsSkip = null;
+            final Bits initsSkip = new Bits(true);
+            final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
-            Bits uninitsEntry = uninits.dup();
+            final Bits uninitsEntry = new Bits(uninits);
             uninitsEntry.excludeFrom(nextadr);
             do {
                 scanCond(tree.cond);
                 if (!flowKind.isFinal()) {
-                    initsSkip = initsWhenFalse;
-                    uninitsSkip = uninitsWhenFalse;
+                    initsSkip.assign(initsWhenFalse) ;
+                    uninitsSkip.assign(uninitsWhenFalse);
                 }
-                inits = initsWhenTrue;
-                uninits = uninitsWhenTrue;
+                inits.assign(initsWhenTrue);
+                uninits.assign(uninitsWhenTrue);
                 scan(tree.body);
                 resolveContinues(tree);
                 if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
-                uninits = uninitsEntry.andSet(uninits);
+                uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits = initsSkip;
-            uninits = uninitsSkip;
+            inits.assign(initsSkip);
+            uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
@@ -1767,25 +1787,25 @@
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
             scan(tree.init);
-            Bits initsSkip = null;
-            Bits uninitsSkip = null;
+            final Bits initsSkip = new Bits(true);
+            final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
             do {
-                Bits uninitsEntry = uninits.dup();
+                final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 if (tree.cond != null) {
                     scanCond(tree.cond);
                     if (!flowKind.isFinal()) {
-                        initsSkip = initsWhenFalse;
-                        uninitsSkip = uninitsWhenFalse;
+                        initsSkip.assign(initsWhenFalse);
+                        uninitsSkip.assign(uninitsWhenFalse);
                     }
-                    inits = initsWhenTrue;
-                    uninits = uninitsWhenTrue;
+                    inits.assign(initsWhenTrue);
+                    uninits.assign(uninitsWhenTrue);
                 } else if (!flowKind.isFinal()) {
-                    initsSkip = inits.dup();
+                    initsSkip.assign(inits);
                     initsSkip.inclRange(firstadr, nextadr);
-                    uninitsSkip = uninits.dup();
+                    uninitsSkip.assign(uninits);
                     uninitsSkip.inclRange(firstadr, nextadr);
                 }
                 scan(tree.body);
@@ -1793,16 +1813,16 @@
                 scan(tree.step);
                 if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
-                uninits = uninitsEntry.andSet(uninits);
+                uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits = initsSkip;
-            uninits = uninitsSkip;
+            inits.assign(initsSkip);
+            uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
@@ -1815,27 +1835,27 @@
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
             scan(tree.expr);
-            Bits initsStart = inits.dup();
-            Bits uninitsStart = uninits.dup();
+            final Bits initsStart = new Bits(inits);
+            final Bits uninitsStart = new Bits(uninits);
 
             letInit(tree.pos(), tree.var.sym);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
             do {
-                Bits uninitsEntry = uninits.dup();
+                final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
                 if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
-                uninits = uninitsEntry.andSet(uninits);
+                uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits = initsStart;
-            uninits = uninitsStart.andSet(uninits);
+            inits.assign(initsStart);
+            uninits.assign(uninitsStart.andSet(uninits));
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
@@ -1852,12 +1872,12 @@
             pendingExits = new ListBuffer<AssignPendingExit>();
             int nextadrPrev = nextadr;
             scanExpr(tree.selector);
-            Bits initsSwitch = inits;
-            Bits uninitsSwitch = uninits.dup();
+            final Bits initsSwitch = new Bits(inits);
+            final Bits uninitsSwitch = new Bits(uninits);
             boolean hasDefault = false;
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
-                inits = initsSwitch.dup();
-                uninits = uninits.andSet(uninitsSwitch);
+                inits.assign(initsSwitch);
+                uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
                 if (c.pat == null)
                     hasDefault = true;
@@ -1875,8 +1895,8 @@
         }
         // where
             /** Add any variables defined in stats to inits and uninits. */
-            private void addVars(List<JCStatement> stats, Bits inits,
-                                        Bits uninits) {
+            private void addVars(List<JCStatement> stats, final Bits inits,
+                                        final Bits uninits) {
                 for (;stats.nonEmpty(); stats = stats.tail) {
                     JCTree stat = stats.head;
                     if (stat.hasTag(VARDEF)) {
@@ -1889,11 +1909,11 @@
 
         public void visitTry(JCTry tree) {
             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
-            Bits uninitsTryPrev = uninitsTry;
+            final Bits uninitsTryPrev = new Bits(uninitsTry);
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<AssignPendingExit>();
-            Bits initsTry = inits.dup();
-            uninitsTry = uninits.dup();
+            final Bits initsTry = new Bits(inits);
+            uninitsTry.assign(uninits);
             for (JCTree resource : tree.resources) {
                 if (resource instanceof JCVariableDecl) {
                     JCVariableDecl vdecl = (JCVariableDecl) resource;
@@ -1908,8 +1928,8 @@
             }
             scan(tree.body);
             uninitsTry.andSet(uninits);
-            Bits initsEnd = inits;
-            Bits uninitsEnd = uninits;
+            final Bits initsEnd = new Bits(inits);
+            final Bits uninitsEnd = new Bits(uninits);
             int nextadrCatch = nextadr;
 
             if (!resourceVarDecls.isEmpty() &&
@@ -1925,8 +1945,8 @@
 
             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
                 JCVariableDecl param = l.head.param;
-                inits = initsTry.dup();
-                uninits = uninitsTry.dup();
+                inits.assign(initsTry);
+                uninits.assign(uninitsTry);
                 scan(param);
                 inits.incl(param.sym.adr);
                 uninits.excl(param.sym.adr);
@@ -1936,8 +1956,8 @@
                 nextadr = nextadrCatch;
             }
             if (tree.finalizer != null) {
-                inits = initsTry.dup();
-                uninits = uninitsTry.dup();
+                inits.assign(initsTry);
+                uninits.assign(uninitsTry);
                 ListBuffer<AssignPendingExit> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 scan(tree.finalizer);
@@ -1958,8 +1978,8 @@
                     inits.orSet(initsEnd);
                 }
             } else {
-                inits = initsEnd;
-                uninits = uninitsEnd;
+                inits.assign(initsEnd);
+                uninits.assign(uninitsEnd);
                 ListBuffer<AssignPendingExit> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 while (exits.nonEmpty()) pendingExits.append(exits.next());
@@ -1969,10 +1989,10 @@
 
         public void visitConditional(JCConditional tree) {
             scanCond(tree.cond);
-            Bits initsBeforeElse = initsWhenFalse;
-            Bits uninitsBeforeElse = uninitsWhenFalse;
-            inits = initsWhenTrue;
-            uninits = uninitsWhenTrue;
+            final Bits initsBeforeElse = new Bits(initsWhenFalse);
+            final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
+            inits.assign(initsWhenTrue);
+            uninits.assign(uninitsWhenTrue);
             if (tree.truepart.type.hasTag(BOOLEAN) &&
                 tree.falsepart.type.hasTag(BOOLEAN)) {
                 // if b and c are boolean valued, then
@@ -1980,12 +2000,12 @@
                 //    v is (un)assigned after b when true and
                 //    v is (un)assigned after c when true
                 scanCond(tree.truepart);
-                Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
-                Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
-                Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
-                Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
-                inits = initsBeforeElse;
-                uninits = uninitsBeforeElse;
+                final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
+                final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
+                final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
+                final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
+                inits.assign(initsBeforeElse);
+                uninits.assign(uninitsBeforeElse);
                 scanCond(tree.falsepart);
                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
@@ -1993,10 +2013,10 @@
                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
             } else {
                 scanExpr(tree.truepart);
-                Bits initsAfterThen = inits.dup();
-                Bits uninitsAfterThen = uninits.dup();
-                inits = initsBeforeElse;
-                uninits = uninitsBeforeElse;
+                final Bits initsAfterThen = new Bits(inits);
+                final Bits uninitsAfterThen = new Bits(uninits);
+                inits.assign(initsBeforeElse);
+                uninits.assign(uninitsBeforeElse);
                 scanExpr(tree.falsepart);
                 inits.andSet(initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
@@ -2005,16 +2025,16 @@
 
         public void visitIf(JCIf tree) {
             scanCond(tree.cond);
-            Bits initsBeforeElse = initsWhenFalse;
-            Bits uninitsBeforeElse = uninitsWhenFalse;
-            inits = initsWhenTrue;
-            uninits = uninitsWhenTrue;
+            final Bits initsBeforeElse = new Bits(initsWhenFalse);
+            final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
+            inits.assign(initsWhenTrue);
+            uninits.assign(uninitsWhenTrue);
             scan(tree.thenpart);
             if (tree.elsepart != null) {
-                Bits initsAfterThen = inits.dup();
-                Bits uninitsAfterThen = uninits.dup();
-                inits = initsBeforeElse;
-                uninits = uninitsBeforeElse;
+                final Bits initsAfterThen = new Bits(inits);
+                final Bits uninitsAfterThen = new Bits(uninits);
+                inits.assign(initsBeforeElse);
+                uninits.assign(uninitsBeforeElse);
                 scan(tree.elsepart);
                 inits.andSet(initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
@@ -2055,8 +2075,8 @@
 
         @Override
         public void visitLambda(JCLambda tree) {
-            Bits prevUninits = uninits;
-            Bits prevInits = inits;
+            final Bits prevUninits = new Bits(uninits);
+            final Bits prevInits = new Bits(inits);
             int returnadrPrev = returnadr;
             ListBuffer<AssignPendingExit> prevPending = pendingExits;
             try {
@@ -2076,8 +2096,8 @@
             }
             finally {
                 returnadr = returnadrPrev;
-                uninits = prevUninits;
-                inits = prevInits;
+                uninits.assign(prevUninits);
+                inits.assign(prevInits);
                 pendingExits = prevPending;
             }
         }
@@ -2088,17 +2108,17 @@
         }
 
         public void visitAssert(JCAssert tree) {
-            Bits initsExit = inits.dup();
-            Bits uninitsExit = uninits.dup();
+            final Bits initsExit = new Bits(inits);
+            final Bits uninitsExit = new Bits(uninits);
             scanCond(tree.cond);
             uninitsExit.andSet(uninitsWhenTrue);
             if (tree.detail != null) {
-                inits = initsWhenFalse;
-                uninits = uninitsWhenFalse;
+                inits.assign(initsWhenFalse);
+                uninits.assign(uninitsWhenFalse);
                 scanExpr(tree.detail);
             }
-            inits = initsExit;
-            uninits = uninitsExit;
+            inits.assign(initsExit);
+            uninits.assign(uninitsExit);
         }
 
         public void visitAssign(JCAssign tree) {
@@ -2120,12 +2140,12 @@
             switch (tree.getTag()) {
             case NOT:
                 scanCond(tree.arg);
-                Bits t = initsWhenFalse;
-                initsWhenFalse = initsWhenTrue;
-                initsWhenTrue = t;
-                t = uninitsWhenFalse;
-                uninitsWhenFalse = uninitsWhenTrue;
-                uninitsWhenTrue = t;
+                final Bits t = new Bits(initsWhenFalse);
+                initsWhenFalse.assign(initsWhenTrue);
+                initsWhenTrue.assign(t);
+                t.assign(uninitsWhenFalse);
+                uninitsWhenFalse.assign(uninitsWhenTrue);
+                uninitsWhenTrue.assign(t);
                 break;
             case PREINC: case POSTINC:
             case PREDEC: case POSTDEC:
@@ -2141,20 +2161,20 @@
             switch (tree.getTag()) {
             case AND:
                 scanCond(tree.lhs);
-                Bits initsWhenFalseLeft = initsWhenFalse;
-                Bits uninitsWhenFalseLeft = uninitsWhenFalse;
-                inits = initsWhenTrue;
-                uninits = uninitsWhenTrue;
+                final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
+                final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
+                inits.assign(initsWhenTrue);
+                uninits.assign(uninitsWhenTrue);
                 scanCond(tree.rhs);
                 initsWhenFalse.andSet(initsWhenFalseLeft);
                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
                 break;
             case OR:
                 scanCond(tree.lhs);
-                Bits initsWhenTrueLeft = initsWhenTrue;
-                Bits uninitsWhenTrueLeft = uninitsWhenTrue;
-                inits = initsWhenFalse;
-                uninits = uninitsWhenFalse;
+                final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
+                final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
+                inits.assign(initsWhenFalse);
+                uninits.assign(uninitsWhenFalse);
                 scanCond(tree.rhs);
                 initsWhenTrue.andSet(initsWhenTrueLeft);
                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
@@ -2200,11 +2220,7 @@
                 attrEnv = env;
                 Flow.this.make = make;
                 startPos = tree.pos().getStartPosition();
-                inits = new Bits();
-                uninits = new Bits();
-                uninitsTry = new Bits();
-                initsWhenTrue = initsWhenFalse =
-                    uninitsWhenTrue = uninitsWhenFalse = null;
+
                 if (vars == null)
                     vars = new VarSymbol[32];
                 else
@@ -2219,9 +2235,8 @@
             } finally {
                 // note that recursive invocations of this method fail hard
                 startPos = -1;
-                inits = uninits = uninitsTry = null;
-                initsWhenTrue = initsWhenFalse =
-                    uninitsWhenTrue = uninitsWhenFalse = null;
+                resetBits(inits, uninits, uninitsTry, initsWhenTrue,
+                        initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
                 if (vars != null) for (int i=0; i<vars.length; i++)
                     vars[i] = null;
                 firstadr = 0;
--- a/src/share/classes/com/sun/tools/javac/jvm/Code.java	Thu Apr 25 17:57:04 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Code.java	Sat Apr 27 08:13:07 2013 -0700
@@ -1656,7 +1656,7 @@
         State dup() {
             try {
                 State state = (State)super.clone();
-                state.defined = defined.dup();
+                state.defined = new Bits(defined);
                 state.stack = stack.clone();
                 if (locks != null) state.locks = locks.clone();
                 if (debugCode) {
@@ -1784,7 +1784,7 @@
         }
 
         State join(State other) {
-            defined = defined.andSet(other.defined);
+            defined.andSet(other.defined);
             Assert.check(stacksize == other.stacksize
                     && nlocks == other.nlocks);
             for (int i=0; i<stacksize; ) {
@@ -1896,7 +1896,7 @@
     /** Set the current variable defined state. */
     public void setDefined(Bits newDefined) {
         if (alive && newDefined != state.defined) {
-            Bits diff = state.defined.dup().xorSet(newDefined);
+            Bits diff = new Bits(state.defined).xorSet(newDefined);
             for (int adr = diff.nextBit(0);
                  adr >= 0;
                  adr = diff.nextBit(adr+1)) {
--- a/src/share/classes/com/sun/tools/javac/util/Bits.java	Thu Apr 25 17:57:04 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/util/Bits.java	Sat Apr 27 08:13:07 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -27,6 +27,8 @@
 
 import java.util.Arrays;
 
+import static com.sun.tools.javac.util.Bits.BitsOpKind.*;
+
 /** A class for extensible, mutable bit sets.
  *
  *  <p><b>This is NOT part of any supported API.
@@ -36,31 +38,114 @@
  */
 public class Bits {
 
+    public enum BitsOpKind {
+        INIT,
+        CLEAR,
+        INCL_BIT,
+        EXCL_BIT,
+        ASSIGN,
+        AND_SET,
+        OR_SET,
+        DIFF_SET,
+        XOR_SET,
+        INCL_RANGE,
+        EXCL_RANGE,
+    }
+
+    //       ____________      reset    _________
+    //      /  UNKNOWN   \   <-------- / UNINIT  \
+    //      \____________/       |     \_________/
+    //            |              |          |
+    //            |assign        |          | any
+    //            |        ___________      |
+    //            ------> /  NORMAL   \ <----
+    //                    \___________/     |
+    //                            |         |
+    //                            |         |
+    //                            -----------
+    //                               any
+    private enum BitsState {
+        /*  A Bits instance is in UNKNOWN state if it has been explicitly reset.
+         *  It is possible to get to this state from any other by calling the
+         *  reset method. An instance in the UNKNOWN state can pass to the
+         *  NORMAL state after being assigned another Bits instance.
+         */
+        UNKNOWN,
+        /*  A Bits instance is in UNINIT when it is created with the default
+         *  constructor but it isn't explicitly reset. The main objective of this
+         *  internal state is to save some memory.
+         */
+        UNINIT,
+        /*  The normal state is reached after creating a Bits instance from an
+         *  existing one or after applying any operation to an instance on UNINIT
+         *  or NORMAL state. From this state a bits instance can pass to the
+         *  UNKNOWN state by calling the reset method.
+         */
+        NORMAL;
+
+        static BitsState getState(int[] someBits, boolean reset) {
+            if (reset) {
+                return UNKNOWN;
+            } else {
+                if (someBits != unassignedBits) {
+                    return NORMAL;
+                } else {
+                    return UNINIT;
+                }
+            }
+        }
+
+    }
 
     private final static int wordlen = 32;
     private final static int wordshift = 5;
     private final static int wordmask = wordlen - 1;
 
-    private int[] bits;
+    public int[] bits = null;
+    // This field will store last version of bits after every change.
+    public int[] oldBits = null;
+
+    public BitsOpKind lastOperation = null;
+
+    private static final int[] unassignedBits = new int[0];
+
+    private BitsState currentState;
 
     /** Construct an initially empty set.
      */
     public Bits() {
-        this(new int[1]);
+        this(false);
+    }
+
+    public Bits(Bits someBits) {
+        this(someBits.dup().bits, BitsState.getState(someBits.bits, false));
+    }
+
+    public Bits(boolean reset) {
+        this(unassignedBits, BitsState.getState(unassignedBits, reset));
     }
 
     /** Construct a set consisting initially of given bit vector.
      */
-    public Bits(int[] bits) {
+    private Bits(int[] bits, BitsState initState) {
         this.bits = bits;
+        this.currentState = initState;
+        switch (initState) {
+            case UNKNOWN:
+                reset(); //this will also set current state;
+                break;
+            case NORMAL:
+                Assert.check(bits != unassignedBits);
+                lastOperation = INIT;
+                break;
+        }
     }
 
-    /** Construct a set consisting initially of given range.
+    /** This method will be called after any operation that causes a change to
+     *  the bits. Subclasses can thus override it in order to extract information
+     *  from the changes produced to the bits by the given operation.
      */
-    public Bits(int start, int limit) {
-        this();
-        inclRange(start, limit);
-    }
+    public void changed() {}
 
     private void sizeTo(int len) {
         if (bits.length < len) {
@@ -71,57 +156,110 @@
     /** This set = {}.
      */
     public void clear() {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = CLEAR;
         for (int i = 0; i < bits.length; i++) bits[i] = 0;
+        changed();
+        currentState = BitsState.NORMAL;
+    }
+
+    public void reset() {
+        bits = null;
+        oldBits = null;
+        currentState = BitsState.UNKNOWN;
+    }
+
+    public boolean isReset() {
+        return currentState == BitsState.UNKNOWN;
+    }
+
+    public Bits assign(Bits someBits) {
+        lastOperation = ASSIGN;
+        oldBits = bits;
+        bits = someBits.dup().bits;
+        changed();
+        currentState = BitsState.NORMAL;
+        return this;
     }
 
     /** Return a copy of this set.
      */
-    public Bits dup() {
-        int[] newbits = new int[bits.length];
-        System.arraycopy(bits, 0, newbits, 0, bits.length);
-        return new Bits(newbits);
+    private Bits dup() {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        Bits tmp = new Bits();
+        if (currentState != BitsState.NORMAL) {
+            tmp.bits = bits;
+        } else {
+            tmp.bits = new int[bits.length];
+            System.arraycopy(bits, 0, tmp.bits, 0, bits.length);
+        }
+        currentState = BitsState.NORMAL;
+        return tmp;
     }
 
     /** Include x in this set.
      */
     public void incl(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         Assert.check(x >= 0);
+        oldBits = bits;
+        lastOperation = INCL_BIT;
         sizeTo((x >>> wordshift) + 1);
         bits[x >>> wordshift] = bits[x >>> wordshift] |
             (1 << (x & wordmask));
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
 
     /** Include [start..limit) in this set.
      */
     public void inclRange(int start, int limit) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = INCL_RANGE;
         sizeTo((limit >>> wordshift) + 1);
-        for (int x = start; x < limit; x++)
+        for (int x = start; x < limit; x++) {
             bits[x >>> wordshift] = bits[x >>> wordshift] |
                 (1 << (x & wordmask));
+        }
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
     /** Exclude [start...end] from this set.
      */
     public void excludeFrom(int start) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = EXCL_RANGE;
         Bits temp = new Bits();
         temp.sizeTo(bits.length);
         temp.inclRange(0, start);
-        andSet(temp);
+        internalAndSet(temp);
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
     /** Exclude x from this set.
      */
     public void excl(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         Assert.check(x >= 0);
+        oldBits = bits;
+        lastOperation = EXCL_BIT;
         sizeTo((x >>> wordshift) + 1);
         bits[x >>> wordshift] = bits[x >>> wordshift] &
             ~(1 << (x & wordmask));
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
     /** Is x an element of this set?
      */
     public boolean isMember(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         return
             0 <= x && x < (bits.length << wordshift) &&
             (bits[x >>> wordshift] & (1 << (x & wordmask))) != 0;
@@ -130,38 +268,66 @@
     /** {@literal this set = this set & xs}.
      */
     public Bits andSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = AND_SET;
+        internalAndSet(xs);
+        changed();
+        currentState = BitsState.NORMAL;
+        return this;
+    }
+
+    private void internalAndSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         sizeTo(xs.bits.length);
-        for (int i = 0; i < xs.bits.length; i++)
+        for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] & xs.bits[i];
-        return this;
+        }
     }
 
     /** this set = this set | xs.
      */
     public Bits orSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = OR_SET;
         sizeTo(xs.bits.length);
-        for (int i = 0; i < xs.bits.length; i++)
+        for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] | xs.bits[i];
+        }
+        changed();
+        currentState = BitsState.NORMAL;
         return this;
     }
 
     /** this set = this set \ xs.
      */
     public Bits diffSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = DIFF_SET;
         for (int i = 0; i < bits.length; i++) {
             if (i < xs.bits.length) {
                 bits[i] = bits[i] & ~xs.bits[i];
             }
         }
+        changed();
+        currentState = BitsState.NORMAL;
         return this;
     }
 
     /** this set = this set ^ xs.
      */
     public Bits xorSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = XOR_SET;
         sizeTo(xs.bits.length);
-        for (int i = 0; i < xs.bits.length; i++)
+        for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] ^ xs.bits[i];
+        }
+        changed();
+        currentState = BitsState.NORMAL;
         return this;
     }
 
@@ -187,6 +353,7 @@
      *  }</pre>
      */
     public int nextBit(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         int windex = x >>> wordshift;
         if (windex >= bits.length) return -1;
         int word = bits[windex] & ~((1 << (x & wordmask))-1);
@@ -202,17 +369,20 @@
     /** a string representation of this set.
      */
     public String toString() {
-        char[] digits = new char[bits.length * wordlen];
-        for (int i = 0; i < bits.length * wordlen; i++)
-            digits[i] = isMember(i) ? '1' : '0';
-        return new String(digits);
+        if (bits.length > 0) {
+            char[] digits = new char[bits.length * wordlen];
+            for (int i = 0; i < bits.length * wordlen; i++)
+                digits[i] = isMember(i) ? '1' : '0';
+            return new String(digits);
+        } else {
+            return "[]";
+        }
     }
 
     /** Test Bits.nextBit(int). */
     public static void main(String[] args) {
         java.util.Random r = new java.util.Random();
         Bits bits = new Bits();
-        int dupCount = 0;
         for (int i=0; i<125; i++) {
             int k;
             do {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defaultMethods/CheckACC_STRICTFlagOnDefaultMethodTest.java	Sat Apr 27 08:13:07 2013 -0700
@@ -0,0 +1,96 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 8012723
+ * @summary strictfp interface misses strictfp modifer on default method
+ * @run main CheckACC_STRICTFlagOnDefaultMethodTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.io.File;
+import java.io.IOException;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Descriptor;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.Method;
+
+import static com.sun.tools.classfile.AccessFlags.ACC_STRICT;
+
+public class CheckACC_STRICTFlagOnDefaultMethodTest {
+    private static final String AssertionErrorMessage =
+        "All methods should have the ACC_STRICT access flag " +
+        "please check output";
+    private static final String offendingMethodErrorMessage =
+        "Method %s of class %s doesn't have the ACC_STRICT access flag";
+
+    private List<String> errors = new ArrayList<>();
+
+    public static void main(String[] args)
+            throws IOException, ConstantPoolException, InvalidDescriptor {
+        new CheckACC_STRICTFlagOnDefaultMethodTest().run();
+    }
+
+    private void run()
+            throws IOException, ConstantPoolException, InvalidDescriptor {
+        String testClasses = System.getProperty("test.classes");
+        check(testClasses,
+                "CheckACC_STRICTFlagOnDefaultMethodTest$StrictfpInterface.class");
+        if (errors.size() > 0) {
+            for (String error: errors) {
+                System.err.println(error);
+            }
+            throw new AssertionError(AssertionErrorMessage);
+        }
+    }
+
+    void check(String dir, String... fileNames)
+        throws
+            IOException,
+            ConstantPoolException,
+            Descriptor.InvalidDescriptor {
+        for (String fileName : fileNames) {
+            ClassFile classFileToCheck = ClassFile.read(new File(dir, fileName));
+
+            for (Method method : classFileToCheck.methods) {
+                if ((method.access_flags.flags & ACC_STRICT) == 0) {
+                    errors.add(String.format(offendingMethodErrorMessage,
+                            method.getName(classFileToCheck.constant_pool),
+                            classFileToCheck.getName()));
+                }
+            }
+        }
+    }
+
+    strictfp interface StrictfpInterface {
+        default void default_interface_method() {}
+        static void static_interface_method() {}
+    }
+
+}