changeset 2828:ee20efe0255d jdk9-b52

Merge
author lana
date Thu, 19 Feb 2015 16:38:54 -0800
parents c5561bfde449 5e500700b168
children cdef738241cd 414b82835861
files test/tools/javac/resolve/tests/PrimitiveBinopOverload.java
diffstat 28 files changed, 1501 insertions(+), 1144 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Feb 19 16:38:54 2015 -0800
@@ -200,9 +200,6 @@
      */
     public final VarSymbol lengthVar;
 
-    /** The null check operator. */
-    public final OperatorSymbol nullcheck;
-
     /** The symbol representing the final finalize method on enums */
     public final MethodSymbol enumFinalFinalize;
 
@@ -217,10 +214,6 @@
      */
     public final Name[] boxedName = new Name[TypeTag.getTypeTagCount()];
 
-    /** A set containing all operator names.
-     */
-    public final Set<Name> operatorNames = new HashSet<>();
-
     /** A hashtable containing the encountered top-level and member classes,
      *  indexed by flat names. The table does not contain local classes.
      *  It should be updated from the outside to reflect classes defined
@@ -255,85 +248,6 @@
      */
     public final ClassSymbol predefClass;
 
-    /** Enter a constant into symbol table.
-     *  @param name   The constant's name.
-     *  @param type   The constant's type.
-     */
-    private VarSymbol enterConstant(String name, Type type) {
-        VarSymbol c = new VarSymbol(
-            PUBLIC | STATIC | FINAL,
-            names.fromString(name),
-            type,
-            predefClass);
-        c.setData(type.constValue());
-        predefClass.members().enter(c);
-        return c;
-    }
-
-    /** Enter a binary operation into symbol table.
-     *  @param name     The name of the operator.
-     *  @param left     The type of the left operand.
-     *  @param right    The type of the left operand.
-     *  @param res      The operation's result type.
-     *  @param opcode   The operation's bytecode instruction.
-     */
-    private void enterBinop(String name,
-                            Type left, Type right, Type res,
-                            int opcode) {
-        predefClass.members().enter(
-            new OperatorSymbol(
-                makeOperatorName(name),
-                new MethodType(List.of(left, right), res,
-                               List.<Type>nil(), methodClass),
-                opcode,
-                predefClass));
-    }
-
-    /** Enter a binary operation, as above but with two opcodes,
-     *  which get encoded as
-     *  {@code (opcode1 << ByteCodeTags.preShift) + opcode2 }.
-     *  @param opcode1     First opcode.
-     *  @param opcode2     Second opcode.
-     */
-    private void enterBinop(String name,
-                            Type left, Type right, Type res,
-                            int opcode1, int opcode2) {
-        enterBinop(
-            name, left, right, res, (opcode1 << ByteCodes.preShift) | opcode2);
-    }
-
-    /** Enter a unary operation into symbol table.
-     *  @param name     The name of the operator.
-     *  @param arg      The type of the operand.
-     *  @param res      The operation's result type.
-     *  @param opcode   The operation's bytecode instruction.
-     */
-    private OperatorSymbol enterUnop(String name,
-                                     Type arg,
-                                     Type res,
-                                     int opcode) {
-        OperatorSymbol sym =
-            new OperatorSymbol(makeOperatorName(name),
-                               new MethodType(List.of(arg),
-                                              res,
-                                              List.<Type>nil(),
-                                              methodClass),
-                               opcode,
-                               predefClass);
-        predefClass.members().enter(sym);
-        return sym;
-    }
-
-    /**
-     * Create a new operator name from corresponding String representation
-     * and add the name to the set of known operator names.
-     */
-    private Name makeOperatorName(String name) {
-        Name opName = names.fromString(name);
-        operatorNames.add(opName);
-        return opName;
-    }
-
     /** Enter a class into symbol table.
      *  @param s The name of the class.
      */
@@ -591,163 +505,6 @@
                            List.<Type>nil(), methodClass),
             arrayClass);
         arrayClass.members().enter(arrayCloneMethod);
-
-        // Enter operators.
-        /*  Internally we use +++, --- for unary +, - to reduce +, - operators
-         *  overloading
-         */
-        enterUnop("+++", doubleType, doubleType, nop);
-        enterUnop("+++", floatType, floatType, nop);
-        enterUnop("+++", longType, longType, nop);
-        enterUnop("+++", intType, intType, nop);
-
-        enterUnop("---", doubleType, doubleType, dneg);
-        enterUnop("---", floatType, floatType, fneg);
-        enterUnop("---", longType, longType, lneg);
-        enterUnop("---", intType, intType, ineg);
-
-        enterUnop("~", longType, longType, lxor);
-        enterUnop("~", intType, intType, ixor);
-
-        enterUnop("++", doubleType, doubleType, dadd);
-        enterUnop("++", floatType, floatType, fadd);
-        enterUnop("++", longType, longType, ladd);
-        enterUnop("++", intType, intType, iadd);
-        enterUnop("++", charType, charType, iadd);
-        enterUnop("++", shortType, shortType, iadd);
-        enterUnop("++", byteType, byteType, iadd);
-
-        enterUnop("--", doubleType, doubleType, dsub);
-        enterUnop("--", floatType, floatType, fsub);
-        enterUnop("--", longType, longType, lsub);
-        enterUnop("--", intType, intType, isub);
-        enterUnop("--", charType, charType, isub);
-        enterUnop("--", shortType, shortType, isub);
-        enterUnop("--", byteType, byteType, isub);
-
-        enterUnop("!", booleanType, booleanType, bool_not);
-        nullcheck = enterUnop("<*nullchk*>", objectType, objectType, nullchk);
-
-        // string concatenation
-        enterBinop("+", stringType, objectType, stringType, string_add);
-        enterBinop("+", objectType, stringType, stringType, string_add);
-        enterBinop("+", stringType, stringType, stringType, string_add);
-        enterBinop("+", stringType, intType, stringType, string_add);
-        enterBinop("+", stringType, longType, stringType, string_add);
-        enterBinop("+", stringType, floatType, stringType, string_add);
-        enterBinop("+", stringType, doubleType, stringType, string_add);
-        enterBinop("+", stringType, booleanType, stringType, string_add);
-        enterBinop("+", stringType, botType, stringType, string_add);
-        enterBinop("+", intType, stringType, stringType, string_add);
-        enterBinop("+", longType, stringType, stringType, string_add);
-        enterBinop("+", floatType, stringType, stringType, string_add);
-        enterBinop("+", doubleType, stringType, stringType, string_add);
-        enterBinop("+", booleanType, stringType, stringType, string_add);
-        enterBinop("+", botType, stringType, stringType, string_add);
-
-        // these errors would otherwise be matched as string concatenation
-        enterBinop("+", botType, botType, botType, error);
-        enterBinop("+", botType, intType, botType, error);
-        enterBinop("+", botType, longType, botType, error);
-        enterBinop("+", botType, floatType, botType, error);
-        enterBinop("+", botType, doubleType, botType, error);
-        enterBinop("+", botType, booleanType, botType, error);
-        enterBinop("+", botType, objectType, botType, error);
-        enterBinop("+", intType, botType, botType, error);
-        enterBinop("+", longType, botType, botType, error);
-        enterBinop("+", floatType, botType, botType, error);
-        enterBinop("+", doubleType, botType, botType, error);
-        enterBinop("+", booleanType, botType, botType, error);
-        enterBinop("+", objectType, botType, botType, error);
-
-        enterBinop("+", doubleType, doubleType, doubleType, dadd);
-        enterBinop("+", floatType, floatType, floatType, fadd);
-        enterBinop("+", longType, longType, longType, ladd);
-        enterBinop("+", intType, intType, intType, iadd);
-
-        enterBinop("-", doubleType, doubleType, doubleType, dsub);
-        enterBinop("-", floatType, floatType, floatType, fsub);
-        enterBinop("-", longType, longType, longType, lsub);
-        enterBinop("-", intType, intType, intType, isub);
-
-        enterBinop("*", doubleType, doubleType, doubleType, dmul);
-        enterBinop("*", floatType, floatType, floatType, fmul);
-        enterBinop("*", longType, longType, longType, lmul);
-        enterBinop("*", intType, intType, intType, imul);
-
-        enterBinop("/", doubleType, doubleType, doubleType, ddiv);
-        enterBinop("/", floatType, floatType, floatType, fdiv);
-        enterBinop("/", longType, longType, longType, ldiv);
-        enterBinop("/", intType, intType, intType, idiv);
-
-        enterBinop("%", doubleType, doubleType, doubleType, dmod);
-        enterBinop("%", floatType, floatType, floatType, fmod);
-        enterBinop("%", longType, longType, longType, lmod);
-        enterBinop("%", intType, intType, intType, imod);
-
-        enterBinop("&", booleanType, booleanType, booleanType, iand);
-        enterBinop("&", longType, longType, longType, land);
-        enterBinop("&", intType, intType, intType, iand);
-
-        enterBinop("|", booleanType, booleanType, booleanType, ior);
-        enterBinop("|", longType, longType, longType, lor);
-        enterBinop("|", intType, intType, intType, ior);
-
-        enterBinop("^", booleanType, booleanType, booleanType, ixor);
-        enterBinop("^", longType, longType, longType, lxor);
-        enterBinop("^", intType, intType, intType, ixor);
-
-        enterBinop("<<", longType, longType, longType, lshll);
-        enterBinop("<<", intType, longType, intType, ishll);
-        enterBinop("<<", longType, intType, longType, lshl);
-        enterBinop("<<", intType, intType, intType, ishl);
-
-        enterBinop(">>", longType, longType, longType, lshrl);
-        enterBinop(">>", intType, longType, intType, ishrl);
-        enterBinop(">>", longType, intType, longType, lshr);
-        enterBinop(">>", intType, intType, intType, ishr);
-
-        enterBinop(">>>", longType, longType, longType, lushrl);
-        enterBinop(">>>", intType, longType, intType, iushrl);
-        enterBinop(">>>", longType, intType, longType, lushr);
-        enterBinop(">>>", intType, intType, intType, iushr);
-
-        enterBinop("<", doubleType, doubleType, booleanType, dcmpg, iflt);
-        enterBinop("<", floatType, floatType, booleanType, fcmpg, iflt);
-        enterBinop("<", longType, longType, booleanType, lcmp, iflt);
-        enterBinop("<", intType, intType, booleanType, if_icmplt);
-
-        enterBinop(">", doubleType, doubleType, booleanType, dcmpl, ifgt);
-        enterBinop(">", floatType, floatType, booleanType, fcmpl, ifgt);
-        enterBinop(">", longType, longType, booleanType, lcmp, ifgt);
-        enterBinop(">", intType, intType, booleanType, if_icmpgt);
-
-        enterBinop("<=", doubleType, doubleType, booleanType, dcmpg, ifle);
-        enterBinop("<=", floatType, floatType, booleanType, fcmpg, ifle);
-        enterBinop("<=", longType, longType, booleanType, lcmp, ifle);
-        enterBinop("<=", intType, intType, booleanType, if_icmple);
-
-        enterBinop(">=", doubleType, doubleType, booleanType, dcmpl, ifge);
-        enterBinop(">=", floatType, floatType, booleanType, fcmpl, ifge);
-        enterBinop(">=", longType, longType, booleanType, lcmp, ifge);
-        enterBinop(">=", intType, intType, booleanType, if_icmpge);
-
-        enterBinop("==", objectType, objectType, booleanType, if_acmpeq);
-        enterBinop("==", booleanType, booleanType, booleanType, if_icmpeq);
-        enterBinop("==", doubleType, doubleType, booleanType, dcmpl, ifeq);
-        enterBinop("==", floatType, floatType, booleanType, fcmpl, ifeq);
-        enterBinop("==", longType, longType, booleanType, lcmp, ifeq);
-        enterBinop("==", intType, intType, booleanType, if_icmpeq);
-
-        enterBinop("!=", objectType, objectType, booleanType, if_acmpne);
-        enterBinop("!=", booleanType, booleanType, booleanType, if_icmpne);
-        enterBinop("!=", doubleType, doubleType, booleanType, dcmpl, ifne);
-        enterBinop("!=", floatType, floatType, booleanType, fcmpl, ifne);
-        enterBinop("!=", longType, longType, booleanType, lcmp, ifne);
-        enterBinop("!=", intType, intType, booleanType, if_icmpne);
-
-        enterBinop("&&", booleanType, booleanType, booleanType, bool_and);
-        enterBinop("||", booleanType, booleanType, booleanType, bool_or);
     }
 
     /** Define a new class given its name and owner.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Thu Feb 19 16:38:54 2015 -0800
@@ -1445,26 +1445,6 @@
     }
     // </editor-fold>
 
-    /**
-     * Can t and s be compared for equality?  Any primitive ==
-     * primitive or primitive == object comparisons here are an error.
-     * Unboxing and correct primitive == primitive comparisons are
-     * already dealt with in Attr.visitBinary.
-     *
-     */
-    public boolean isEqualityComparable(Type s, Type t, Warner warn) {
-        if (t.isNumeric() && s.isNumeric())
-            return true;
-
-        boolean tPrimitive = t.isPrimitive();
-        boolean sPrimitive = s.isPrimitive();
-        if (!tPrimitive && !sPrimitive) {
-            return isCastable(s, t, warn) || isCastable(t, s, warn);
-        } else {
-            return false;
-        }
-    }
-
     // <editor-fold defaultstate="collapsed" desc="isCastable">
     public boolean isCastable(Type t, Type s) {
         return isCastable(t, s, noWarnings);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Feb 19 16:38:54 2015 -0800
@@ -82,6 +82,7 @@
     final Log log;
     final Symtab syms;
     final Resolve rs;
+    final Operators operators;
     final Infer infer;
     final Analyzer analyzer;
     final DeferredAttr deferredAttr;
@@ -115,6 +116,7 @@
         log = Log.instance(context);
         syms = Symtab.instance(context);
         rs = Resolve.instance(context);
+        operators = Operators.instance(context);
         chk = Check.instance(context);
         flow = Flow.instance(context);
         memberEnter = MemberEnter.instance(context);
@@ -1467,7 +1469,7 @@
          *  @param thentype The type of the expression's then-part.
          *  @param elsetype The type of the expression's else-part.
          */
-        private Type condType(DiagnosticPosition pos,
+        Type condType(DiagnosticPosition pos,
                                Type thentype, Type elsetype) {
             // If same type, that is the result
             if (types.isSameType(thentype, elsetype))
@@ -2142,7 +2144,7 @@
 
         JCTree.Tag optag = NULLCHK;
         JCUnary tree = make.at(arg.pos).Unary(optag, arg);
-        tree.operator = syms.nullcheck;
+        tree.operator = operators.resolveUnary(arg, optag, arg.type);
         tree.type = arg.type;
         return tree;
     }
@@ -2903,18 +2905,10 @@
         Type owntype = attribTree(tree.lhs, env, varAssignmentInfo);
         Type operand = attribExpr(tree.rhs, env);
         // Find operator.
-        Symbol operator = tree.operator = rs.resolveBinaryOperator(
-            tree.pos(), tree.getTag().noAssignOp(), env,
-            owntype, operand);
-
+        Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), owntype, operand);
         if (operator.kind == MTH &&
                 !owntype.isErroneous() &&
                 !operand.isErroneous()) {
-            chk.checkOperator(tree.pos(),
-                              (OperatorSymbol)operator,
-                              tree.getTag().noAssignOp(),
-                              owntype,
-                              operand);
             chk.checkDivZero(tree.rhs.pos(), operator, operand);
             chk.checkCastable(tree.rhs.pos(),
                               operator.type.getReturnType(),
@@ -2930,9 +2924,7 @@
             : chk.checkNonVoid(tree.arg.pos(), attribExpr(tree.arg, env));
 
         // Find operator.
-        Symbol operator = tree.operator =
-            rs.resolveUnaryOperator(tree.pos(), tree.getTag(), env, argtype);
-
+        Symbol operator = tree.operator = operators.resolveUnary(tree, tree.getTag(), argtype);
         Type owntype = types.createErrorType(tree.type);
         if (operator.kind == MTH &&
                 !argtype.isErroneous()) {
@@ -2957,22 +2949,13 @@
         Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env));
         Type right = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.rhs, env));
         // Find operator.
