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); }