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