-        Symbol operator = tree.operator =
-            rs.resolveBinaryOperator(tree.pos(), tree.getTag(), env, left, right);
-
+        Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
         Type owntype = types.createErrorType(tree.type);
         if (operator.kind == MTH &&
                 !left.isErroneous() &&
                 !right.isErroneous()) {
             owntype = operator.type.getReturnType();
-            // This will figure out when unboxing can happen and
-            // choose the right comparison operator.
-            int opc = chk.checkOperator(tree.lhs.pos(),
-                                        (OperatorSymbol)operator,
-                                        tree.getTag(),
-                                        left,
-                                        right);
-
+            int opc = ((OperatorSymbol)operator).opcode;
             // If both arguments are constants, fold them.
             if (left.constValue() != null && right.constValue() != null) {
                 Type ctype = cfolder.fold2(opc, left, right);
@@ -2985,8 +2968,7 @@
             // castable to each other, (JLS 15.21).  Note: unboxing
             // comparisons will not have an acmp* opc at this point.
             if ((opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne)) {
-                if (!types.isEqualityComparable(left, right,
-                                                new Warner(tree.pos()))) {
+                if (!types.isCastable(left, right, new Warner(tree.pos()))) {
                     log.error(tree.pos(), "incomparable.types", left, right);
                 }
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Feb 19 16:38:54 2015 -0800
@@ -83,7 +83,6 @@
     private boolean warnOnSyntheticConflicts;
     private boolean suppressAbortOnBadClassFile;
     private boolean enableSunApiLintControl;
-    private final TreeInfo treeinfo;
     private final JavaFileManager fileManager;
     private final Profile profile;
     private final boolean warnOnAccessToSensitiveMembers;
@@ -121,7 +120,6 @@
         diags = JCDiagnostic.Factory.instance(context);
         Options options = Options.instance(context);
         lint = Lint.instance(context);
-        treeinfo = TreeInfo.instance(context);
         fileManager = context.get(JavaFileManager.class);
 
         Source source = Source.instance(context);
@@ -3265,30 +3263,6 @@
  **************************************************************************/
 
     /**
-     * Return the opcode of the operator but emit an error if it is an
-     * error.
-     * @param pos        position for error reporting.
-     * @param operator   an operator
-     * @param tag        a tree tag
-     * @param left       type of left hand side
-     * @param right      type of right hand side
-     */
-    int checkOperator(DiagnosticPosition pos,
-                       OperatorSymbol operator,
-                       JCTree.Tag tag,
-                       Type left,
-                       Type right) {
-        if (operator.opcode == ByteCodes.error) {
-            log.error(pos,
-                      "operator.cant.be.applied.1",
-                      treeinfo.operatorName(tag),
-                      left, right);
-        }
-        return operator.opcode;
-    }
-
-
-    /**
      *  Check for division by integer constant zero
      *  @param pos           Position for error reporting.
      *  @param operator      The operator for the expression
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu Feb 19 16:38:54 2015 -0800
@@ -1386,7 +1386,7 @@
                 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                     return rec == null ?
                         rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
-                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
+                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired());
                 }
                 @Override
                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Feb 19 16:38:54 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, 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
@@ -353,17 +353,17 @@
                 this.tree = tree;
             }
 
-            void resolveJump(JCTree tree) {
+            void resolveJump() {
                 //do nothing
             }
         }
 
-        abstract void markDead(JCTree tree);
+        abstract void markDead();
 
         /** Record an outward transfer of control. */
-        void recordExit(JCTree tree, P pe) {
+        void recordExit(P pe) {
             pendingExits.append(pe);
-            markDead(tree);
+            markDead();
         }
 
         /** Resolve all jumps of this statement. */
@@ -377,7 +377,7 @@
                 P exit = exits.head;
                 if (exit.tree.hasTag(jk.treeTag) &&
                         jk.getTarget(exit.tree) == tree) {
-                    exit.resolveJump(tree);
+                    exit.resolveJump();
                     resolved = true;
                 } else {
                     pendingExits.append(exit);
@@ -424,7 +424,7 @@
         private boolean alive;
 
         @Override
-        void markDead(JCTree tree) {
+        void markDead() {
             alive = false;
         }
 
@@ -692,21 +692,21 @@
         }
 
         public void visitBreak(JCBreak tree) {
-            recordExit(tree, new PendingExit(tree));
+            recordExit(new PendingExit(tree));
         }
 
         public void visitContinue(JCContinue tree) {
-            recordExit(tree, new PendingExit(tree));
+            recordExit(new PendingExit(tree));
         }
 
         public void visitReturn(JCReturn tree) {
             scan(tree.expr);
-            recordExit(tree, new PendingExit(tree));
+            recordExit(new PendingExit(tree));
         }
 
         public void visitThrow(JCThrow tree) {
             scan(tree.expr);
-            markDead(tree);
+            markDead();
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -803,7 +803,7 @@
         }
 
         @Override
-        void markDead(JCTree tree) {
+        void markDead() {
             //do nothing
         }
 
@@ -1201,16 +1201,16 @@
             }
 
         public void visitBreak(JCBreak tree) {
-            recordExit(tree, new FlowPendingExit(tree, null));
+            recordExit(new FlowPendingExit(tree, null));
         }
 
         public void visitContinue(JCContinue tree) {
-            recordExit(tree, new FlowPendingExit(tree, null));
+            recordExit(new FlowPendingExit(tree, null));
         }
 
         public void visitReturn(JCReturn tree) {
             scan(tree.expr);
-            recordExit(tree, new FlowPendingExit(tree, null));
+            recordExit(new FlowPendingExit(tree, null));
         }
 
         public void visitThrow(JCThrow tree) {
@@ -1228,7 +1228,7 @@
             else {
                 markThrown(tree, tree.expr.type);
             }
-            markDead(tree);
+            markDead();
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -1375,12 +1375,11 @@
      * effectively-final local variables/parameters.
      */
 
-    public abstract class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer<P>.AbstractAssignPendingExit>
-        extends BaseAnalyzer<P> {
+    public class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
 
         /** The set of definitely assigned variables.
          */
-        protected Bits inits;
+        final Bits inits;
 
         /** The set of definitely unassigned variables.
          */
@@ -1428,20 +1427,20 @@
          */
         WriteableScope unrefdResources;
 
-        /** Set when processing a loop body the second time for DU analysis. */
+        /** Modified when processing a loop body the second time for DU analysis. */
         FlowKind flowKind = FlowKind.NORMAL;
 
-        /** The starting position of the analysed tree */
+        /** The starting position of the analyzed tree */
         int startPos;
 
-        public class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
+        public class AssignPendingExit extends BaseAnalyzer.PendingExit {
 
             final Bits inits;
             final Bits uninits;
             final Bits exit_inits = new Bits(true);
             final Bits exit_uninits = new Bits(true);
 
-            public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
                 super(tree);
                 this.inits = inits;
                 this.uninits = uninits;
@@ -1450,13 +1449,13 @@
             }
 
             @Override
-            public void resolveJump(JCTree tree) {
+            public void resolveJump() {
                 inits.andSet(exit_inits);
                 uninits.andSet(exit_uninits);
             }
         }
 
-        public AbstractAssignAnalyzer() {
+        public AssignAnalyzer() {
             this.inits = new Bits();
             uninits = new Bits();
             uninitsTry = new Bits();
@@ -1469,7 +1468,7 @@
         private boolean isInitialConstructor = false;
 
         @Override
-        protected void markDead(JCTree tree) {
+        protected void markDead() {
             if (!isInitialConstructor) {
                 inits.inclRange(returnadr, nextadr);
             } else {
@@ -1516,35 +1515,43 @@
             }
             sym.adr = nextadr;
             vardecls[nextadr] = varDecl;
-            exclVarFromInits(varDecl, nextadr);
+            inits.excl(nextadr);
             uninits.incl(nextadr);
             nextadr++;
         }
 
-        protected void exclVarFromInits(JCTree tree, int adr) {
-            inits.excl(adr);
-        }
-
-        protected void assignToInits(JCTree tree, Bits bits) {
-            inits.assign(bits);
-        }
-
-        protected void andSetInits(JCTree tree, Bits bits) {
-            inits.andSet(bits);
-        }
-
-        protected void orSetInits(JCTree tree, Bits bits) {
-            inits.orSet(bits);
-        }
-
         /** Record an initialization of a trackable variable.
          */
         void letInit(DiagnosticPosition pos, VarSymbol sym) {
             if (sym.adr >= firstadr && trackable(sym)) {
-                if (uninits.isMember(sym.adr)) {
-                    uninit(sym);
+                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
+                    if (!uninits.isMember(sym.adr)) {
+                        //assignment targeting an effectively final variable
+                        //makes the variable lose its status of effectively final
+                        //if the variable is _not_ definitively unassigned
+                        sym.flags_field &= ~EFFECTIVELY_FINAL;
+                    } else {
+                        uninit(sym);
+                    }
+                }
+                else if ((sym.flags() & FINAL) != 0) {
+                    if ((sym.flags() & PARAMETER) != 0) {
+                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
+                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
+                        }
+                        else {
+                            log.error(pos, "final.parameter.may.not.be.assigned",
+                                  sym);
+                        }
+                    } else if (!uninits.isMember(sym.adr)) {
+                        log.error(pos, flowKind.errKey, sym);
+                    } else {
+                        uninit(sym);
+                    }
                 }
                 inits.incl(sym.adr);
+            } else if ((sym.flags() & FINAL) != 0) {
+                log.error(pos, "var.might.already.be.assigned", sym);
             }
         }
         //where
@@ -1579,7 +1586,14 @@
             checkInit(pos, sym, "var.might.not.have.been.initialized");
         }
 
-        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
+            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
+                trackable(sym) &&
+                !inits.isMember(sym.adr)) {
+                log.error(pos, errkey, sym);
+                inits.incl(sym.adr);
+            }
+        }
 
         /** Utility method to reset several Bits instances.
          */
@@ -1603,7 +1617,7 @@
 
         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
          */
-        protected void merge(JCTree tree) {
+        protected void merge() {
             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
         }
@@ -1619,7 +1633,7 @@
             if (tree != null) {
                 scan(tree);
                 if (inits.isReset()) {
-                    merge(tree);
+                    merge();
                 }
             }
         }
@@ -1637,7 +1651,7 @@
          */
         void scanCond(JCTree tree) {
             if (tree.type.isFalse()) {
-                if (inits.isReset()) merge(tree);
+                if (inits.isReset()) merge();
                 initsWhenTrue.assign(inits);
                 initsWhenTrue.inclRange(firstadr, nextadr);
                 uninitsWhenTrue.assign(uninits);
@@ -1645,7 +1659,7 @@
                 initsWhenFalse.assign(inits);
                 uninitsWhenFalse.assign(uninits);
             } else if (tree.type.isTrue()) {
-                if (inits.isReset()) merge(tree);
+                if (inits.isReset()) merge();
                 initsWhenFalse.assign(inits);
                 initsWhenFalse.inclRange(firstadr, nextadr);
                 uninitsWhenFalse.assign(uninits);
@@ -1664,173 +1678,203 @@
 
         /* ------------ Visitor methods for various sorts of trees -------------*/
 
-        @Override
         public void visitClassDef(JCClassDecl tree) {
             if (tree.sym == null) {
                 return;
             }
 
-            JCClassDecl classDefPrev = classDef;
-            int firstadrPrev = firstadr;
-            int nextadrPrev = nextadr;
-            ListBuffer<P> pendingExitsPrev = pendingExits;
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try {
+                if (tree.sym == null) {
+                    return;
+                }
 
-            pendingExits = new ListBuffer<>();
-            if (tree.name != names.empty) {
-                firstadr = nextadr;
-            }
-            classDef = tree;
-            try {
-                // define all the static fields
-                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
-                    if (l.head.hasTag(VARDEF)) {
-                        JCVariableDecl def = (JCVariableDecl)l.head;
-                        if ((def.mods.flags & STATIC) != 0) {
-                            VarSymbol sym = def.sym;
-                            if (trackable(sym)) {
-                                newVar(def);
+                JCClassDecl classDefPrev = classDef;
+                int firstadrPrev = firstadr;
+                int nextadrPrev = nextadr;
+                ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
+
+                pendingExits = new ListBuffer<>();
+                if (tree.name != names.empty) {
+                    firstadr = nextadr;
+                }
+                classDef = tree;
+                try {
+                    // define all the static fields
+                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+                        if (l.head.hasTag(VARDEF)) {
+                            JCVariableDecl def = (JCVariableDecl)l.head;
+                            if ((def.mods.flags & STATIC) != 0) {
+                                VarSymbol sym = def.sym;
+                                if (trackable(sym)) {
+                                    newVar(def);
+                                }
                             }
                         }
                     }
-                }
 
-                // process all the static initializers
-                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
-                    if (!l.head.hasTag(METHODDEF) &&
-                        (TreeInfo.flags(l.head) & STATIC) != 0) {
-                        scan(l.head);
+                    // process all the static initializers
+                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+                        if (!l.head.hasTag(METHODDEF) &&
+                            (TreeInfo.flags(l.head) & STATIC) != 0) {
+                            scan(l.head);
+                        }
                     }
-                }
 
-                // define all the instance fields
-                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
-                    if (l.head.hasTag(VARDEF)) {
-                        JCVariableDecl def = (JCVariableDecl)l.head;
-                        if ((def.mods.flags & STATIC) == 0) {
-                            VarSymbol sym = def.sym;
-                            if (trackable(sym)) {
-                                newVar(def);
+                    // define all the instance fields
+                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+                        if (l.head.hasTag(VARDEF)) {
+                            JCVariableDecl def = (JCVariableDecl)l.head;
+                            if ((def.mods.flags & STATIC) == 0) {
+                                VarSymbol sym = def.sym;
+                                if (trackable(sym)) {
+                                    newVar(def);
+                                }
                             }
                         }
                     }
-                }
 
-                // process all the instance initializers
-                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
-                    if (!l.head.hasTag(METHODDEF) &&
-                        (TreeInfo.flags(l.head) & STATIC) == 0) {
-                        scan(l.head);
+                    // process all the instance initializers
+                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+                        if (!l.head.hasTag(METHODDEF) &&
+                            (TreeInfo.flags(l.head) & STATIC) == 0) {
+                            scan(l.head);
+                        }
                     }
-                }
 
-                // process all the methods
-                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
-                    if (l.head.hasTag(METHODDEF)) {
-                        scan(l.head);
+                    // process all the methods
+                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+                        if (l.head.hasTag(METHODDEF)) {
+                            scan(l.head);
+                        }
                     }
+                } finally {
+                    pendingExits = pendingExitsPrev;
+                    nextadr = nextadrPrev;
+                    firstadr = firstadrPrev;
+                    classDef = classDefPrev;
                 }
             } finally {
-                pendingExits = pendingExitsPrev;
-                nextadr = nextadrPrev;
-                firstadr = firstadrPrev;
-                classDef = classDefPrev;
+                lint = lintPrev;
             }
         }
 
-        @Override
         public void visitMethodDef(JCMethodDecl tree) {
             if (tree.body == null) {
                 return;
             }
-            /*  Ignore synthetic methods, except for translated lambda methods.
+
+            /*  MemberEnter can generate synthetic methods ignore them
              */
-            if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
+            if ((tree.sym.flags() & SYNTHETIC) != 0) {
                 return;
             }
 
-            final Bits initsPrev = new Bits(inits);
-            final Bits uninitsPrev = new Bits(uninits);
-            int nextadrPrev = nextadr;
-            int firstadrPrev = firstadr;
-            int returnadrPrev = returnadr;
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try {
+                if (tree.body == null) {
+                    return;
+                }
+                /*  Ignore synthetic methods, except for translated lambda methods.
+                 */
+                if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
+                    return;
+                }
 
-            Assert.check(pendingExits.isEmpty());
-            boolean lastInitialConstructor = isInitialConstructor;
-            try {
-                isInitialConstructor = TreeInfo.isInitialConstructor(tree);
+                final Bits initsPrev = new Bits(inits);
+                final Bits uninitsPrev = new Bits(uninits);
+                int nextadrPrev = nextadr;
+                int firstadrPrev = firstadr;
+                int returnadrPrev = returnadr;
 
-                if (!isInitialConstructor) {
-                    firstadr = nextadr;
-                }
-                for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
-                    JCVariableDecl def = l.head;
-                    scan(def);
-                    Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
-                    /*  If we are executing the code from Gen, then there can be
-                     *  synthetic or mandated variables, ignore them.
-                     */
-                    initParam(def);
-                }
-                // else we are in an instance initializer block;
-                // leave caught unchanged.
-                scan(tree.body);
+                Assert.check(pendingExits.isEmpty());
+                boolean lastInitialConstructor = isInitialConstructor;
+                try {
+                    isInitialConstructor = TreeInfo.isInitialConstructor(tree);
 
-                if (isInitialConstructor) {
-                    boolean isSynthesized = (tree.sym.flags() &
-                                             GENERATEDCONSTR) != 0;
-                    for (int i = firstadr; i < nextadr; i++) {
-                        JCVariableDecl vardecl = vardecls[i];
-                        VarSymbol var = vardecl.sym;
-                        if (var.owner == classDef.sym) {
-                            // choose the diagnostic position based on whether
-                            // the ctor is default(synthesized) or not
-                            if (isSynthesized) {
-                                checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
-                                    var, "var.not.initialized.in.default.constructor");
-                            } else {
-                                checkInit(TreeInfo.diagEndPos(tree.body), var);
+                    if (!isInitialConstructor) {
+                        firstadr = nextadr;
+                    }
+                    for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
+                        JCVariableDecl def = l.head;
+                        scan(def);
+                        Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
+                        /*  If we are executing the code from Gen, then there can be
+                         *  synthetic or mandated variables, ignore them.
+                         */
+                        initParam(def);
+                    }
+                    // else we are in an instance initializer block;
+                    // leave caught unchanged.
+                    scan(tree.body);
+
+                    if (isInitialConstructor) {
+                        boolean isSynthesized = (tree.sym.flags() &
+                                                 GENERATEDCONSTR) != 0;
+                        for (int i = firstadr; i < nextadr; i++) {
+                            JCVariableDecl vardecl = vardecls[i];
+                            VarSymbol var = vardecl.sym;
+                            if (var.owner == classDef.sym) {
+                                // choose the diagnostic position based on whether
+                                // the ctor is default(synthesized) or not
+                                if (isSynthesized) {
+                                    checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
+                                        var, "var.not.initialized.in.default.constructor");
+                                } else {
+                                    checkInit(TreeInfo.diagEndPos(tree.body), var);
+                                }
                             }
                         }
                     }
-                }
-                List<P> exits = pendingExits.toList();
-                pendingExits = new ListBuffer<>();
-                while (exits.nonEmpty()) {
-                    P exit = exits.head;
-                    exits = exits.tail;
-                    Assert.check(exit.tree.hasTag(RETURN), exit.tree);
-                    if (isInitialConstructor) {
-                        assignToInits(exit.tree, exit.exit_inits);
-                        for (int i = firstadr; i < nextadr; i++) {
-                            checkInit(exit.tree.pos(), vardecls[i].sym);
+                    List<AssignPendingExit> exits = pendingExits.toList();
+                    pendingExits = new ListBuffer<>();
+                    while (exits.nonEmpty()) {
+                        AssignPendingExit exit = exits.head;
+                        exits = exits.tail;
+                        Assert.check(exit.tree.hasTag(RETURN), exit.tree);
+                        if (isInitialConstructor) {
+                            inits.assign(exit.exit_inits);
+                            for (int i = firstadr; i < nextadr; i++) {
+                                checkInit(exit.tree.pos(), vardecls[i].sym);
+                            }
                         }
                     }
+                } finally {
+                    inits.assign(initsPrev);
+                    uninits.assign(uninitsPrev);
+                    nextadr = nextadrPrev;
+                    firstadr = firstadrPrev;
+                    returnadr = returnadrPrev;
+                    isInitialConstructor = lastInitialConstructor;
                 }
             } finally {
-                assignToInits(tree, initsPrev);
-                uninits.assign(uninitsPrev);
-                nextadr = nextadrPrev;
-                firstadr = firstadrPrev;
-                returnadr = returnadrPrev;
-                isInitialConstructor = lastInitialConstructor;
+                lint = lintPrev;
             }
         }
 
         protected void initParam(JCVariableDecl def) {
             inits.incl(def.sym.adr);
             uninits.excl(def.sym.adr);
-            }
+        }
 
         public void visitVarDef(JCVariableDecl tree) {
-            boolean track = trackable(tree.sym);
-            if (track && tree.sym.owner.kind == MTH) {
-                newVar(tree);
-            }
-            if (tree.init != null) {
-                scanExpr(tree.init);
-                if (track) {
-                    letInit(tree.pos(), tree.sym);
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try{
+                boolean track = trackable(tree.sym);
+                if (track && tree.sym.owner.kind == MTH) {
+                    newVar(tree);
                 }
+                if (tree.init != null) {
+                    scanExpr(tree.init);
+                    if (track) {
+                        letInit(tree.pos(), tree.sym);
+                    }
+                }
+            } finally {
+                lint = lintPrev;
             }
         }
 
@@ -1840,18 +1884,14 @@
             nextadr = nextadrPrev;
         }
 
-        int getLogNumberOfErrors() {
-            return 0;
-        }
-
         public void visitDoLoop(JCDoWhileLoop tree) {
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<>();
-            int prevErrors = getLogNumberOfErrors();
+            int prevErrors = log.nerrors;
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
@@ -1862,28 +1902,28 @@
                     initsSkip.assign(initsWhenFalse);
                     uninitsSkip.assign(uninitsWhenFalse);
                 }
-                if (getLogNumberOfErrors() !=  prevErrors ||
+                if (log.nerrors !=  prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
                     break;
-                assignToInits(tree.cond, initsWhenTrue);
+                inits.assign(initsWhenTrue);
                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            assignToInits(tree, initsSkip);
+            inits.assign(initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitWhileLoop(JCWhileLoop tree) {
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<>();
-            int prevErrors = getLogNumberOfErrors();
+            int prevErrors = log.nerrors;
             final Bits uninitsEntry = new Bits(uninits);
             uninitsEntry.excludeFrom(nextadr);
             do {
@@ -1892,11 +1932,11 @@
                     initsSkip.assign(initsWhenFalse) ;
                     uninitsSkip.assign(uninitsWhenFalse);
                 }
-                assignToInits(tree, initsWhenTrue);
+                inits.assign(initsWhenTrue);
                 uninits.assign(uninitsWhenTrue);
                 scan(tree.body);
                 resolveContinues(tree);
-                if (getLogNumberOfErrors() != prevErrors ||
+                if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
                     break;
@@ -1907,13 +1947,13 @@
             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
-            assignToInits(tree.body, initsSkip);
+            inits.assign(initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitForLoop(JCForLoop tree) {
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
@@ -1921,7 +1961,7 @@
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<>();
-            int prevErrors = getLogNumberOfErrors();
+            int prevErrors = log.nerrors;
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
@@ -1931,7 +1971,7 @@
                         initsSkip.assign(initsWhenFalse);
                         uninitsSkip.assign(uninitsWhenFalse);
                     }
-                    assignToInits(tree.body, initsWhenTrue);
+                    inits.assign(initsWhenTrue);
                     uninits.assign(uninitsWhenTrue);
                 } else if (!flowKind.isFinal()) {
                     initsSkip.assign(inits);
@@ -1942,7 +1982,7 @@
                 scan(tree.body);
                 resolveContinues(tree);
                 scan(tree.step);
-                if (getLogNumberOfErrors() != prevErrors ||
+                if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
@@ -1952,7 +1992,7 @@
             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
-            assignToInits(tree.body, initsSkip);
+            inits.assign(initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
@@ -1961,7 +2001,7 @@
         public void visitForeachLoop(JCEnhancedForLoop tree) {
             visitVarDef(tree.var);
 
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
@@ -1971,13 +2011,13 @@
 
             letInit(tree.pos(), tree.var.sym);
             pendingExits = new ListBuffer<>();
-            int prevErrors = getLogNumberOfErrors();
+            int prevErrors = log.nerrors;
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
-                if (getLogNumberOfErrors() != prevErrors ||
+                if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
@@ -1985,21 +2025,21 @@
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            assignToInits(tree.body, initsStart);
+            inits.assign(initsStart);
             uninits.assign(uninitsStart.andSet(uninits));
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
 
         public void visitLabelled(JCLabeledStatement tree) {
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<>();
             scan(tree.body);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitSwitch(JCSwitch tree) {
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<>();
             int nextadrPrev = nextadr;
             scanExpr(tree.selector);
@@ -2007,7 +2047,7 @@
             final Bits uninitsSwitch = new Bits(uninits);
             boolean hasDefault = false;
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
-                assignToInits(l.head, initsSwitch);
+                inits.assign(initsSwitch);
                 uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
                 if (c.pat == null) {
@@ -2016,19 +2056,19 @@
                     scanExpr(c.pat);
                 }
                 if (hasDefault) {
-                    assignToInits(null, initsSwitch);
+                    inits.assign(initsSwitch);
                     uninits.assign(uninits.andSet(uninitsSwitch));
                 }
                 scan(c.stats);
                 addVars(c.stats, initsSwitch, uninitsSwitch);
                 if (!hasDefault) {
-                    assignToInits(l.head.stats.last(), initsSwitch);
+                    inits.assign(initsSwitch);
                     uninits.assign(uninits.andSet(uninitsSwitch));
                 }
                 // Warn about fall-through if lint switch fallthrough enabled.
             }
             if (!hasDefault) {
-                andSetInits(null, initsSwitch);
+                inits.andSet(initsSwitch);
             }
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
@@ -2047,16 +2087,10 @@
                 }
             }
 
-        boolean isEnabled(Lint.LintCategory lc) {
-            return false;
-        }
-
-        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
-
         public void visitTry(JCTry tree) {
             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
             final Bits uninitsTryPrev = new Bits(uninitsTry);
-            ListBuffer<P> prevPendingExits = pendingExits;
+            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<>();
             final Bits initsTry = new Bits(inits);
             uninitsTry.assign(uninits);
@@ -2079,10 +2113,10 @@
             int nextadrCatch = nextadr;
 
             if (!resourceVarDecls.isEmpty() &&
-                    isEnabled(Lint.LintCategory.TRY)) {
+                    lint.isEnabled(Lint.LintCategory.TRY)) {
                 for (JCVariableDecl resVar : resourceVarDecls) {
                     if (unrefdResources.includes(resVar.sym)) {
-                        reportWarning(Lint.LintCategory.TRY, resVar.pos(),
+                        log.warning(Lint.LintCategory.TRY, resVar.pos(),
                                     "try.resource.not.referenced", resVar.sym);
                         unrefdResources.remove(resVar.sym);
                     }
@@ -2098,7 +2132,7 @@
 
             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
                 JCVariableDecl param = l.head.param;
-                assignToInits(tree.body, initsCatchPrev);
+                inits.assign(initsCatchPrev);
                 uninits.assign(uninitsCatchPrev);
                 scan(param);
                 /* If this is a TWR and we are executing the code from Gen,
@@ -2111,9 +2145,9 @@
                 nextadr = nextadrCatch;
             }
             if (tree.finalizer != null) {
-                assignToInits(tree.finalizer, initsTry);
+                inits.assign(initsTry);
                 uninits.assign(uninitsTry);
-                ListBuffer<P> exits = pendingExits;
+                ListBuffer<AssignPendingExit> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 scan(tree.finalizer);
                 if (!tree.finallyCanCompleteNormally) {
@@ -2123,19 +2157,19 @@
                     // FIX: this doesn't preserve source order of exits in catch
                     // versus finally!
                     while (exits.nonEmpty()) {
-                        P exit = exits.next();
+                        AssignPendingExit exit = exits.next();
                         if (exit.exit_inits != null) {
                             exit.exit_inits.orSet(inits);
                             exit.exit_uninits.andSet(uninits);
                         }
                         pendingExits.append(exit);
                     }
-                    orSetInits(tree, initsEnd);
+                    inits.orSet(initsEnd);
                 }
             } else {
-                assignToInits(tree, initsEnd);
+                inits.assign(initsEnd);
                 uninits.assign(uninitsEnd);
-                ListBuffer<P> exits = pendingExits;
+                ListBuffer<AssignPendingExit> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 while (exits.nonEmpty()) pendingExits.append(exits.next());
             }
@@ -2146,7 +2180,7 @@
             scanCond(tree.cond);
             final Bits initsBeforeElse = new Bits(initsWhenFalse);
             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
-            assignToInits(tree.cond, initsWhenTrue);
+            inits.assign(initsWhenTrue);
             uninits.assign(uninitsWhenTrue);
             if (tree.truepart.type.hasTag(BOOLEAN) &&
                 tree.falsepart.type.hasTag(BOOLEAN)) {
@@ -2159,7 +2193,7 @@
                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
-                assignToInits(tree.truepart, initsBeforeElse);
+                inits.assign(initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scanCond(tree.falsepart);
                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
@@ -2170,10 +2204,10 @@
                 scanExpr(tree.truepart);
                 final Bits initsAfterThen = new Bits(inits);
                 final Bits uninitsAfterThen = new Bits(uninits);
-                assignToInits(tree.truepart, initsBeforeElse);
+                inits.assign(initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scanExpr(tree.falsepart);
-                andSetInits(tree.falsepart, initsAfterThen);
+                inits.andSet(initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
             }
         }
@@ -2182,46 +2216,42 @@
             scanCond(tree.cond);
             final Bits initsBeforeElse = new Bits(initsWhenFalse);
             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
-            assignToInits(tree.cond, initsWhenTrue);
+            inits.assign(initsWhenTrue);
             uninits.assign(uninitsWhenTrue);
             scan(tree.thenpart);
             if (tree.elsepart != null) {
                 final Bits initsAfterThen = new Bits(inits);
                 final Bits uninitsAfterThen = new Bits(uninits);
-                assignToInits(tree.thenpart, initsBeforeElse);
+                inits.assign(initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scan(tree.elsepart);
-                andSetInits(tree.elsepart, initsAfterThen);
+                inits.andSet(initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
             } else {
-                andSetInits(tree.thenpart, initsBeforeElse);
+                inits.andSet(initsBeforeElse);
                 uninits.andSet(uninitsBeforeElse);
             }
         }
 
-        protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
-            return null;
-        }
-
         @Override
         public void visitBreak(JCBreak tree) {
-            recordExit(tree, createNewPendingExit(tree, inits, uninits));
+            recordExit(new AssignPendingExit(tree, inits, uninits));
         }
 
         @Override
         public void visitContinue(JCContinue tree) {
-            recordExit(tree, createNewPendingExit(tree, inits, uninits));
+            recordExit(new AssignPendingExit(tree, inits, uninits));
         }
 
         @Override
         public void visitReturn(JCReturn tree) {
             scanExpr(tree.expr);
-            recordExit(tree, createNewPendingExit(tree, inits, uninits));
+            recordExit(new AssignPendingExit(tree, inits, uninits));
         }
 
         public void visitThrow(JCThrow tree) {
             scanExpr(tree.expr);
-            markDead(tree.expr);
+            markDead();
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -2240,7 +2270,7 @@
             final Bits prevUninits = new Bits(uninits);
             final Bits prevInits = new Bits(inits);
             int returnadrPrev = returnadr;
-            ListBuffer<P> prevPending = pendingExits;
+            ListBuffer<AssignPendingExit> prevPending = pendingExits;
             try {
                 returnadr = nextadr;
                 pendingExits = new ListBuffer<>();
@@ -2259,7 +2289,7 @@
             finally {
                 returnadr = returnadrPrev;
                 uninits.assign(prevUninits);
-                assignToInits(tree, prevInits);
+                inits.assign(prevInits);
                 pendingExits = prevPending;
             }
         }
@@ -2275,11 +2305,11 @@
             scanCond(tree.cond);
             uninitsExit.andSet(uninitsWhenTrue);
             if (tree.detail != null) {
-                assignToInits(tree, initsWhenFalse);
+                inits.assign(initsWhenFalse);
                 uninits.assign(uninitsWhenFalse);
                 scanExpr(tree.detail);
             }
-            assignToInits(tree, initsExit);
+            inits.assign(initsExit);
             uninits.assign(uninitsExit);
         }
 
@@ -2308,8 +2338,7 @@
             if (enforceThisDotInit &&
                 tree.selected.hasTag(IDENT) &&
                 ((JCIdent)tree.selected).name == names._this &&
-                tree.sym.kind == VAR)
-            {
+                tree.sym.kind == VAR) {
                 checkInit(tree.pos(), (VarSymbol)tree.sym);
             }
         }
@@ -2347,7 +2376,7 @@
                 scanCond(tree.lhs);
                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
-                assignToInits(tree.lhs, initsWhenTrue);
+                inits.assign(initsWhenTrue);
                 uninits.assign(uninitsWhenTrue);
                 scanCond(tree.rhs);
                 initsWhenFalse.andSet(initsWhenFalseLeft);
@@ -2357,7 +2386,7 @@
                 scanCond(tree.lhs);
                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
-                assignToInits(tree.lhs, initsWhenFalse);
+                inits.assign(initsWhenFalse);
                 uninits.assign(uninitsWhenFalse);
                 scanCond(tree.rhs);
                 initsWhenTrue.andSet(initsWhenTrueLeft);
@@ -2428,136 +2457,6 @@
         }
     }
 
-    public class AssignAnalyzer extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
-
-        public class AssignPendingExit extends AbstractAssignAnalyzer<AssignPendingExit>.AbstractAssignPendingExit {
-
-            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
-                super(tree, inits, uninits);
-            }
-        }
-
-        @Override
-        protected AssignPendingExit createNewPendingExit(JCTree tree,
-            Bits inits, Bits uninits) {
-            return new AssignPendingExit(tree, inits, uninits);
-        }
-
-        /** Record an initialization of a trackable variable.
-         */
-        @Override
-        void letInit(DiagnosticPosition pos, VarSymbol sym) {
-            if (sym.adr >= firstadr && trackable(sym)) {
-                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
-                    if (!uninits.isMember(sym.adr)) {
-                        //assignment targeting an effectively final variable
-                        //makes the variable lose its status of effectively final
-                        //if the variable is _not_ definitively unassigned
-                        sym.flags_field &= ~EFFECTIVELY_FINAL;
-                    } else {
-                        uninit(sym);
-                    }
-                }
-                else if ((sym.flags() & FINAL) != 0) {
-                    if ((sym.flags() & PARAMETER) != 0) {
-                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
-                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
-                        }
-                        else {
-                            log.error(pos, "final.parameter.may.not.be.assigned",
-                                  sym);
-                        }
-                    } else if (!uninits.isMember(sym.adr)) {
-                        log.error(pos, flowKind.errKey, sym);
-                    } else {
-                        uninit(sym);
-                    }
-                }
-                inits.incl(sym.adr);
-            } else if ((sym.flags() & FINAL) != 0) {
-                log.error(pos, "var.might.already.be.assigned", sym);
-            }
-        }
-
-        @Override
-        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
-            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
-                trackable(sym) &&
-                !inits.isMember(sym.adr)) {
-                log.error(pos, errkey, sym);
-                inits.incl(sym.adr);
-            }
-        }
-
-        @Override
-        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
-            String key, Object ... args) {
-            log.warning(lc, pos, key, args);
-        }
-
-        @Override
-        int getLogNumberOfErrors() {
-            return log.nerrors;
-        }
-
-        @Override
-        boolean isEnabled(Lint.LintCategory lc) {
-            return lint.isEnabled(lc);
-        }
-
-        @Override
-        public void visitClassDef(JCClassDecl tree) {
-            if (tree.sym == null) {
-                return;
-            }
-
-            Lint lintPrev = lint;
-            lint = lint.augment(tree.sym);
-            try {
-                super.visitClassDef(tree);
-            } finally {
-                lint = lintPrev;
-            }
-        }
-
-        @Override
-        public void visitMethodDef(JCMethodDecl tree) {
-            if (tree.body == null) {
-                return;
-            }
-
-            /*  MemberEnter can generate synthetic methods ignore them
-             */
-            if ((tree.sym.flags() & SYNTHETIC) != 0) {
-                return;
-            }
-
-            Lint lintPrev = lint;
-            lint = lint.augment(tree.sym);
-            try {
-                super.visitMethodDef(tree);
-            } finally {
-                lint = lintPrev;
-            }
-        }
-
-        @Override
-        public void visitVarDef(JCVariableDecl tree) {
-            if (tree.init == null) {
-                super.visitVarDef(tree);
-            } else {
-                Lint lintPrev = lint;
-                lint = lint.augment(tree.sym);
-                try{
-                    super.visitVarDef(tree);
-                } finally {
-                    lint = lintPrev;
-                }
-            }
-        }
-
-    }
-
     /**
      * This pass implements the last step of the dataflow analysis, namely
      * the effectively-final analysis check. This checks that every local variable
@@ -2572,7 +2471,7 @@
         JCTree currentTree; //local class or lambda
 
         @Override
-        void markDead(JCTree tree) {
+        void markDead() {
             //do nothing
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Feb 19 16:38:54 2015 -0800
@@ -80,6 +80,7 @@
     private Names names;
     private Symtab syms;
     private Resolve rs;
+    private Operators operators;
     private TreeMaker make;
     private Types types;
     private TransTypes transTypes;
@@ -130,6 +131,7 @@
         names = Names.instance(context);
         syms = Symtab.instance(context);
         rs = Resolve.instance(context);
+        operators = Operators.instance(context);
         make = TreeMaker.instance(context);
         types = Types.instance(context);
         transTypes = TransTypes.instance(context);
@@ -654,7 +656,7 @@
 
     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
-        testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
+        testExpr.operator = operators.resolveBinary(testExpr, JCTree.Tag.EQ, argType, argType);
         testExpr.setType(syms.booleanType);
         return testExpr;
     }
@@ -668,7 +670,7 @@
                 List.<JCExpression>of(make.Literal(lit)));
         eqtest.setType(syms.booleanType);
         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
-        compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
+        compound.operator = operators.resolveBinary(compound, JCTree.Tag.AND, syms.booleanType, syms.booleanType);
         compound.setType(syms.booleanType);
         return compound;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Feb 19 16:38:54 2015 -0800
@@ -74,6 +74,7 @@
     private final Log log;
     private final Symtab syms;
     private final Resolve rs;
+    private final Operators operators;
     private final Check chk;
     private final Attr attr;
     private TreeMaker make;
@@ -95,6 +96,7 @@
         log = Log.instance(context);
         syms = Symtab.instance(context);
         rs = Resolve.instance(context);
+        operators = Operators.instance(context);
         chk = Check.instance(context);
         attr = Attr.instance(context);
         make = TreeMaker.instance(context);
@@ -575,8 +577,7 @@
      */
     JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) {
         JCUnary tree = make.Unary(optag, arg);
-        tree.operator = rs.resolveUnaryOperator(
-            make_pos, optag, attrEnv, arg.type);
+        tree.operator = operators.resolveUnary(tree, optag, arg.type);
         tree.type = tree.operator.type.getReturnType();
         return tree;
     }
@@ -588,8 +589,7 @@
      */
     JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
         JCBinary tree = make.Binary(optag, lhs, rhs);
-        tree.operator = rs.resolveBinaryOperator(
-            make_pos, optag, attrEnv, lhs.type, rhs.type);
+        tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
         tree.type = tree.operator.type.getReturnType();
         return tree;
     }
@@ -601,8 +601,7 @@
      */
     JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
         JCAssignOp tree = make.Assignop(optag, lhs, rhs);
-        tree.operator = rs.resolveBinaryOperator(
-            make_pos, tree.getTag().noAssignOp(), attrEnv, lhs.type, rhs.type);
+        tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), lhs.type, rhs.type);
         tree.type = lhs.type;
         return tree;
     }
@@ -2644,7 +2643,6 @@
 
             MethodSymbol m = tree.sym;
             tree.params = tree.params.prepend(ordParam).prepend(nameParam);
-            incrementParamTypeAnnoIndexes(m, 2);
 
             m.extraParams = m.extraParams.prepend(ordParam.sym);
             m.extraParams = m.extraParams.prepend(nameParam.sym);
@@ -2667,17 +2665,6 @@
             currentMethodSym = prevMethodSym;
         }
     }
-    //where
-    private void incrementParamTypeAnnoIndexes(MethodSymbol m,
-                                               int amount) {
-        for (final Attribute.TypeCompound anno : m.getRawTypeAttributes()) {
-            // Increment the parameter_index of any existing formal
-            // parameter annotations.
-            if (anno.position.type == TargetType.METHOD_FORMAL_PARAMETER) {
-                anno.position.parameter_index += amount;
-            }
-        }
-    }
 
     private void visitMethodDefInternal(JCMethodDecl tree) {
         if (tree.name == names.init &&
@@ -2711,7 +2698,6 @@
             tree.params = tree.params.appendList(fvdefs);
             if (currentClass.hasOuterInstance()) {
                 tree.params = tree.params.prepend(otdef);
-                incrementParamTypeAnnoIndexes(m, 1);
             }
 
             // If this is an initial constructor, i.e., it does not start with
@@ -3206,9 +3192,8 @@
                         // tree.lhs.  However, we can still get the
                         // unerased type of tree.lhs as it is stored
                         // in tree.type in Attr.
-                        Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
+                        Symbol newOperator = operators.resolveBinary(tree,
                                                                       newTag,
-                                                                      attrEnv,
                                                                       tree.type,
                                                                       tree.rhs.type);
                         JCExpression expr = (JCExpression)lhs;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Thu Feb 19 16:38:54 2015 -0800
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.OperatorSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.TypeTag;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.jvm.ByteCodes;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import static com.sun.tools.javac.jvm.ByteCodes.*;
+import static com.sun.tools.javac.comp.Operators.OperatorType.*;
+
+/**
+ * This class contains the logic for unary and binary operator resolution/lookup.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class Operators {
+    protected static final Context.Key<Operators> operatorsKey = new Context.Key<>();
+
+    private final Names names;
+    private final Log log;
+    private final Symtab syms;
+    private final Types types;
+
+    /** Unary operators map. */
+    private Map<Name, List<UnaryOperatorHelper>> unaryOperators = new HashMap<>(Tag.getNumberOfOperators());
+
+    /** Binary operators map. */
+    private Map<Name, List<BinaryOperatorHelper>> binaryOperators = new HashMap<>(Tag.getNumberOfOperators());
+
+    /** The names of all operators. */
+    private Name[] opname = new Name[Tag.getNumberOfOperators()];
+
+    public static Operators instance(Context context) {
+        Operators instance = context.get(operatorsKey);
+        if (instance == null)
+            instance = new Operators(context);
+        return instance;
+    }
+
+    protected Operators(Context context) {
+        context.put(operatorsKey, this);
+        syms = Symtab.instance(context);
+        names = Names.instance(context);
+        log = Log.instance(context);
+        types = Types.instance(context);
+        initOperatorNames();
+        initUnaryOperators();
+        initBinaryOperators();
+    }
+
+    /**
+     * Perform unary promotion of a type; this routine implements JLS 5.6.1.
+     * If the input type is not supported by unary promotion, it is returned unaltered.
+     */
+    Type unaryPromotion(Type t) {
+        Type unboxed = types.unboxedTypeOrType(t);
+        switch (unboxed.getTag()) {
+            case BYTE:
+            case SHORT:
+            case CHAR:
+                return syms.intType;
+            default:
+                return unboxed;
+        }
+    }
+
+    /**
+     * Perform binary promotion of a pair of types; this routine implements JLS 5.6.2.
+     * If the input types are not supported by unary promotion, if such types are identical to
+     * a type C, then C is returned, otherwise Object is returned.
+     */
+    Type binaryPromotion(Type t1, Type t2) {
+        Type unboxedT1 = types.unboxedTypeOrType(t1);
+        Type unboxedT2 = types.unboxedTypeOrType(t2);
+
+        if (unboxedT1.isNumeric() && unboxedT2.isNumeric()) {
+            if (unboxedT1.hasTag(TypeTag.DOUBLE) || unboxedT2.hasTag(TypeTag.DOUBLE)) {
+                return syms.doubleType;
+            } else if (unboxedT1.hasTag(TypeTag.FLOAT) || unboxedT2.hasTag(TypeTag.FLOAT)) {
+                return syms.floatType;
+            } else if (unboxedT1.hasTag(TypeTag.LONG) || unboxedT2.hasTag(TypeTag.LONG)) {
+                return syms.longType;
+            } else {
+                return syms.intType;
+            }
+        } else if (types.isSameType(unboxedT1, unboxedT2)) {
+            return unboxedT1;
+        } else {
+            return syms.objectType;
+        }
+    }
+
+    /**
+     * Entry point for resolving a unary operator given an operator tag and an argument type.
+     */
+    Symbol resolveUnary(DiagnosticPosition pos, JCTree.Tag tag, Type op) {
+        return resolve(tag,
+                unaryOperators,
+                unop -> unop.test(op),
+                unop -> unop.resolve(op),
+                () -> reportErrorIfNeeded(pos, tag, op));
+    }
+
+    /**
+     * Entry point for resolving a binary operator given an operator tag and a pair of argument types.
+     */
+    Symbol resolveBinary(DiagnosticPosition pos, JCTree.Tag tag, Type op1, Type op2) {
+        return resolve(tag,
+                binaryOperators,
+                binop -> binop.test(op1, op2),
+                binop -> binop.resolve(op1, op2),
+                () -> reportErrorIfNeeded(pos, tag, op1, op2));
+    }
+
+    /**
+     * Main operator lookup routine; lookup an operator (either unary or binary) in its corresponding
+     * map. If there's a matching operator, its resolve routine is called and the result is returned;
+     * otherwise the result of a fallback function is returned.
+     */
+    private <O> Symbol resolve(Tag tag, Map<Name, List<O>> opMap, Predicate<O> opTestFunc,
+                       Function<O, Symbol> resolveFunc, Supplier<Symbol> noResultFunc) {
+        return opMap.get(operatorName(tag)).stream()
+                .filter(opTestFunc)
+                .map(resolveFunc)
+                .findFirst()
+                .orElseGet(noResultFunc);
+    }
+
+    /**
+     * Creates an operator symbol.
+     */
+    private Symbol makeOperator(Name name, List<OperatorType> formals, OperatorType res, int... opcodes) {
+        MethodType opType = new MethodType(
+                formals.stream()
+                        .map(o -> o.asType(syms))
+                        .collect(List.collector()),
+                res.asType(syms), List.nil(), syms.methodClass);
+        return new OperatorSymbol(name, opType, mergeOpcodes(opcodes), syms.noSymbol);
+    }
+
+    /**
+     * Fold two opcodes in a single int value (if required).
+     */
+    private int mergeOpcodes(int... opcodes) {
+        int opcodesLen = opcodes.length;
+        Assert.check(opcodesLen == 1 || opcodesLen == 2);
+        return (opcodesLen == 1) ?
+                opcodes[0] :
+                ((opcodes[0] << ByteCodes.preShift) | opcodes[1]);
+    }
+
+    /**
+     * Report an operator lookup error.
+     */
+    private Symbol reportErrorIfNeeded(DiagnosticPosition pos, Tag tag, Type... args) {
+        if (Stream.of(args).noneMatch(Type::isErroneous)) {
+            Name opName = operatorName(tag);
+            JCDiagnostic.Error opError = (args.length) == 1 ?
+                    Errors.OperatorCantBeApplied(opName, args[0]) :
+                    Errors.OperatorCantBeApplied1(opName, args[0], args[1]);
+            log.error(pos, opError);
+        }
+        return syms.noSymbol;
+    }
+
+    /**
+     * Return name of operator with given tree tag.
+     */
+    public Name operatorName(JCTree.Tag tag) {
+        return opname[tag.operatorIndex()];
+    }
+
+    /**
+     * The constants in this enum represent the types upon which all the operator helpers
+     * operate upon. This allows lazy and consise mapping between a type name and a type instance.
+     */
+    enum OperatorType {
+        BYTE(syms -> syms.byteType),
+        SHORT(syms -> syms.shortType),
+        INT(syms -> syms.intType),
+        LONG(syms -> syms.longType),
+        FLOAT(syms -> syms.floatType),
+        DOUBLE(syms -> syms.doubleType),
+        CHAR(syms -> syms.charType),
+        BOOLEAN(syms -> syms.booleanType),
+        OBJECT(syms -> syms.objectType),
+        STRING(syms -> syms.stringType),
+        BOT(syms -> syms.botType);
+
+        final Function<Symtab, Type> asTypeFunc;
+
+        OperatorType(Function<Symtab, Type> asTypeFunc) {
+            this.asTypeFunc = asTypeFunc;
+        }
+
+        Type asType(Symtab syms) {
+            return asTypeFunc.apply(syms);
+        }
+    }
+
+    /**
+     * Common root for all operator helpers. An operator helper instance is associated with a
+     * given operator (i.e. '+'); it contains routines to perform operator lookup, i.e. find
+     * which version of the '+' operator is the best given an argument type list. Supported
+     * operator symbols are initialized lazily upon first lookup request - this is in order to avoid
+     * initialization circularities between this class and {@code Symtab}.
+     */
+    abstract class OperatorHelper {
+
+        /** The operator name. */
+        final Name name;
+
+        /** The list of symbols associated with this operator (lazily populated). */
+        Optional<Symbol[]> alternatives = Optional.empty();
+
+        /** An array of operator symbol suppliers (used to lazily populate the symbol list). */
+        List<Supplier<Symbol>> operatorSuppliers = List.nil();
+
+        @SuppressWarnings("varargs")
+        OperatorHelper(Tag tag) {
+            this.name = operatorName(tag);
+        }
+
+        /**
+         * This routine implements the main operator lookup process. Each operator is tested
+         * using an applicability predicate; if the test suceeds that same operator is returned,
+         * otherwise a dummy symbol is returned.
+         */
+        final Symbol doLookup(Predicate<Symbol> applicabilityTest) {
+            return Stream.of(alternatives.orElseGet(this::initOperators))
+                    .filter(applicabilityTest)
+                    .findFirst()
+                    .orElse(syms.noSymbol);
+        }
+
+        /**
+         * This routine performs lazy instantiation of the operator symbols supported by this helper.
+         * After initialization is done, the suppliers are cleared, to free up memory.
+         */
+        private Symbol[] initOperators() {
+            Symbol[] operators = operatorSuppliers.stream()
+                    .map(op -> op.get())
+                    .toArray(Symbol[]::new);
+            alternatives = Optional.of(operators);
+            operatorSuppliers = null; //let GC do its work
+            return operators;
+        }
+    }
+
+    /**
+     * Common superclass for all unary operator helpers.
+     */
+    abstract class UnaryOperatorHelper extends OperatorHelper implements Predicate<Type> {
+
+        UnaryOperatorHelper(Tag tag) {
+            super(tag);
+        }
+
+        /**
+         * This routine implements the unary operator lookup process. It customizes the behavior
+         * of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test
+         * (see {@link UnaryOperatorHelper#isUnaryOperatorApplicable(OperatorSymbol, Type)}
+         */
+        final Symbol doLookup(Type t) {
+            return doLookup(op -> isUnaryOperatorApplicable((OperatorSymbol)op, t));
+        }
+
+        /**
+         * Unary operator applicability test - is the input type the same as the expected operand type?
+         */
+        boolean isUnaryOperatorApplicable(OperatorSymbol op, Type t) {
+            return types.isSameType(op.type.getParameterTypes().head, t);
+        }
+
+        /**
+         * Adds a unary operator symbol.
+         */
+        final UnaryOperatorHelper addUnaryOperator(OperatorType arg, OperatorType res, int... opcode) {
+            operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg), res, opcode));
+            return this;
+        }
+
+        /**
+         * This method will be overridden by unary operator helpers to provide custom resolution
+         * logic.
+         */
+        abstract Symbol resolve(Type t);
+    }
+
+    abstract class BinaryOperatorHelper extends OperatorHelper implements BiPredicate<Type, Type> {
+
+        BinaryOperatorHelper(Tag tag) {
+            super(tag);
+        }
+
+        /**
+         * This routine implements the binary operator lookup process. It customizes the behavior
+         * of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test
+         * (see {@link BinaryOperatorHelper#isBinaryOperatorApplicable(OperatorSymbol, Type, Type)}
+         */
+        final Symbol doLookup(Type t1, Type t2) {
+            return doLookup(op -> isBinaryOperatorApplicable((OperatorSymbol)op, t1, t2));
+        }
+
+        /**
+         * Binary operator applicability test - are the input types the same as the expected operand types?
+         */
+        boolean isBinaryOperatorApplicable(OperatorSymbol op, Type t1, Type t2) {
+            List<Type> formals = op.type.getParameterTypes();
+            return types.isSameType(formals.head, t1) &&
+                    types.isSameType(formals.tail.head, t2);
+        }
+
+        /**
+         * Adds a binary operator symbol.
+         */
+        final BinaryOperatorHelper addBinaryOperator(OperatorType arg1, OperatorType arg2, OperatorType res, int... opcode) {
+            operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg1, arg2), res, opcode));
+            return this;
+        }
+
+        /**
+         * This method will be overridden by binary operator helpers to provide custom resolution
+         * logic.
+         */
+        abstract Symbol resolve(Type t1, Type t2);
+    }
+
+    /**
+     * Class representing unary operator helpers that operate on reference types.
+     */
+    class UnaryReferenceOperator extends UnaryOperatorHelper {
+
+        UnaryReferenceOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type type) {
+            return type.isNullOrReference();
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(syms.objectType);
+        }
+    }
+
+    /**
+     * Class representing unary operator helpers that operate on numeric types (either boxed or unboxed).
+     * Operator lookup is performed after applying numeric promotion of the input type.
+     */
+    class UnaryNumericOperator extends UnaryOperatorHelper {
+
+        UnaryNumericOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type type) {
+            return unaryPromotion(type).isNumeric();
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(unaryPromotion(arg));
+        }
+    }
+
+    /**
+     * Class representing unary operator helpers that operate on boolean types  (either boxed or unboxed).
+     * Operator lookup is performed assuming the input type is a boolean type.
+     */
+    class UnaryBooleanOperator extends UnaryOperatorHelper {
+
+        UnaryBooleanOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type type) {
+            return types.unboxedTypeOrType(type).hasTag(TypeTag.BOOLEAN);
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(syms.booleanType);
+        }
+    }
+
+    /**
+     * Class representing prefix/postfix unary operator helpers. Operates on numeric types (either
+     * boxed or unboxed). Operator lookup is performed on the unboxed version of the input type.
+     */
+    class UnaryPrefixPostfixOperator extends UnaryNumericOperator {
+
+        UnaryPrefixPostfixOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(types.unboxedTypeOrType(arg));
+        }
+    }
+
+    /**
+     * Class representing binary operator helpers that operate on numeric types (either boxed or unboxed).
+     * Operator lookup is performed after applying binary numeric promotion of the input types.
+     */
+    class BinaryNumericOperator extends BinaryOperatorHelper {
+
+        BinaryNumericOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            Type t = binaryPromotion(arg1, arg2);
+            return doLookup(t, t);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return unaryPromotion(arg1).isNumeric() && unaryPromotion(arg2).isNumeric();
+        }
+    }
+
+    /**
+     * Class representing bitwise operator helpers that operate on all primitive types (either boxed or unboxed).
+     * Operator lookup is performed after applying binary numeric promotion of the input types.
+     */
+    class BinaryBitwiseOperator extends BinaryNumericOperator {
+
+        BinaryBitwiseOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return unaryPromotion(arg1).isPrimitive() && unaryPromotion(arg2).isPrimitive();
+        }
+    }
+
+    /**
+     * Class representing bitwise operator helpers that operate on boolean types (either boxed or unboxed).
+     * Operator lookup is performed assuming both input types are boolean types.
+     */
+    class BinaryBooleanOperator extends BinaryOperatorHelper {
+
+        BinaryBooleanOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            return doLookup(syms.booleanType, syms.booleanType);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return types.unboxedTypeOrType(arg1).hasTag(TypeTag.BOOLEAN) &&
+                    types.unboxedTypeOrType(arg2).hasTag(TypeTag.BOOLEAN);
+        }
+    }
+
+    /**
+     * Class representing string concatenation operator helper that operates on at least an
+     * string operand. Input types subject to an operator lookup undergoes a special string promotion
+     * (see {@link BinaryStringOperator#stringPromotion(Type)}.
+     */
+    class BinaryStringOperator extends BinaryOperatorHelper {
+
+        BinaryStringOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            return doLookup(stringPromotion(arg1), stringPromotion(arg2));
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return types.isSameType(arg1, syms.stringType) ||
+                    types.isSameType(arg2, syms.stringType);
+        }
+
+        /**
+         * This routine applies following mappings:
+         * - if input type is primitive, apply numeric promotion
+         * - if input type is either 'null' or 'String' leave it untouched
+         * - otherwise return 'Object'
+         */
+        private Type stringPromotion(Type t) {
+            if (t.isPrimitive()) {
+                return unaryPromotion(t);
+            } else if (t.hasTag(TypeTag.BOT) ||
+                    types.isSameType(t, syms.stringType)) {
+                return t;
+            } else if (t.hasTag(TypeTag.TYPEVAR)) {
+                return stringPromotion(t.getUpperBound());
+            } else {
+                return syms.objectType;
+            }
+        }
+    }
+
+    /**
+     * Class representing shift operator helper that operates on integral operand types (either boxed
+     * or unboxed). Operator lookup is performed after applying unary numeric promotion to each input type.
+     */
+    class BinaryShiftOperator extends BinaryOperatorHelper {
+
+        BinaryShiftOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            return doLookup(unaryPromotion(arg1), unaryPromotion(arg2));
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            TypeTag op1 = unaryPromotion(arg1).getTag();
+            TypeTag op2 = unaryPromotion(arg2).getTag();
+            return (op1 == TypeTag.LONG || op1 == TypeTag.INT) &&
+                    (op2 == TypeTag.LONG || op2 == TypeTag.INT);
+        }
+    }
+
+    /**
+     * This enum represent the possible kinds of an comparison test ('==' and '!=').
+     */
+    enum ComparisonKind {
+        /** equality between numeric or boolean operands. */
+        NUMERIC_OR_BOOLEAN,
+        /** equality between reference operands. */
+        REFERENCE,
+        /** erroneous equality */
+        INVALID
+    }
+
+    /**
+     * Class representing equality operator helper that operates on either numeric, boolean or reference
+     * types. Operator lookup for numeric/boolean equality test is performed after binary numeric
+     * promotion to the input types. Operator lookup for reference equality test is performed assuming
+     * the input type is 'Object'.
+     */
+    class BinaryEqualityOperator extends BinaryOperatorHelper {
+
+        BinaryEqualityOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return getKind(arg1, arg2) != ComparisonKind.INVALID;
+        }
+
+        @Override
+        public Symbol resolve(Type t1, Type t2) {
+            ComparisonKind kind = getKind(t1, t2);
+            Type t = (kind == ComparisonKind.NUMERIC_OR_BOOLEAN) ?
+                    binaryPromotion(t1, t2) :
+                    syms.objectType;
+            return doLookup(t, t);
+        }
+
+        /**
+         * Retrieve the comparison kind associated with the given argument type pair.
+         */
+        private ComparisonKind getKind(Type arg1, Type arg2) {
+            boolean arg1Primitive = arg1.isPrimitive();
+            boolean arg2Primitive = arg2.isPrimitive();
+            if (arg1Primitive && arg2Primitive) {
+                return ComparisonKind.NUMERIC_OR_BOOLEAN;
+            } else if (arg1Primitive) {
+                return unaryPromotion(arg2).isPrimitive() ?
+                        ComparisonKind.NUMERIC_OR_BOOLEAN : ComparisonKind.INVALID;
+            } else if (arg2Primitive) {
+                return unaryPromotion(arg1).isPrimitive() ?
+                        ComparisonKind.NUMERIC_OR_BOOLEAN : ComparisonKind.INVALID;
+            } else {
+                return arg1.isNullOrReference() && arg2.isNullOrReference() ?
+                        ComparisonKind.REFERENCE : ComparisonKind.INVALID;
+            }
+        }
+    }
+
+    /**
+     * Initialize all unary operators.
+     */
+    private void initUnaryOperators() {
+        initOperators(unaryOperators,
+                new UnaryNumericOperator(Tag.POS)
+                        .addUnaryOperator(DOUBLE, DOUBLE, nop)
+                        .addUnaryOperator(FLOAT, FLOAT, nop)
+                        .addUnaryOperator(LONG, LONG, nop)
+                        .addUnaryOperator(INT, INT, nop),
+                new UnaryNumericOperator(Tag.NEG)
+                        .addUnaryOperator(DOUBLE, DOUBLE, dneg)
+                        .addUnaryOperator(FLOAT, FLOAT, fneg)
+                        .addUnaryOperator(LONG, LONG, lneg)
+                        .addUnaryOperator(INT, INT, ineg),
+                new UnaryNumericOperator(Tag.COMPL)
+                        .addUnaryOperator(LONG, LONG, lxor)
+                        .addUnaryOperator(INT, INT, ixor),
+                new UnaryPrefixPostfixOperator(Tag.POSTINC)
+                        .addUnaryOperator(DOUBLE, DOUBLE, dadd)
+                        .addUnaryOperator(FLOAT, FLOAT, fadd)
+                        .addUnaryOperator(LONG, LONG, ladd)
+                        .addUnaryOperator(INT, INT, iadd)
+                        .addUnaryOperator(CHAR, CHAR, iadd)
+                        .addUnaryOperator(SHORT, SHORT, iadd)
+                        .addUnaryOperator(BYTE, BYTE, iadd),
+                new UnaryPrefixPostfixOperator(Tag.POSTDEC)
+                        .addUnaryOperator(DOUBLE, DOUBLE, dsub)
+                        .addUnaryOperator(FLOAT, FLOAT, fsub)
+                        .addUnaryOperator(LONG, LONG, lsub)
+                        .addUnaryOperator(INT, INT, isub)
+                        .addUnaryOperator(CHAR, CHAR, isub)
+                        .addUnaryOperator(SHORT, SHORT, isub)
+                        .addUnaryOperator(BYTE, BYTE, isub),
+                new UnaryBooleanOperator(Tag.NOT)
+                        .addUnaryOperator(BOOLEAN, BOOLEAN, bool_not),
+                new UnaryReferenceOperator(Tag.NULLCHK)
+                        .addUnaryOperator(OBJECT, OBJECT, nullchk));
+    }
+
+    /**
+     * Initialize all binary operators.
+     */
+    private void initBinaryOperators() {
+        initOperators(binaryOperators,
+            new BinaryStringOperator(Tag.PLUS)
+                    .addBinaryOperator(STRING, OBJECT, STRING, string_add)
+                    .addBinaryOperator(OBJECT, STRING, STRING, string_add)
+                    .addBinaryOperator(STRING, STRING, STRING, string_add)
+                    .addBinaryOperator(STRING, INT, STRING, string_add)
+                    .addBinaryOperator(STRING, LONG, STRING, string_add)
+                    .addBinaryOperator(STRING, FLOAT, STRING, string_add)
+                    .addBinaryOperator(STRING, DOUBLE, STRING, string_add)
+                    .addBinaryOperator(STRING, BOOLEAN, STRING, string_add)
+                    .addBinaryOperator(STRING, BOT, STRING, string_add)
+                    .addBinaryOperator(INT, STRING, STRING, string_add)
+                    .addBinaryOperator(LONG, STRING, STRING, string_add)
+                    .addBinaryOperator(FLOAT, STRING, STRING, string_add)
+                    .addBinaryOperator(DOUBLE, STRING, STRING, string_add)
+                    .addBinaryOperator(BOOLEAN, STRING, STRING, string_add)
+                    .addBinaryOperator(BOT, STRING, STRING, string_add),
+            new BinaryNumericOperator(Tag.PLUS)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dadd)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fadd)
+                    .addBinaryOperator(LONG, LONG, LONG, ladd)
+                    .addBinaryOperator(INT, INT, INT, iadd),
+            new BinaryNumericOperator(Tag.MINUS)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dsub)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fsub)
+                    .addBinaryOperator(LONG, LONG, LONG, lsub)
+                    .addBinaryOperator(INT, INT, INT, isub),
+            new BinaryNumericOperator(Tag.MUL)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dmul)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fmul)
+                    .addBinaryOperator(LONG, LONG, LONG, lmul)
+                    .addBinaryOperator(INT, INT, INT, imul),
+            new BinaryNumericOperator(Tag.DIV)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, ddiv)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fdiv)
+                    .addBinaryOperator(LONG, LONG, LONG, ldiv)
+                    .addBinaryOperator(INT, INT, INT, idiv),
+            new BinaryNumericOperator(Tag.MOD)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dmod)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fmod)
+                    .addBinaryOperator(LONG, LONG, LONG, lmod)
+                    .addBinaryOperator(INT, INT, INT, imod),
+            new BinaryBitwiseOperator(Tag.BITAND)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, iand)
+                    .addBinaryOperator(LONG, LONG, LONG, land)
+                    .addBinaryOperator(INT, INT, INT, iand),
+            new BinaryBitwiseOperator(Tag.BITOR)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ior)
+                    .addBinaryOperator(LONG, LONG, LONG, lor)
+                    .addBinaryOperator(INT, INT, INT, ior),
+            new BinaryBitwiseOperator(Tag.BITXOR)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ixor)
+                    .addBinaryOperator(LONG, LONG, LONG, lxor)
+                    .addBinaryOperator(INT, INT, INT, ixor),
+            new BinaryShiftOperator(Tag.SL)
+                    .addBinaryOperator(INT, INT, INT, ishl)
+                    .addBinaryOperator(INT, LONG, INT, ishll)
+                    .addBinaryOperator(LONG, INT, LONG, lshl)
+                    .addBinaryOperator(LONG, LONG, LONG, lshll),
+            new BinaryShiftOperator(Tag.SR)
+                    .addBinaryOperator(INT, INT, INT, ishr)
+                    .addBinaryOperator(INT, LONG, INT, ishrl)
+                    .addBinaryOperator(LONG, INT, LONG, lshr)
+                    .addBinaryOperator(LONG, LONG, LONG, lshrl),
+            new BinaryShiftOperator(Tag.USR)
+                    .addBinaryOperator(INT, INT, INT, iushr)
+                    .addBinaryOperator(INT, LONG, INT, iushrl)
+                    .addBinaryOperator(LONG, INT, LONG, lushr)
+                    .addBinaryOperator(LONG, LONG, LONG, lushrl),
+            new BinaryNumericOperator(Tag.LT)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpg, iflt)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpg, iflt)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, iflt)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmplt),
+            new BinaryNumericOperator(Tag.GT)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifgt)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifgt)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifgt)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpgt),
+            new BinaryNumericOperator(Tag.LE)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpg, ifle)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpg, ifle)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifle)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmple),
+            new BinaryNumericOperator(Tag.GE)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifge)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifge)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifge)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpge),
+            new BinaryEqualityOperator(Tag.EQ)
+                    .addBinaryOperator(OBJECT, OBJECT, BOOLEAN, if_acmpeq)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, if_icmpeq)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifeq)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifeq)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifeq)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpeq),
+            new BinaryEqualityOperator(Tag.NE)
+                    .addBinaryOperator(OBJECT, OBJECT, BOOLEAN, if_acmpne)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, if_icmpne)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifne)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifne)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifne)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpne),
+            new BinaryBooleanOperator(Tag.AND)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_and),
+            new BinaryBooleanOperator(Tag.OR)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_or));
+    }
+
+    /**
+     * Complete the initialization of an operator helper by storing it into the corresponding operator map.
+     */
+    @SafeVarargs
+    private final <O extends OperatorHelper> void initOperators(Map<Name, List<O>> opsMap, O... ops) {
+        for (O o : ops) {
+            Name opName = o.name;
+            List<O> helpers = opsMap.getOrDefault(opName, List.nil());
+            opsMap.put(opName, helpers.prepend(o));
+        }
+    }
+
+    /**
+     * Initialize operator name array.
+     */
+    private void initOperatorNames() {
+        setOperatorName(Tag.POS, "+");
+        setOperatorName(Tag.NEG, "-");
+        setOperatorName(Tag.NOT, "!");
+        setOperatorName(Tag.COMPL, "~");
+        setOperatorName(Tag.PREINC, "++");
+        setOperatorName(Tag.PREDEC, "--");
+        setOperatorName(Tag.POSTINC, "++");
+        setOperatorName(Tag.POSTDEC, "--");
+        setOperatorName(Tag.NULLCHK, "<*nullchk*>");
+        setOperatorName(Tag.OR, "||");
+        setOperatorName(Tag.AND, "&&");
+        setOperatorName(Tag.EQ, "==");
+        setOperatorName(Tag.NE, "!=");
+        setOperatorName(Tag.LT, "<");
+        setOperatorName(Tag.GT, ">");
+        setOperatorName(Tag.LE, "<=");
+        setOperatorName(Tag.GE, ">=");
+        setOperatorName(Tag.BITOR, "|");
+        setOperatorName(Tag.BITXOR, "^");
+        setOperatorName(Tag.BITAND, "&");
+        setOperatorName(Tag.SL, "<<");
+        setOperatorName(Tag.SR, ">>");
+        setOperatorName(Tag.USR, ">>>");
+        setOperatorName(Tag.PLUS, "+");
+        setOperatorName(Tag.MINUS, names.hyphen);
+        setOperatorName(Tag.MUL, names.asterisk);
+        setOperatorName(Tag.DIV, names.slash);
+        setOperatorName(Tag.MOD, "%");
+    }
+    //where
+        private void setOperatorName(Tag tag, String name) {
+            setOperatorName(tag, names.fromString(name));
+        }
+
+        private void setOperatorName(Tag tag, Name name) {
+            opname[tag.operatorIndex()] = name;
+        }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Feb 19 16:38:54 2015 -0800
@@ -90,7 +90,6 @@
     Check chk;
     Infer infer;
     ClassFinder finder;
