javac: optimized for-each over RandomAccess List
Vitaly Davidovich
vitalyd at gmail.com
Tue Nov 12 01:08:02 UTC 2013
You'd lose the concurrent mod checking that the iterator may do, which
would change behavior.
Vitaly
Sent from my phone
On Nov 11, 2013 1:12 PM, "Robert Stupp" <snazy at gmx.de> wrote:
> 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