8010923: Avoid redundant speculative attribution

Mon, 15 Apr 2013 14:18:30 +0100

author
mcimadamore
date
Mon, 15 Apr 2013 14:18:30 +0100
changeset 1697
950e8ac120f0
parent 1696
c2315af9cc28
child 1698
49d32c84dfea

8010923: Avoid redundant speculative attribution
Summary: Add optimization to avoid speculative attribution for certain argument expressions
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Resolve.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeInfo.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Apr 15 14:17:30 2013 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Apr 15 14:18:30 2013 +0100
     1.3 @@ -148,6 +148,7 @@
     1.4          varInfo = new ResultInfo(VAR, Type.noType);
     1.5          unknownExprInfo = new ResultInfo(VAL, Type.noType);
     1.6          unknownTypeInfo = new ResultInfo(TYP, Type.noType);
     1.7 +        unknownTypeExprInfo = new ResultInfo(Kinds.TYP | Kinds.VAL, Type.noType);
     1.8          recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
     1.9      }
    1.10  
    1.11 @@ -559,6 +560,7 @@
    1.12      final ResultInfo varInfo;
    1.13      final ResultInfo unknownExprInfo;
    1.14      final ResultInfo unknownTypeInfo;
    1.15 +    final ResultInfo unknownTypeExprInfo;
    1.16      final ResultInfo recoveryInfo;
    1.17  
    1.18      Type pt() {
    1.19 @@ -667,7 +669,7 @@
    1.20      List<Type> attribArgs(List<JCExpression> trees, Env<AttrContext> env) {
    1.21          ListBuffer<Type> argtypes = new ListBuffer<Type>();
    1.22          for (JCExpression arg : trees) {
    1.23 -            Type argtype = allowPoly && TreeInfo.isPoly(arg, env.tree) ?
    1.24 +            Type argtype = allowPoly && deferredAttr.isDeferred(env, arg) ?
    1.25                      deferredAttr.new DeferredType(arg, env) :
    1.26                      chk.checkNonVoid(arg, attribExpr(arg, env, Infer.anyPoly));
    1.27              argtypes.append(argtype);
    1.28 @@ -2989,7 +2991,8 @@
    1.29          Env<AttrContext> localEnv = env.dup(tree);
    1.30          //should we propagate the target type?
    1.31          final ResultInfo castInfo;
    1.32 -        final boolean isPoly = TreeInfo.isPoly(tree.expr, tree);
    1.33 +        JCExpression expr = TreeInfo.skipParens(tree.expr);
    1.34 +        boolean isPoly = expr.hasTag(LAMBDA) || expr.hasTag(REFERENCE);
    1.35          if (isPoly) {
    1.36              //expression is a poly - we need to propagate target type info
    1.37              castInfo = new ResultInfo(VAL, clazztype, new Check.NestedCheckContext(resultInfo.checkContext) {
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Apr 15 14:17:30 2013 +0100
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Apr 15 14:18:30 2013 +0100
     2.3 @@ -800,4 +800,219 @@
     2.4              }
     2.5          }
     2.6      }
     2.7 +
     2.8 +    /**
     2.9 +     * Does the argument expression {@code expr} need speculative type-checking?
    2.10 +     */
    2.11 +    boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
    2.12 +        DeferredChecker dc = new DeferredChecker(env);
    2.13 +        dc.scan(expr);
    2.14 +        return dc.result.isPoly();
    2.15 +    }
    2.16 +
    2.17 +    /**
    2.18 +     * The kind of an argument expression. This is used by the analysis that
    2.19 +     * determines as to whether speculative attribution is necessary.
    2.20 +     */
    2.21 +    enum ArgumentExpressionKind {
    2.22 +
    2.23 +        /** kind that denotes poly argument expression */
    2.24 +        POLY,
    2.25 +        /** kind that denotes a standalone expression */
    2.26 +        NO_POLY,
    2.27 +        /** kind that denotes a primitive/boxed standalone expression */
    2.28 +        PRIMITIVE;
    2.29 +
    2.30 +        /**
    2.31 +         * Does this kind denote a poly argument expression
    2.32 +         */
    2.33 +        public final boolean isPoly() {
    2.34 +            return this == POLY;
    2.35 +        }
    2.36 +
    2.37 +        /**
    2.38 +         * Does this kind denote a primitive standalone expression
    2.39 +         */
    2.40 +        public final boolean isPrimitive() {
    2.41 +            return this == PRIMITIVE;
    2.42 +        }
    2.43 +
    2.44 +        /**
    2.45 +         * Compute the kind of a standalone expression of a given type
    2.46 +         */
    2.47 +        static ArgumentExpressionKind standaloneKind(Type type, Types types) {
    2.48 +            return types.unboxedTypeOrType(type).isPrimitive() ?
    2.49 +                    ArgumentExpressionKind.PRIMITIVE :
    2.50 +                    ArgumentExpressionKind.NO_POLY;
    2.51 +        }
    2.52 +
    2.53 +        /**
    2.54 +         * Compute the kind of a method argument expression given its symbol
    2.55 +         */
    2.56 +        static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
    2.57 +            Type restype = sym.type.getReturnType();
    2.58 +            if (sym.type.hasTag(FORALL) &&
    2.59 +                    restype.containsAny(((ForAll)sym.type).tvars)) {
    2.60 +                return ArgumentExpressionKind.POLY;
    2.61 +            } else {
    2.62 +                return ArgumentExpressionKind.standaloneKind(restype, types);
    2.63 +            }
    2.64 +        }
    2.65 +    }
    2.66 +
    2.67 +    /**
    2.68 +     * Tree scanner used for checking as to whether an argument expression
    2.69 +     * requires speculative attribution
    2.70 +     */
    2.71 +    final class DeferredChecker extends FilterScanner {
    2.72 +
    2.73 +        Env<AttrContext> env;
    2.74 +        ArgumentExpressionKind result;
    2.75 +
    2.76 +        public DeferredChecker(Env<AttrContext> env) {
    2.77 +            super(deferredCheckerTags);
    2.78 +            this.env = env;
    2.79 +        }
    2.80 +
    2.81 +        @Override
    2.82 +        public void visitLambda(JCLambda tree) {
    2.83 +            //a lambda is always a poly expression
    2.84 +            result = ArgumentExpressionKind.POLY;
    2.85 +        }
    2.86 +
    2.87 +        @Override
    2.88 +        public void visitReference(JCMemberReference tree) {
    2.89 +            //a method reference is always a poly expression
    2.90 +            result = ArgumentExpressionKind.POLY;
    2.91 +        }
    2.92 +
    2.93 +        @Override
    2.94 +        public void visitTypeCast(JCTypeCast tree) {
    2.95 +            //a cast is always a standalone expression
    2.96 +            result = ArgumentExpressionKind.NO_POLY;
    2.97 +        }
    2.98 +
    2.99 +        @Override
   2.100 +        public void visitConditional(JCConditional tree) {
   2.101 +            scan(tree.truepart);
   2.102 +            if (!result.isPrimitive()) {
   2.103 +                result = ArgumentExpressionKind.POLY;
   2.104 +                return;
   2.105 +            }
   2.106 +            scan(tree.falsepart);
   2.107 +            result = reduce(ArgumentExpressionKind.PRIMITIVE);
   2.108 +        }
   2.109 +
   2.110 +        @Override
   2.111 +        public void visitNewClass(JCNewClass tree) {
   2.112 +            result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
   2.113 +                    ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
   2.114 +        }
   2.115 +
   2.116 +        @Override
   2.117 +        public void visitApply(JCMethodInvocation tree) {
   2.118 +            Name name = TreeInfo.name(tree.meth);
   2.119 +
   2.120 +            //fast path
   2.121 +            if (tree.typeargs.nonEmpty() ||
   2.122 +                    name == name.table.names._this ||
   2.123 +                    name == name.table.names._super) {
   2.124 +                result = ArgumentExpressionKind.NO_POLY;
   2.125 +                return;
   2.126 +            }
   2.127 +
   2.128 +            //slow path
   2.129 +            final JCExpression rec = tree.meth.hasTag(SELECT) ?
   2.130 +                    ((JCFieldAccess)tree.meth).selected :
   2.131 +                    null;
   2.132 +
   2.133 +            if (rec != null && !isSimpleReceiver(rec)) {
   2.134 +                //give up if receiver is too complex (to cut down analysis time)
   2.135 +                result = ArgumentExpressionKind.POLY;
   2.136 +                return;
   2.137 +            }
   2.138 +
   2.139 +            Type site = rec != null ?
   2.140 +                    attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
   2.141 +                    env.enclClass.sym.type;
   2.142 +
   2.143 +            ListBuffer<Type> args = ListBuffer.lb();
   2.144 +            for (int i = 0; i < tree.args.length(); i ++) {
   2.145 +                args.append(Type.noType);
   2.146 +            }
   2.147 +
   2.148 +            Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args.toList(), List.<Type>nil(), MethodResolutionPhase.VARARITY) {
   2.149 +                @Override
   2.150 +                Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
   2.151 +                    return rec == null ?
   2.152 +                        rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
   2.153 +                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
   2.154 +                }
   2.155 +                @Override
   2.156 +                Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
   2.157 +                    return sym;
   2.158 +                }
   2.159 +            };
   2.160 +
   2.161 +            Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
   2.162 +
   2.163 +            if (sym.kind == Kinds.AMBIGUOUS) {
   2.164 +                Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
   2.165 +                result = ArgumentExpressionKind.PRIMITIVE;
   2.166 +                for (List<Symbol> ambigousSyms = err.ambiguousSyms ;
   2.167 +                        ambigousSyms.nonEmpty() && !result.isPoly() ;
   2.168 +                        ambigousSyms = ambigousSyms.tail) {
   2.169 +                    Symbol s = ambigousSyms.head;
   2.170 +                    if (s.kind == Kinds.MTH) {
   2.171 +                        result = reduce(ArgumentExpressionKind.methodKind(s, types));
   2.172 +                    }
   2.173 +                }
   2.174 +            } else {
   2.175 +                result = (sym.kind == Kinds.MTH) ?
   2.176 +                    ArgumentExpressionKind.methodKind(sym, types) :
   2.177 +                    ArgumentExpressionKind.NO_POLY;
   2.178 +            }
   2.179 +        }
   2.180 +        //where
   2.181 +            private boolean isSimpleReceiver(JCTree rec) {
   2.182 +                switch (rec.getTag()) {
   2.183 +                    case IDENT:
   2.184 +                        return true;
   2.185 +                    case SELECT:
   2.186 +                        return isSimpleReceiver(((JCFieldAccess)rec).selected);
   2.187 +                    case TYPEAPPLY:
   2.188 +                    case TYPEARRAY:
   2.189 +                        return true;
   2.190 +                    case ANNOTATED_TYPE:
   2.191 +                        return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
   2.192 +                    default:
   2.193 +                        return false;
   2.194 +                }
   2.195 +            }
   2.196 +            private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
   2.197 +                switch (result) {
   2.198 +                    case PRIMITIVE: return kind;
   2.199 +                    case NO_POLY: return kind.isPoly() ? kind : result;
   2.200 +                    case POLY: return result;
   2.201 +                    default:
   2.202 +                        Assert.error();
   2.203 +                        return null;
   2.204 +                }
   2.205 +            }
   2.206 +
   2.207 +        @Override
   2.208 +        public void visitLiteral(JCLiteral tree) {
   2.209 +            Type litType = attr.litType(tree.typetag);
   2.210 +            result = ArgumentExpressionKind.standaloneKind(litType, types);
   2.211 +        }
   2.212 +
   2.213 +        @Override
   2.214 +        void skip(JCTree tree) {
   2.215 +            result = ArgumentExpressionKind.NO_POLY;
   2.216 +        }
   2.217 +    }
   2.218 +    //where
   2.219 +    private EnumSet<JCTree.Tag> deferredCheckerTags =
   2.220 +            EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
   2.221 +                    CONDEXPR, NEWCLASS, APPLY, LITERAL);
   2.222  }
     3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Apr 15 14:17:30 2013 +0100
     3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Apr 15 14:18:30 2013 +0100
     3.3 @@ -3604,6 +3604,11 @@
     3.4          }
     3.5  
     3.6          @Override
     3.7 +        public Symbol baseSymbol() {
     3.8 +            return delegatedError.baseSymbol();
     3.9 +        }
    3.10 +
    3.11 +        @Override
    3.12          protected Symbol access(Name name, TypeSymbol location) {
    3.13              return delegatedError.access(name, location);
    3.14          }
     4.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Mon Apr 15 14:17:30 2013 +0100
     4.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Mon Apr 15 14:18:30 2013 +0100
     4.3 @@ -249,23 +249,6 @@
     4.4          }
     4.5      }
     4.6  
     4.7 -    /** Return true if a a tree corresponds to a poly expression. */
     4.8 -    public static boolean isPoly(JCTree tree, JCTree origin) {
     4.9 -        switch (tree.getTag()) {
    4.10 -            case APPLY:
    4.11 -            case NEWCLASS:
    4.12 -            case CONDEXPR:
    4.13 -                return !origin.hasTag(TYPECAST);
    4.14 -            case LAMBDA:
    4.15 -            case REFERENCE:
    4.16 -                return true;
    4.17 -            case PARENS:
    4.18 -                return isPoly(((JCParens)tree).expr, origin);
    4.19 -            default:
    4.20 -                return false;
    4.21 -        }
    4.22 -    }
    4.23 -
    4.24      /** set 'polyKind' on given tree */
    4.25      public static void setPolyKind(JCTree tree, PolyKind pkind) {
    4.26          switch (tree.getTag()) {

mercurial