-    TreeInfo treeinfo;
     Types types;
     JCDiagnostic.Factory diags;
     public final boolean allowMethodHandles;
@@ -118,7 +117,6 @@
         chk = Check.instance(context);
         infer = Infer.instance(context);
         finder = ClassFinder.instance(context);
-        treeinfo = TreeInfo.instance(context);
         types = Types.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         Source source = Source.instance(context);
@@ -652,7 +650,7 @@
          * Retrieve the method check object that will be used during a
          * most specific check.
          */
-        MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict);
+        MethodCheck mostSpecificCheck(List<Type> actuals);
     }
 
     /**
@@ -698,7 +696,7 @@
             //do nothing - method always applicable regardless of actuals
         }
 
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
             return this;
         }
     };
@@ -773,7 +771,7 @@
             throw ex.setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args));
         }
 
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
             return nilMethodCheck;
         }
 
@@ -881,8 +879,8 @@
         }
 
         @Override
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
-            return new MostSpecificCheck(strict, actuals);
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
+            return new MostSpecificCheck(actuals);
         }
 
         @Override
@@ -935,8 +933,8 @@
         }
 
         @Override
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
-            return new MostSpecificCheck(strict, actuals);
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
+            return new MostSpecificCheck(actuals);
         }
 
         @Override
@@ -1047,11 +1045,9 @@
      */
     class MostSpecificCheck implements MethodCheck {
 
-        boolean strict;
         List<Type> actuals;
 
-        MostSpecificCheck(boolean strict, List<Type> actuals) {
-            this.strict = strict;
+        MostSpecificCheck(List<Type> actuals) {
             this.actuals = actuals;
         }
 
@@ -1077,7 +1073,7 @@
         ResultInfo methodCheckResult(Type to, DeferredAttr.DeferredAttrContext deferredAttrContext,
                Warner rsWarner, Type actual) {
             return attr.new ResultInfo(KindSelector.VAL, to,
-                   new MostSpecificCheckContext(strict, deferredAttrContext, rsWarner, actual));
+                   new MostSpecificCheckContext(deferredAttrContext, rsWarner, actual));
         }
 
         /**
@@ -1089,8 +1085,8 @@
 
             Type actual;
 
-            public MostSpecificCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) {
-                super(strict, deferredAttrContext, rsWarner);
+            public MostSpecificCheckContext(DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) {
+                super(true, deferredAttrContext, rsWarner);
                 this.actual = actual;
             }
 
@@ -1236,7 +1232,7 @@
 
         }
 
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
             Assert.error("Cannot get here!");
             return null;
         }
@@ -1427,8 +1423,7 @@
                       Symbol sym,
                       Symbol bestSoFar,
                       boolean allowBoxing,
-                      boolean useVarargs,
-                      boolean operator) {
+                      boolean useVarargs) {
         if (sym.kind == ERR ||
                 !sym.isInheritedIn(site.tsym, types)) {
             return bestSoFar;
@@ -1441,16 +1436,13 @@
         try {
             Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes,
                                allowBoxing, useVarargs, types.noWarnings);
-            if (!operator || verboseResolutionMode.contains(VerboseResolutionMode.PREDEF))
-                currentResolutionContext.addApplicableCandidate(sym, mt);
+            currentResolutionContext.addApplicableCandidate(sym, mt);
         } catch (InapplicableMethodException ex) {
-            if (!operator)
-                currentResolutionContext.addInapplicableCandidate(sym, ex.getDiagnostic());
+            currentResolutionContext.addInapplicableCandidate(sym, ex.getDiagnostic());
             switch (bestSoFar.kind) {
                 case ABSENT_MTH:
                     return new InapplicableSymbolError(currentResolutionContext);
                 case WRONG_MTH:
-                    if (operator) return bestSoFar;
                     bestSoFar = new InapplicableSymbolsError(currentResolutionContext);
                 default:
                     return bestSoFar;
@@ -1463,8 +1455,7 @@
         }
         return (bestSoFar.kind.isOverloadError() && bestSoFar.kind != AMBIGUOUS)
             ? sym
-            : mostSpecific(argtypes, sym, bestSoFar, env, site,
-                           allowBoxing && operator, useVarargs);
+            : mostSpecific(argtypes, sym, bestSoFar, env, site, useVarargs);
     }
 
     /* Return the most specific of the two methods for a call,
@@ -1481,15 +1472,14 @@
                         Symbol m2,
                         Env<AttrContext> env,
                         final Type site,
-                        boolean allowBoxing,
                         boolean useVarargs) {
         switch (m2.kind) {
         case MTH:
             if (m1 == m2) return m1;
             boolean m1SignatureMoreSpecific =
-                    signatureMoreSpecific(argtypes, env, site, m1, m2, allowBoxing, useVarargs);
+                    signatureMoreSpecific(argtypes, env, site, m1, m2, useVarargs);
             boolean m2SignatureMoreSpecific =
-                    signatureMoreSpecific(argtypes, env, site, m2, m1, allowBoxing, useVarargs);
+                    signatureMoreSpecific(argtypes, env, site, m2, m1, useVarargs);
             if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) {
                 Type mt1 = types.memberType(site, m1);
                 Type mt2 = types.memberType(site, m2);
@@ -1531,7 +1521,7 @@
             boolean m1MoreSpecificThanAnyAmbiguous = true;
             boolean allAmbiguousMoreSpecificThanM1 = true;
             for (Symbol s : e.ambiguousSyms) {
-                Symbol moreSpecific = mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs);
+                Symbol moreSpecific = mostSpecific(argtypes, m1, s, env, site, useVarargs);
                 m1MoreSpecificThanAnyAmbiguous &= moreSpecific == m1;
                 allAmbiguousMoreSpecificThanM1 &= moreSpecific == s;
             }
@@ -1547,7 +1537,7 @@
         }
     }
     //where
-    private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
+    private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean useVarargs) {
         noteWarner.clear();
         int maxLength = Math.max(
                             Math.max(m1.type.getParameterTypes().length(), actuals.length()),
@@ -1557,10 +1547,10 @@
             currentResolutionContext = new MethodResolutionContext();
             currentResolutionContext.step = prevResolutionContext.step;
             currentResolutionContext.methodCheck =
-                    prevResolutionContext.methodCheck.mostSpecificCheck(actuals, !allowBoxing);
+                    prevResolutionContext.methodCheck.mostSpecificCheck(actuals);
             Type mst = instantiate(env, site, m2, null,
                     adjustArgs(types.cvarLowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null,
-                    allowBoxing, useVarargs, noteWarner);
+                    false, useVarargs, noteWarner);
             return mst != null &&
                     !noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
         } finally {
@@ -1623,11 +1613,10 @@
             Symbol bestSoFar,
             boolean allowBoxing,
             boolean useVarargs,
-            boolean operator,
             boolean abstractok) {
         for (Symbol s : sc.getSymbolsByName(name, new LookupFilter(abstractok))) {
             bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
-                    bestSoFar, allowBoxing, useVarargs, operator);
+                    bestSoFar, allowBoxing, useVarargs);
         }
         return bestSoFar;
     }
@@ -1667,8 +1656,7 @@
                       List<Type> argtypes,
                       List<Type> typeargtypes,
                       boolean allowBoxing,
-                      boolean useVarargs,
-                      boolean operator) {
+                      boolean useVarargs) {
         Symbol bestSoFar = methodNotFound;
         bestSoFar = findMethod(env,
                           site,
@@ -1678,8 +1666,7 @@
                           site.tsym.type,
                           bestSoFar,
                           allowBoxing,
-                          useVarargs,
-                          operator);
+                          useVarargs);
         return bestSoFar;
     }
     // where
@@ -1691,15 +1678,14 @@
                               Type intype,
                               Symbol bestSoFar,
                               boolean allowBoxing,
-                              boolean useVarargs,
-                              boolean operator) {
+                              boolean useVarargs) {
         @SuppressWarnings({"unchecked","rawtypes"})
         List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>nil() };
 
         InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK;
         for (TypeSymbol s : superclasses(intype)) {
             bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
-                    s.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
+                    s.members(), bestSoFar, allowBoxing, useVarargs, true);
             if (name == names.init) return bestSoFar;
             iphase = (iphase == null) ? null : iphase.update(s, this);
             if (iphase != null) {
@@ -1720,7 +1706,7 @@
                 if (iphase2 == InterfaceLookupPhase.DEFAULT_OK &&
                         (itype.tsym.flags() & DEFAULT) == 0) continue;
                 bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
-                        itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
+                        itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, true);
                 if (concrete != bestSoFar &&
                     concrete.kind.isValid() &&
                     bestSoFar.kind.isValid() &&
@@ -1833,7 +1819,7 @@
             if (isStatic(env1)) staticOnly = true;
             Symbol sym = findMethod(
                 env1, env1.enclClass.sym.type, name, argtypes, typeargtypes,
-                allowBoxing, useVarargs, false);
+                allowBoxing, useVarargs);
             if (sym.exists()) {
                 if (staticOnly &&
                     sym.kind == MTH &&
@@ -1848,7 +1834,7 @@
         }
 
         Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
-                                typeargtypes, allowBoxing, useVarargs, false);
+                                typeargtypes, allowBoxing, useVarargs);
         if (sym.exists())
             return sym;
 
@@ -1862,7 +1848,7 @@
                 bestSoFar = selectBest(env, origin.type,
                                        argtypes, typeargtypes,
                                        currentSym, bestSoFar,
-                                       allowBoxing, useVarargs, false);
+                                       allowBoxing, useVarargs);
             }
         }
         if (bestSoFar.exists())
@@ -1878,7 +1864,7 @@
                 bestSoFar = selectBest(env, origin.type,
                                        argtypes, typeargtypes,
                                        currentSym, bestSoFar,
-                                       allowBoxing, useVarargs, false);
+                                       allowBoxing, useVarargs);
             }
         }
         return bestSoFar;
@@ -2269,9 +2255,7 @@
                         (typeargtypes == null || !Type.isErroneous(typeargtypes));
         }
         public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
-            return (syms.operatorNames.contains(name)) ?
-                    argtypes :
-                    Type.map(argtypes, new ResolveDeferredRecoveryMap(AttrMode.SPECULATIVE, accessedSym, currentResolutionContext.step));
+            return Type.map(argtypes, new ResolveDeferredRecoveryMap(AttrMode.SPECULATIVE, accessedSym, currentResolutionContext.step));
         }
     };
 
@@ -2375,7 +2359,7 @@
             Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                 return findMethod(env, site, name, argtypes, typeargtypes,
                         phase.isBoxingRequired(),
-                        phase.isVarargsRequired(), false);
+                        phase.isVarargsRequired());
             }
             @Override
             Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
@@ -2506,7 +2490,7 @@
         Symbol sym = findMethod(env, site,
                                     names.init, argtypes,
                                     typeargtypes, allowBoxing,
-                                    useVarargs, false);
+                                    useVarargs);
         chk.checkDeprecated(pos, env.info.scope.owner, sym);
         return sym;
     }
@@ -2587,71 +2571,12 @@
                             newConstr,
                             bestSoFar,
                             allowBoxing,
-                            useVarargs,
-                            false);
+                            useVarargs);
             }
         }
         return bestSoFar;
     }
 
-
-
-    /** Resolve operator.
-     *  @param pos       The position to use for error reporting.
-     *  @param optag     The tag of the operation tree.
-     *  @param env       The environment current at the operation.
-     *  @param argtypes  The types of the operands.
-     */
-    Symbol resolveOperator(DiagnosticPosition pos, JCTree.Tag optag,
-                           Env<AttrContext> env, List<Type> argtypes) {
-        MethodResolutionContext prevResolutionContext = currentResolutionContext;
-        try {
-            currentResolutionContext = new MethodResolutionContext();
-            Name name = treeinfo.operatorName(optag);
-            return lookupMethod(env, pos, syms.predefClass, currentResolutionContext,
-                    new BasicLookupHelper(name, syms.predefClass.type, argtypes, null, BOX) {
-                @Override
-                Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
-                    return findMethod(env, site, name, argtypes, typeargtypes,
-                            phase.isBoxingRequired(),
-                            phase.isVarargsRequired(), true);
-                }
-                @Override
-                Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
-                    return accessMethod(sym, pos, env.enclClass.sym.type, name,
-                          false, argtypes, null);
-                }
-            });
-        } finally {
-            currentResolutionContext = prevResolutionContext;
-        }
-    }
-
-    /** Resolve operator.
-     *  @param pos       The position to use for error reporting.
-     *  @param optag     The tag of the operation tree.
-     *  @param env       The environment current at the operation.
-     *  @param arg       The type of the operand.
-     */
-    Symbol resolveUnaryOperator(DiagnosticPosition pos, JCTree.Tag optag, Env<AttrContext> env, Type arg) {
-        return resolveOperator(pos, optag, env, List.of(arg));
-    }
-
-    /** Resolve binary operator.
-     *  @param pos       The position to use for error reporting.
-     *  @param optag     The tag of the operation tree.
-     *  @param env       The environment current at the operation.
-     *  @param left      The types of the left operand.
-     *  @param right     The types of the right operand.
-     */
-    Symbol resolveBinaryOperator(DiagnosticPosition pos,
-                                 JCTree.Tag optag,
-                                 Env<AttrContext> env,
-                                 Type left,
-                                 Type right) {
-        return resolveOperator(pos, optag, env, List.of(left, right));
-    }
-
     Symbol getMemberReference(DiagnosticPosition pos,
             Env<AttrContext> env,
             JCMemberReference referenceTree,
@@ -3122,7 +3047,7 @@
         @Override
         final Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
             return findMethod(env, site, name, argtypes, typeargtypes,
-                    phase.isBoxingRequired(), phase.isVarargsRequired(), syms.operatorNames.contains(name));
+                    phase.isBoxingRequired(), phase.isVarargsRequired());
         }
 
         @Override
