javac: optimized for-each over RandomAccess List

Robert Stupp snazy at gmx.de
Wed Nov 6 22:55:16 UTC 2013


Hi,

is it ok to optimize for-each-loop code generation for instances of java.util.List that also implement java.util.RandomAccess by expanding to
        List lst$ = listexpr;
	int len$ = lst$.size();
	for (int i$ = 0 ; i$ < len$ ; i$++) {
		T loopvar = lst$.get(i$);
<LOOOP-BODY>
	}

I am not sure whether this would break existing code, that relies on Iterator. RandomAccess declares that access using size()+get(int) are faster than using an iterator.

The necessary modifications to com.sun.tools.javac.comp.Lower#visitForeachLoop may look like this:

    /** Translate away the foreach loop.  */
    public void visitForeachLoop(JCEnhancedForLoop tree) {
        if (types.elemtype(tree.expr.type) == null) {
            if (tree.var.vartype.type.contains(syms.listType) && tree.var.vartype.type.contains(syms.randomAccessType))
                visitRandomAccessListLoop(tree);
            else
                visitIterableForeachLoop(tree);
        }
        else
            visitArrayForeachLoop(tree);
    }
        // where
        /**
         * A statement of the form
         *
         * <pre>
         *     for ( T v : listexpr ) stmt;
         * </pre>
         *
         * (where listexpr is of an randomaccess-list type) gets translated to
         *
         * <pre>{@code
         *     for ( { listtype #lst = listexpr;
         *             int #len = lst.size();
         *             int #i = 0; };
         *           #i < #len; i$++ ) {
         *         T v = lst$.get(#i);
         *         stmt;
         *     }
         * }</pre>
         *
         * where #arr, #len, and #i are freshly named synthetic local variables.
         */
        private void visitRandomAccessListLoop(JCEnhancedForLoop tree) {
            make_at(tree.expr.pos());
            VarSymbol listcache = new VarSymbol(SYNTHETIC,
                    names.fromString("lst" + target.syntheticNameChar()),
                    tree.expr.type,
                    currentMethodSym);
            JCStatement listcachedef = make.VarDef(listcache, tree.expr);
            VarSymbol lencache = new VarSymbol(SYNTHETIC,
                    names.fromString("len" + target.syntheticNameChar()),
                    syms.intType,
                    currentMethodSym);
            Symbol size = lookupMethod(tree.expr.pos(),
                    names.size,
                    tree.expr.type,
                    List.<Type>nil());
            Symbol get = lookupMethod(tree.expr.pos(),
                    names.get,
                    tree.expr.type,
                    List.<Type>nil());
            JCStatement lencachedef = make.
                    VarDef(lencache,
                            make.App(make.Select(make.Ident(listcache), size)));
            VarSymbol index = new VarSymbol(SYNTHETIC,
                    names.fromString("i" + target.syntheticNameChar()),
                    syms.intType,
                    currentMethodSym);

            JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
            indexdef.init.type = indexdef.type = syms.intType.constType(0);

            List<JCStatement> loopinit = List.of(listcachedef, lencachedef, indexdef);
            JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache));

            JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index)));

            Type elemtype = types.elemtype(tree.expr.type);
            JCExpression loopvarinit =
                    make.App(make.Select(make.Ident(listcache), get), List.of(make.Ident(indexdef)));
            JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
                    tree.var.name,
                    tree.var.vartype,
                    loopvarinit).setType(tree.var.type);
            loopvardef.sym = tree.var.sym;
            JCBlock body = make.
                    Block(0, List.of(loopvardef, tree.body));

            result = translate(make.
                    ForLoop(loopinit,
                            cond,
                            List.of(step),
                            body));
            patchTargets(body, tree, result);
        }




More information about the core-libs-dev mailing list