@@ -3217,7 +3142,7 @@
             MethodSymbol arrayConstr = new MethodSymbol(PUBLIC, name, null, site.tsym);
             arrayConstr.type = new MethodType(List.<Type>of(syms.intType), site, List.<Type>nil(), syms.methodClass);
             sc.enter(arrayConstr);
-            return findMethodInScope(env, site, name, argtypes, typeargtypes, sc, methodNotFound, phase.isBoxingRequired(), phase.isVarargsRequired(), false, false);
+            return findMethodInScope(env, site, name, argtypes, typeargtypes, sc, methodNotFound, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
         }
 
         @Override
@@ -3252,7 +3177,7 @@
             Symbol sym = needsInference ?
                 findDiamond(env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
                 findMethod(env, site, name, argtypes, typeargtypes,
-                        phase.isBoxingRequired(), phase.isVarargsRequired(), syms.operatorNames.contains(name));
+                        phase.isBoxingRequired(), phase.isVarargsRequired());
             return (sym.kind != MTH ||
                     site.getEnclosingType().hasTag(NONE) ||
                     hasEnclosingInstance(env, site)) ?
@@ -3607,16 +3532,6 @@
             if (name == names.error)
                 return null;
 
-            if (syms.operatorNames.contains(name)) {
-                boolean isUnaryOp = argtypes.size() == 1;
-                String key = argtypes.size() == 1 ?
-                    "operator.cant.be.applied" :
-                    "operator.cant.be.applied.1";
-                Type first = argtypes.head;
-                Type second = !isUnaryOp ? argtypes.tail.head : null;
-                return diags.create(dkind, log.currentSource(), pos,
-                        key, name, first, second);
-            }
             boolean hasLocation = false;
             if (location == null) {
                 location = site.tsym;
@@ -3716,36 +3631,24 @@
             if (name == names.error)
                 return null;
 
-            if (syms.operatorNames.contains(name)) {
-                boolean isUnaryOp = argtypes.size() == 1;
-                String key = argtypes.size() == 1 ?
-                    "operator.cant.be.applied" :
-                    "operator.cant.be.applied.1";
-                Type first = argtypes.head;
-                Type second = !isUnaryOp ? argtypes.tail.head : null;
-                return diags.create(dkind, log.currentSource(), pos,
-                        key, name, first, second);
+            Pair<Symbol, JCDiagnostic> c = errCandidate();
+            if (compactMethodDiags) {
+                JCDiagnostic simpleDiag =
+                    MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd);
+                if (simpleDiag != null) {
+                    return simpleDiag;
+                }
             }
-            else {
-                Pair<Symbol, JCDiagnostic> c = errCandidate();
-                if (compactMethodDiags) {
-                    JCDiagnostic simpleDiag =
-                        MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd);
-                    if (simpleDiag != null) {
-                        return simpleDiag;
-                    }
-                }
-                Symbol ws = c.fst.asMemberOf(site, types);
-                return diags.create(dkind, log.currentSource(), pos,
-                          "cant.apply.symbol",
-                          kindName(ws),
-                          ws.name == names.init ? ws.owner.name : ws.name,
-                          methodArguments(ws.type.getParameterTypes()),
-                          methodArguments(argtypes),
-                          kindName(ws.owner),
-                          ws.owner.type,
-                          c.snd);
-            }
+            Symbol ws = c.fst.asMemberOf(site, types);
+            return diags.create(dkind, log.currentSource(), pos,
+                      "cant.apply.symbol",
+                      kindName(ws),
+                      ws.name == names.init ? ws.owner.name : ws.name,
+                      methodArguments(ws.type.getParameterTypes()),
+                      methodArguments(argtypes),
+                      kindName(ws.owner),
+                      ws.owner.type,
+                      c.snd);
         }
 
         @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu Feb 19 16:38:54 2015 -0800
@@ -678,29 +678,43 @@
                     boolean haveJImageFiles =
                             files.anyMatch(f -> f.getFileName().toString().endsWith(".jimage"));
                     if (haveJImageFiles) {
-                        return Collections.singleton(JRT_MARKER_FILE);
+                        return addAdditionalBootEntries(Collections.singleton(JRT_MARKER_FILE));
                     }
                 }
             }
 
-            // Temporary: if no .jimage files, return individual modules
-            if (Files.exists(libModules.resolve("java.base"))) {
-                return Files.list(libModules)
-                            .map(d -> d.resolve("classes"))
-                            .collect(Collectors.toList());
-            }
-
             // Exploded module image
             Path modules = Paths.get(java_home, "modules");
             if (Files.isDirectory(modules.resolve("java.base"))) {
-                return Files.list(modules)
-                            .collect(Collectors.toList());
+                try (Stream<Path> listedModules = Files.list(modules)) {
+                    return addAdditionalBootEntries(listedModules.collect(Collectors.toList()));
+                }
             }
 
             // not a modular image that we know about
             return null;
         }
 
+        //ensure bootclasspath prepends/appends are reflected in the systemClasses
+        private Collection<Path> addAdditionalBootEntries(Collection<Path> modules) throws IOException {
+            String files = System.getProperty("sun.boot.class.path");
+
+            if (files == null)
+                return modules;
+
+            Set<Path> paths = new LinkedHashSet<>();
+
+            for (String s : files.split(Pattern.quote(File.pathSeparator))) {
+                if (s.endsWith(".jimage")) {
+                    paths.addAll(modules);
+                } else if (!s.isEmpty()) {
+                    paths.add(Paths.get(s));
+                }
+            }
+
+            return paths;
+        }
+
         private void lazy() {
             if (searchPath == null) {
                 try {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Feb 19 16:38:54 2015 -0800
@@ -656,8 +656,7 @@
 
     private void writeParamAnnotations(MethodSymbol m,
                                        RetentionPolicy retention) {
-        databuf.appendByte(m.params.length() + m.extraParams.length());
-        writeParamAnnotations(m.extraParams, retention);
+        databuf.appendByte(m.params.length());
         writeParamAnnotations(m.params, retention);
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Feb 19 16:38:54 2015 -0800
@@ -828,7 +828,7 @@
 compiler.err.not.encl.class=\
     not an enclosing class: {0}
 
-# 0: name, 1: type, 2: unused
+# 0: name, 1: type
 compiler.err.operator.cant.be.applied=\
     bad operand type {1} for unary operator ''{0}''
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Thu Feb 19 16:38:54 2015 -0800
@@ -51,62 +51,6 @@
  *  deletion without notice.</b>
  */
 public class TreeInfo {
-    protected static final Context.Key<TreeInfo> treeInfoKey = new Context.Key<>();
-
-    public static TreeInfo instance(Context context) {
-        TreeInfo instance = context.get(treeInfoKey);
-        if (instance == null)
-            instance = new TreeInfo(context);
-        return instance;
-    }
-
-    /** The names of all operators.
-     */
-    private Name[] opname = new Name[Tag.getNumberOfOperators()];
-
-    private void setOpname(Tag tag, String name, Names names) {
-         setOpname(tag, names.fromString(name));
-     }
-     private void setOpname(Tag tag, Name name) {
-         opname[tag.operatorIndex()] = name;
-     }
-
-    private TreeInfo(Context context) {
-        context.put(treeInfoKey, this);
-
-        Names names = Names.instance(context);
-        /*  Internally we use +++, --- for unary +, - to reduce +, - operators
-         *  overloading
-         */
-        setOpname(POS, "+++", names);
-        setOpname(NEG, "---", names);
-        setOpname(NOT, "!", names);
-        setOpname(COMPL, "~", names);
-        setOpname(PREINC, "++", names);
-        setOpname(PREDEC, "--", names);
-        setOpname(POSTINC, "++", names);
-        setOpname(POSTDEC, "--", names);
-        setOpname(NULLCHK, "<*nullchk*>", names);
-        setOpname(OR, "||", names);
-        setOpname(AND, "&&", names);
-        setOpname(EQ, "==", names);
-        setOpname(NE, "!=", names);
-        setOpname(LT, "<", names);
-        setOpname(GT, ">", names);
-        setOpname(LE, "<=", names);
-        setOpname(GE, ">=", names);
-        setOpname(BITOR, "|", names);
-        setOpname(BITXOR, "^", names);
-        setOpname(BITAND, "&", names);
-        setOpname(SL, "<<", names);
-        setOpname(SR, ">>", names);
-        setOpname(USR, ">>>", names);
-        setOpname(PLUS, "+", names);
-        setOpname(MINUS, names.hyphen);
-        setOpname(MUL, names.asterisk);
-        setOpname(DIV, names.slash);
-        setOpname(MOD, "%", names);
-    }
 
     public static List<JCExpression> args(JCTree t) {
         switch (t.getTag()) {
@@ -119,12 +63,6 @@
         }
     }
 
-    /** Return name of operator with given tree tag.
-     */
-    public Name operatorName(JCTree.Tag tag) {
-        return opname[tag.operatorIndex()];
-    }
-
     /** Is tree a constructor declaration?
      */
     public static boolean isConstructor(JCTree tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Bits.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Bits.java	Thu Feb 19 16:38:54 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, 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
@@ -84,20 +84,6 @@
 
     }
 
-    public enum BitsOpKind {
-        INIT,
-        CLEAR,
-        INCL_BIT,
-        EXCL_BIT,
-        ASSIGN,
-        AND_SET,
-        OR_SET,
-        DIFF_SET,
-        XOR_SET,
-        INCL_RANGE,
-        EXCL_RANGE,
-    }
-
     private final static int wordlen = 32;
     private final static int wordshift = 5;
     private final static int wordmask = wordlen - 1;
--- a/test/tools/javac/7102515/T7102515.out	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/7102515/T7102515.out	Thu Feb 19 16:38:54 2015 -0800
@@ -1,3 +1,3 @@
 T7102515.java:9:41: compiler.err.operator.cant.be.applied.1: +, T7102515, T7102515
-T7102515.java:10:32: compiler.err.operator.cant.be.applied: ++, T7102515, null
+T7102515.java:10:32: compiler.err.operator.cant.be.applied: ++, T7102515
 2 errors
--- a/test/tools/javac/annotations/SyntheticParameters.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/annotations/SyntheticParameters.java	Thu Feb 19 16:38:54 2015 -0800
@@ -46,20 +46,11 @@
                      null,
                      new ExpectedParameterAnnotation[] {
                          (ExpectedParameterAnnotation)
-                         // Assert there is no annotation on the
-                         // this$0 parameter.
-                         new ExpectedParameterAnnotation(
-                             "<init>",
-                             0,
-                             "A",
-                             true,
-                             0),
-                         (ExpectedParameterAnnotation)
                          // Assert there is an annotation on the
                          // first parameter.
                          new ExpectedParameterAnnotation(
                              "<init>",
-                             1,
+                             0,
                              "A",
                              true,
                              1),
@@ -71,27 +62,11 @@
                              true,
                              1),
                          (ExpectedParameterAnnotation)
-                         new ExpectedParameterAnnotation(
-                             "foo",
-                             1,
-                             "A",
-                             true,
-                             0),
-                         (ExpectedParameterAnnotation)
-                         // Assert there is no annotation on the
-                         // this$0 parameter.
-                         new ExpectedParameterAnnotation(
-                             "<init>",
-                             0,
-                             "B",
-                             false,
-                             0),
-                         (ExpectedParameterAnnotation)
                          // Assert there is an annotation on the
                          // first parameter.
                          new ExpectedParameterAnnotation(
                              "<init>",
-                             1,
+                             0,
                              "B",
                              false,
                              1),
@@ -117,58 +92,22 @@
                      null,
                      new ExpectedParameterAnnotation[] {
                          (ExpectedParameterAnnotation)
-                         // Assert there is no annotation on the
-                         // $enum$name parameter.
+                         // Assert there is an annotation on the
+                         // first parameter.
                          new ExpectedParameterAnnotation(
                              "<init>",
                              0,
                              "A",
                              true,
-                             0),
-                         (ExpectedParameterAnnotation)
-                         // Assert there is no annotation on the
-                         // $enum$ordinal parameter.
-                         new ExpectedParameterAnnotation(
-                             "<init>",
-                             1,
-                             "A",
-                             true,
-                             0),
+                             1),
                          (ExpectedParameterAnnotation)
                          // Assert there is an annotation on the
                          // first parameter.
                          new ExpectedParameterAnnotation(
                              "<init>",
-                             2,
-                             "A",
-                             true,
-                             1),
-                         (ExpectedParameterAnnotation)
-                         // Assert there is no annotation on the
-                         // $enum$name parameter.
-                         new ExpectedParameterAnnotation(
-                             "<init>",
                              0,
                              "B",
                              false,
-                             0),
-                         (ExpectedParameterAnnotation)
-                         // Assert there is no annotation on the
-                         // $enum$ordinal parameter.
-                         new ExpectedParameterAnnotation(
-                             "<init>",
-                             1,
-                             "B",
-                             false,
-                             0),
-                         (ExpectedParameterAnnotation)
-                         // Assert there is an annotation on the
-                         // first parameter.
-                         new ExpectedParameterAnnotation(
-                             "<init>",
-                             2,
-                             "B",
-                             false,
                              1)
                      },
                      null);
--- a/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java	Thu Feb 19 16:38:54 2015 -0800
@@ -44,15 +44,6 @@
                      null,
                      new ExpectedMethodTypeAnnotation[] {
                          (ExpectedMethodTypeAnnotation)
-                         // Assert there is no annotation on the
-                         // this$0 parameter.
-                         new ExpectedMethodTypeAnnotation.Builder(
-                             "<init>",
-                             "A",
-                             TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
-                             false,
-                             0).setParameterIndex(0).build(),
-                         (ExpectedMethodTypeAnnotation)
                          // Assert there is an annotation on the
                          // first parameter.
                          new ExpectedMethodTypeAnnotation.Builder(
@@ -60,21 +51,7 @@
                              "A",
                              TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
                              false,
-                             1).setParameterIndex(1).build(),
-                         (ExpectedMethodTypeAnnotation)
-                         new ExpectedMethodTypeAnnotation.Builder(
-                             "foo",
-                             "A",
-                             TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
-                             false,
-                             1).setParameterIndex(0).build(),
-                         (ExpectedMethodTypeAnnotation)
-                         new ExpectedMethodTypeAnnotation.Builder(
-                             "foo",
-                             "A",
-                             TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
-                             false,
-                             0).setParameterIndex(1).build()
+                             1).setParameterIndex(0).build()
                      },
                      null);
     private static final Expected Foo_expected =
@@ -89,26 +66,7 @@
                              "A",
                              TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
                              false,
-                             0).setParameterIndex(0).build(),
-                         (ExpectedMethodTypeAnnotation)
-                         // Assert there is no annotation on the
-                         // $enum$ordinal parameter.
-                         new ExpectedMethodTypeAnnotation.Builder(
-                             "<init>",
-                             "A",
-                             TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
-                             false,
-                             0).setParameterIndex(1).build(),
-                         (ExpectedMethodTypeAnnotation)
-                         // Assert there is an annotation on the
-                         // first parameter.
-                         new ExpectedMethodTypeAnnotation.Builder(
-                             "<init>",
-                             "A",
-                             TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
-                             false,
-                             1).setParameterIndex(2).build()
-                     },
+                             1).setParameterIndex(0).build()                     },
                      null);
 
     public static void main(String... args) throws Exception {
--- a/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java	Thu Feb 19 16:38:54 2015 -0800
@@ -43,7 +43,7 @@
 
     @TADescription(annotation = "TA", type = METHOD_RETURN, genericLocation = {1, 0})
     @TADescription(annotation = "TB", type = METHOD_RETURN, genericLocation = {1, 0})
-    @TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
+    @TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
     @TestClass("%TEST_CLASS_NAME%$Inner")
     public String innerClass() {
         return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -56,7 +56,7 @@
     @TADescription(annotation = "TB", type = METHOD_RETURN, genericLocation = {1, 0})
     @TADescription(annotation = "TC", type = METHOD_RECEIVER)
     @TADescription(annotation = "TD", type = METHOD_RETURN, genericLocation = {1, 0})
-    @TADescription(annotation = "TE", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
+    @TADescription(annotation = "TE", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
     @TestClass("%TEST_CLASS_NAME%$Inner")
     public String innerClass2() {
         return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -70,7 +70,7 @@
     @TADescription(annotation = "TC", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
     @TADescription(annotation = "TD", type = METHOD_RECEIVER, genericLocation = {1, 0})
     @TADescription(annotation = "TE", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
-    @TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
+    @TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
     @TestClass("Outer$Middle$Inner")
     public String innerClass3() {
         return "class Outer { class Middle { class Inner {" +
@@ -89,7 +89,7 @@
 
     @TADescription(annotation = "RTAs", type = METHOD_RETURN, genericLocation = {1, 0})
     @TADescription(annotation = "RTBs", type = METHOD_RETURN, genericLocation = {1, 0})
-    @TADescription(annotation = "RTCs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
+    @TADescription(annotation = "RTCs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
     @TestClass("%TEST_CLASS_NAME%$Inner")
     public String innerClassRepeatableAnnotation() {
         return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -102,7 +102,7 @@
     @TADescription(annotation = "RTBs", type = METHOD_RETURN, genericLocation = {1, 0})
     @TADescription(annotation = "RTCs", type = METHOD_RECEIVER)
     @TADescription(annotation = "RTDs", type = METHOD_RETURN, genericLocation = {1, 0})
-    @TADescription(annotation = "RTEs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
+    @TADescription(annotation = "RTEs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
     @TestClass("%TEST_CLASS_NAME%$Inner")
     public String innerClassRepeatableAnnotation2() {
         return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -116,7 +116,7 @@
     @TADescription(annotation = "RTCs", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
     @TADescription(annotation = "RTDs", type = METHOD_RECEIVER, genericLocation = {1, 0})
     @TADescription(annotation = "RTEs", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
-    @TADescription(annotation = "RTFs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
+    @TADescription(annotation = "RTFs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
     @TestClass("Outer$Middle$Inner")
     public String innerClassRepatableAnnotation3() {
         return "class Outer { class Middle { class Inner {" +
--- a/test/tools/javac/diags/examples/IncomparableTypes.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/diags/examples/IncomparableTypes.java	Thu Feb 19 16:38:54 2015 -0800
@@ -24,5 +24,5 @@
 // key: compiler.err.incomparable.types
 
 class X {
-    boolean b = (this == 1);
+    boolean b = (this == "");
 }
--- a/test/tools/javac/expression/NullAppend.out	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/expression/NullAppend.out	Thu Feb 19 16:38:54 2015 -0800
@@ -1,2 +1,2 @@
-NullAppend.java:11:16: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, compiler.misc.type.null
+NullAppend.java:11:21: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, compiler.misc.type.null
 1 error
--- a/test/tools/javac/expression/NullAppend2.out	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/expression/NullAppend2.out	Thu Feb 19 16:38:54 2015 -0800
@@ -1,2 +1,2 @@
-NullAppend2.java:10:16: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, int
+NullAppend2.java:10:21: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, int
 1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/file/BootClassPathPrepend.java	Thu Feb 19 16:38:54 2015 -0800
@@ -0,0 +1,76 @@
+/*
+ * 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 8067445
+ * @summary Verify that file.Locations analyze sun.boot.class.path for BCP prepends/appends
+ * @library /tools/lib
+ */
+
+import java.io.IOException;
+import java.util.EnumSet;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+public class BootClassPathPrepend {
+    public static void main(String... args) throws IOException {
+        if (args.length == 0) {
+            new BootClassPathPrepend().reRun();
+        } else {
+            new BootClassPathPrepend().run();
+        }
+    }
+
+    void reRun() {
+        String testClasses = System.getProperty("test.classes");
+        ToolBox tb = new ToolBox();
+        tb.new JavaTask().vmOptions("-Xbootclasspath/p:" + testClasses)
+                         .classArgs("real-run")
+                         .className("BootClassPathPrepend")
+                         .run()
+                         .writeAll();
+    }
+
+    EnumSet<Kind> classKind = EnumSet.of(JavaFileObject.Kind.CLASS);
+
+    void run() throws IOException {
+        JavaCompiler toolProvider = ToolProvider.getSystemJavaCompiler();
+        try (JavaFileManager fm = toolProvider.getStandardFileManager(null, null, null)) {
+            Iterable<JavaFileObject> files =
+                    fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", classKind, false);
+            for (JavaFileObject fo : files) {
+                if (fo.isNameCompatible("BootClassPathPrepend", JavaFileObject.Kind.CLASS)) {
+                    System.err.println("Found BootClassPathPrepend on bootclasspath");
+                    return ;//found
+                }
+            }
+
+            throw new AssertionError("Cannot find class that was prepended on BCP");
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/file/ExplodedImage.java	Thu Feb 19 16:38:54 2015 -0800
@@ -0,0 +1,186 @@
+/*
+ * 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 com.sun.source.util.JavacTask;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+/**
+ * @test
+ * @bug 8067138
+ * @summary Verify that compiling against the exploded JDK image works, and that Locations close
+ *          the directory streams properly when working with exploded JDK image.
+ * @library /tools/lib
+ * @build ToolBox ExplodedImage
+ * @run main ExplodedImage
+ */
+
+public class ExplodedImage {
+    public static void main(String... args) throws IOException {
+        new ExplodedImage().run();
+    }
+
+    void run() throws IOException {
+        for (String moduleLocations : new String[] {"modules/*"}) {
+            System.setProperty("java.home", originalJavaHome);
+            testDirectoryStreamClosed(moduleLocations);
+            System.setProperty("java.home", originalJavaHome);
+            testCanCompileAgainstExplodedImage(moduleLocations);
+        }
+    }
+
+    void testDirectoryStreamClosed(String loc) throws IOException {
+        System.err.println("testDirectoryStreamClosed(" + loc + ")");
+        Path javaHome = prepareJavaHome();
+        Path targetPath = javaHome.resolve(loc.replace("*", "/java.base").replace("/", sep));
+        Path testClass = targetPath.resolve(("java/lang/" + TEST_FILE).replace("/", sep));
+        Files.createDirectories(testClass.getParent());
+        Files.createFile(testClass);
+        System.setProperty("java.home", javaHome.toString());
+
+        for (int i = 0; i < REPEATS; i++) {
+            try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
+                Iterable<JavaFileObject> javaLangContent =
+                        fm.list(StandardLocation.PLATFORM_CLASS_PATH,
+                                "java.lang",
+                                EnumSet.allOf(JavaFileObject.Kind.class),
+                                false);
+                boolean found = false;
+
+                for (JavaFileObject fo : javaLangContent) {
+                    if (!fo.getName().endsWith(TEST_FILE)) {
+                        throw new IllegalStateException("Wrong file: " + fo);
+                    }
+                    found = true;
+                }
+
+                if (!found)
+                    throw new IllegalStateException("Could not find the expected file!");
+            }
+        }
+
+        System.err.println("finished.");
+    }
+    //where:
+        static final String TEST_FILE = "ExplodedImageTestFile.class";
+        static final int REPEATS = 16 * 1024 + 1;
+
+    void testCanCompileAgainstExplodedImage(String loc) throws IOException {
+        System.err.println("testCanCompileAgainstExplodedImage(" + loc + ")");
+        Path javaHome = prepareJavaHome();
+        Path targetPath = javaHome.resolve(loc.replace("*", "/java.base").replace("/", sep));
+        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
+            for (String pack : REQUIRED_PACKAGES) {
+                Iterable<JavaFileObject> content = fm.list(StandardLocation.PLATFORM_CLASS_PATH,
+                                                           pack,
+                                                           EnumSet.allOf(JavaFileObject.Kind.class),
+                                                           false);
+
+                for (JavaFileObject jfo : content) {
+                    String name = jfo.getName();
+                    int lastSlash = name.lastIndexOf('/');
+                    name = lastSlash >= 0 ? name.substring(lastSlash + 1) : name;
+                    Path target = targetPath.resolve(pack.replace(".", sep) + sep + name);
+                    Files.createDirectories(target.getParent());
+                    try (InputStream in = jfo.openInputStream()) {
+                        Files.copy(in, target);
+                    }
+                }
+            }
+        }
+
+        System.setProperty("java.home", javaHome.toString());
+
+        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
+            DiagnosticListener<JavaFileObject> noErrors = d -> {
+                if (d.getKind() == Diagnostic.Kind.ERROR)
+                    throw new IllegalStateException("Unexpected error: " + d);
+            };
+            ToolBox.JavaSource inputFile =
+                    new ToolBox.JavaSource("import java.util.List; class Test { List l; }");
+            List<JavaFileObject> inputFiles = Arrays.asList(inputFile);
+            boolean result =
+                    javaCompiler.getTask(null, fm, noErrors, null, null, inputFiles).call();
+            if (!result) {
+                throw new IllegalStateException("Could not compile correctly!");
+            }
+            JavacTask task =
+                    (JavacTask) javaCompiler.getTask(null, fm, noErrors, null, null, inputFiles);
+            task.parse();
+            TypeElement juList = task.getElements().getTypeElement("java.util.List");
+            if (juList == null)
+                throw new IllegalStateException("Cannot resolve java.util.List!");
+            URI listSource = ((ClassSymbol) juList).classfile.toUri();
+            if (!listSource.toString().startsWith(javaHome.toUri().toString()))
+                throw new IllegalStateException(  "Did not load java.util.List from correct place, " +
+                                                  "actual location: " + listSource.toString() +
+                                                "; expected prefix: " + javaHome.toUri());
+        }
+
+        System.err.println("finished.");
+    }
+    //where:
+        static final String[] REQUIRED_PACKAGES = {"java.lang", "java.io", "java.util"};
+
+    Path prepareJavaHome() throws IOException {
+        Path javaHome = new File("javahome").getAbsoluteFile().toPath();
+        delete(javaHome);
+        Files.createDirectory(javaHome);
+        return javaHome;
+    }
+
+    String sep = FileSystems.getDefault().getSeparator();
+    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
+    String originalJavaHome = System.getProperty("java.home");
+
+    void delete(Path p) throws IOException {
+        if (!Files.exists(p))
+            return ;
+        if (Files.isDirectory(p)) {
+            try (DirectoryStream<Path> dir = Files.newDirectoryStream(p)) {
+                for (Path child : dir) {
+                    delete(child);
+                }
+            }
+        }
+        Files.delete(p);
+    }
+}
--- a/test/tools/javac/lambda/8068399/T8068399.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/lambda/8068399/T8068399.java	Thu Feb 19 16:38:54 2015 -0800
@@ -24,7 +24,7 @@
  */
 /*
  * @test
- * @bug 8068399
+ * @bug 8068399 8069545
  * @summary structural most specific and stuckness
  */
 
--- a/test/tools/javac/lambda/8068430/T8068430.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/lambda/8068430/T8068430.java	Thu Feb 19 16:38:54 2015 -0800
@@ -25,7 +25,7 @@
 
 /*
  * @test
- * @bug 8068430
+ * @bug 8068430 8069545
  * @summary structural most specific and stuckness
  */
 
@@ -43,4 +43,4 @@
                 (i, e) -> i + e.getKey(),
                 (i1, i2) -> i1 + i2));
     }
-}
\ No newline at end of file
+}
--- a/test/tools/javac/lambda/8071432/T8071432.java	Thu Feb 19 11:24:07 2015 -0800
+++ b/test/tools/javac/lambda/8071432/T8071432.java	Thu Feb 19 16:38:54 2015 -0800
@@ -1,6 +1,6 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 8071432
+ * @bug 8071432 8069545
  * @summary structural most specific and stuckness
  * @compile/fail/ref=T8071432.out -XDrawDiagnostics T8071432.java
  */
--- a/test/tools/javac/resolve/tests/PrimitiveBinopOverload.java	Thu Feb 19 11:24:07 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-@TraceResolve
-class PrimitiveBinopOverload {
-
-    @Candidate(applicable=Phase.BASIC, mostSpecific=true)
-    int _plus(int x, int y) { return -1; }
-    @Candidate(applicable=Phase.BASIC)
-    long _plus(long x, long y) { return -1; }
-    @Candidate(applicable=Phase.BASIC)
-    float _plus(float x, float y) { return -1; }
-    @Candidate(applicable=Phase.BASIC)
-    double _plus(double x, double y) { return -1; }
-    //not a candidate
-    Object _plus(Object x, Object y) { return -1; }
-
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX }, mostSpecific=true)
-    int _minus(int x, int y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    long _minus(long x, long y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    float _minus(float x, float y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    double _minus(double x, double y) { return -1; }
-
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX }, mostSpecific=true)
-    int _mul(int x, int y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    long _mul(long x, long y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    float _mul(float x, float y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    double _mul(double x, double y) { return -1; }
-
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX }, mostSpecific=true)
-    int _div(int x, int y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    long _div(long x, long y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    float _div(float x, float y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    double _div(double x, double y) { return -1; }
-
-    {
-        int i1 = 1 + 1;
-        int i2 = 5 - new Integer(3);
-        int i3 = new Integer(5) * 3;
-        int i4 = new Integer(6) / new Integer(2);
-    }
-}