diff --git a/de.peeeq.wurstscript/build.gradle b/de.peeeq.wurstscript/build.gradle index 58c0cdd17..07246f7fe 100644 --- a/de.peeeq.wurstscript/build.gradle +++ b/de.peeeq.wurstscript/build.gradle @@ -98,8 +98,8 @@ dependencies { implementation "org.antlr:antlr4-runtime:4.13.1" // abstractsyntaxgen (available to IDE via compileOnly; used at runtime via astgen) - compileOnly 'com.github.peterzeller:abstractsyntaxgen:623da1c60f' - astgen 'com.github.peterzeller:abstractsyntaxgen:623da1c60f' + compileOnly 'com.github.peterzeller:abstractsyntaxgen:2b3d742e8a' + astgen 'com.github.peterzeller:abstractsyntaxgen:2b3d742e8a' // Tests diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java index c701803c3..d53385112 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalMerger.java @@ -22,12 +22,21 @@ public int optimize(ImTranslator trans, LocalPlayerContextAnalyzer analyzer) { ImProg prog = trans.getImProg(); localPlayerContextAnalyzer = analyzer; totalLocalsMerged = 0; - for (ImFunction func : de.peeeq.wurstscript.translation.imtranslation.ImHelper.calculateFunctionsOfProg(prog)) { + optimizeFunctions(prog.getFunctions()); + List classes = prog.getClasses(); + for (int i = 0; i < classes.size(); i++) { + optimizeFunctions(classes.get(i).getFunctions()); + } + return totalLocalsMerged; + } + + private void optimizeFunctions(List functions) { + for (int i = 0; i < functions.size(); i++) { + ImFunction func = functions.get(i); if (!func.isNative() && !func.isBj()) { optimizeFunc(func); } } - return totalLocalsMerged; } @Override @@ -54,21 +63,23 @@ private void mergeLocals(Map> livenessInfo, ImFunction func) ); queue.addAll(interference.keySet()); - List params = new ArrayList<>(func.getParameters()); - if (func.hasFlag(de.peeeq.wurstscript.translation.imtranslation.FunctionFlagEnum.IS_VARARG) && !params.isEmpty()) { - params.remove(params.size() - 1); + List colors = new ArrayList<>(func.getParameters()); + if (func.hasFlag(de.peeeq.wurstscript.translation.imtranslation.FunctionFlagEnum.IS_VARARG) && !colors.isEmpty()) { + colors.remove(colors.size() - 1); } queue.removeAll(func.getParameters()); - List colors = new ArrayList<>(params); Map merges = new LinkedHashMap<>(); while (!queue.isEmpty()) { ImVar v = queue.poll(); boolean merged = false; - for (ImVar color : colors) { - if (!canMerge(color.getType(), v.getType())) continue; + for (int colorIndex = 0; colorIndex < colors.size(); colorIndex++) { + ImVar color = colors.get(colorIndex); + if (!canMerge(color.getType(), v.getType())) { + continue; + } if (localPlayerContextAnalyzer != null && (localPlayerContextAnalyzer.isLocalPlayerDependent(v) || localPlayerContextAnalyzer.isLocalPlayerDependent(color))) { @@ -110,7 +121,9 @@ private static void applyMerges(ImFunction func, Map merges) { } @Override public void visit(ImVarargLoop varargLoop) { super.visit(varargLoop); - for (ImVarargLoopVar loopVar : varargLoop.getLoopVars()) { + List loopVars = varargLoop.getLoopVars(); + for (int i = 0; i < loopVars.size(); i++) { + ImVarargLoopVar loopVar = loopVars.get(i); ImVar m = merges.get(loopVar.getVar()); if (m != null) loopVar.setVar(m); } @@ -127,13 +140,20 @@ private static int removeUnusedLocals(ImFunction f) { @Override public void visit(ImVarArrayAccess vaa) { super.visit(vaa); used.add(vaa.getVar()); } @Override public void visit(ImVarargLoop loop) { super.visit(loop); - loop.getLoopVars().forEach(v -> used.add(v.getVar())); + for (int i = 0; i < loop.getLoopVars().size(); i++) { + used.add(loop.getLoopVars().get(i).getVar()); + } } }); - List locals = new ArrayList<>(f.getLocals()); + List locals = f.getLocals(); int before = locals.size(); List kept = new ArrayList<>(locals.size()); - for (ImVar v : locals) if (used.contains(v)) kept.add(v); + for (int i = 0; i < locals.size(); i++) { + ImVar v = locals.get(i); + if (used.contains(v)) { + kept.add(v); + } + } if (kept.size() != locals.size()) { f.getLocals().clear(); f.getLocals().addAll(kept); } return before - kept.size(); } @@ -183,7 +203,8 @@ private void eliminateDeadCode(Map> livenessInfo) { AstEdits.deleteStmt(s); // remove the dead assignment entirely } else { ImStmts block = JassIm.ImStmts(); - for (ImExpr e : raw) { + for (int i = 0; i < raw.size(); i++) { + ImExpr e = raw.get(i); // wrap expression as a statement; add a *copy* to avoid re-parenting conflicts block.add(ImHelper.statementExprVoid(e.copy())); } @@ -195,10 +216,22 @@ private void eliminateDeadCode(Map> livenessInfo) { private static void collectLhsSideEffects(ImLExpr lhs, List out) { if (lhs instanceof ImVarArrayAccess a) { - for (ImExpr idx : a.getIndexes()) if (hasSideEffects(idx)) out.add(idx); + ImExprs indexes = a.getIndexes(); + for (int i = 0; i < indexes.size(); i++) { + ImExpr idx = indexes.get(i); + if (hasSideEffects(idx)) { + out.add(idx); + } + } } else if (lhs instanceof ImMemberAccess m) { if (hasSideEffects(m.getReceiver())) out.add(m.getReceiver()); - for (ImExpr idx : m.getIndexes()) if (hasSideEffects(idx)) out.add(idx); + ImExprs indexes = m.getIndexes(); + for (int i = 0; i < indexes.size(); i++) { + ImExpr idx = indexes.get(i); + if (hasSideEffects(idx)) { + out.add(idx); + } + } } else if (lhs instanceof ImTupleSelection ts) { Element t = ts.getTupleExpr(); if (hasSideEffects(t)) out.add((ImExpr) t); @@ -255,7 +288,12 @@ public Map> calculateLiveness(ImFunction func) { @Override public void case_ImVarArrayAccess(ImVarArrayAccess e) { e.getIndexes().accept(me); } @Override public void case_ImMemberAccess(ImMemberAccess e) { e.getReceiver().accept(me); e.getIndexes().accept(me); } @Override public void case_ImStatementExpr(ImStatementExpr e) { e.getStatements().accept(me); ((ImLExpr) e.getExpr()).match(this); } - @Override public void case_ImTupleExpr(ImTupleExpr e) { for (ImExpr ex : e.getExprs()) ((ImLExpr) ex).match(this); } + @Override public void case_ImTupleExpr(ImTupleExpr e) { + ImExprs exprs = e.getExprs(); + for (int i = 0; i < exprs.size(); i++) { + ((ImLExpr) exprs.get(i)).match(this); + } + } }); } }); @@ -291,14 +329,16 @@ protected Collection getIncidentNodes(Node t) { for (int i = 0; i < N; i++) { in[i] = new ObjectOpenHashSet<>(); out[i] = new ObjectOpenHashSet<>(); } // 5. Iterate over SCCs in reverse topological order - for (List scc : sccs) { + for (int sccIndex = 0; sccIndex < sccs.size(); sccIndex++) { + List scc = sccs.get(sccIndex); if (scc.isEmpty()) continue; // Iterate within this SCC until a fixed point is reached for all its nodes. boolean changedInScc = true; while (changedInScc) { changedInScc = false; - for (Node u_node : scc) { + for (int uIndex = 0; uIndex < scc.size(); uIndex++) { + Node u_node = scc.get(uIndex); int u_idx = idx.getInt(u_node); // Recalculate OUT[u] from the IN sets of its successors. diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalPlayerContextAnalyzer.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalPlayerContextAnalyzer.java index 365fdf496..28e3b120d 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalPlayerContextAnalyzer.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/LocalPlayerContextAnalyzer.java @@ -1,7 +1,6 @@ package de.peeeq.wurstscript.intermediatelang.optimizer; import de.peeeq.wurstscript.jassIm.*; -import de.peeeq.wurstscript.translation.imtranslation.ImHelper; import java.util.ArrayDeque; import java.util.ArrayList; @@ -161,7 +160,17 @@ public boolean isLocalPlayerSource(ImFunction function) { private void analyze(ImProg prog) { sourceFacts.add(unknownDispatchSource); - for (ImFunction function : ImHelper.calculateFunctionsOfProg(prog)) { + analyzeFunctions(prog.getFunctions()); + List classes = prog.getClasses(); + for (int i = 0; i < classes.size(); i++) { + analyzeFunctions(classes.get(i).getFunctions()); + } + propagateFacts(); + } + + private void analyzeFunctions(List functions) { + for (int i = 0; i < functions.size(); i++) { + ImFunction function = functions.get(i); returnFact(function); useFact(function); if (isClientLocalValueSource(function)) { @@ -171,7 +180,6 @@ private void analyze(ImProg prog) { addDependency(function.getBody(), useFact(function)); } } - propagateFacts(); } private boolean methodReturnsLocalPlayerDependentValue(ImMethod method) { @@ -181,8 +189,9 @@ private boolean methodReturnsLocalPlayerDependentValue(ImMethod method) { if (localPlayerDependentReturns.contains(method.getImplementation())) { return true; } - for (ImMethod subMethod : method.getSubMethods()) { - if (methodReturnsLocalPlayerDependentValue(subMethod)) { + List subMethods = method.getSubMethods(); + for (int i = 0; i < subMethods.size(); i++) { + if (methodReturnsLocalPlayerDependentValue(subMethods.get(i))) { return true; } } @@ -259,9 +268,12 @@ private void indexElementAfterChildren(Element element, ImFunction owner, Object } else if (element instanceof ImMemberAccess) { addDependency(variableFact(((ImMemberAccess) element).getVar()), element); } else if (element instanceof ImVarargLoop) { + ImVarargLoop loop = (ImVarargLoop) element; ImVar varargParameter = varargParameter(owner); if (varargParameter != null) { - for (ImVarargLoopVar loopVar : ((ImVarargLoop) element).getLoopVars()) { + List loopVars = loop.getLoopVars(); + for (int i = 0; i < loopVars.size(); i++) { + ImVarargLoopVar loopVar = loopVars.get(i); addDependency(variableFact(varargParameter), variableFact(loopVar.getVar())); } } @@ -292,7 +304,8 @@ private void scheduleStatementSequence(ImStmts statements, Deque work) { List tasks = new ArrayList<>(statements.size()); Object continuationControl = controlContext; - for (ImStmt statement : statements) { + for (int i = 0; i < statements.size(); i++) { + ImStmt statement = statements.get(i); addDependency(statement, statements); tasks.add(new IndexTask(statement, continuationControl, false)); @@ -380,6 +393,8 @@ private void indexFunctionCall(ImFunctionCall call, ImFunction owner, Object con ImFunction called = call.getFunc(); addDependency(returnFact(called), call); addDependency(useFact(called), useFact(owner)); + List arguments = call.getArguments(); + List calledParameters = called.getParameters(); if (!called.isNative()) { addEnclosingControlDependency(controlContext, entryControlFact(called)); } @@ -388,19 +403,20 @@ private void indexFunctionCall(ImFunctionCall call, ImFunction owner, Object con addLocalPlayerSource(called); } - int fixedParameterCount = called.getParameters().size(); + int fixedParameterCount = calledParameters.size(); if (called.hasFlag(IS_VARARG) && fixedParameterCount > 0) { fixedParameterCount--; } - int positionalCount = Math.min(call.getArguments().size(), fixedParameterCount); + int argumentCount = arguments.size(); + int positionalCount = Math.min(argumentCount, fixedParameterCount); for (int i = 0; i < positionalCount; i++) { - addDependency(call.getArguments().get(i), - variableFact(called.getParameters().get(i))); + addDependency(arguments.get(i), + variableFact(calledParameters.get(i))); } ImVar varargParameter = varargParameter(called); if (varargParameter != null) { - for (int i = fixedParameterCount; i < call.getArguments().size(); i++) { - addDependency(call.getArguments().get(i), + for (int i = fixedParameterCount; i < argumentCount; i++) { + addDependency(arguments.get(i), variableFact(varargParameter)); } } @@ -425,14 +441,18 @@ private void indexMethodCall(ImMethodCall call, ImFunction owner, Object control addDependency(unknownDispatchSource, useFact(owner)); } + List arguments = call.getArguments(); for (ImFunction implementation : implementations) { addDependency(returnFact(implementation), call); addDependency(useFact(implementation), useFact(owner)); addEnclosingControlDependency(controlContext, entryControlFact(implementation)); - for (ImVar parameter : implementation.getParameters()) { - addDependency(call.getReceiver(), variableFact(parameter)); - for (ImExpr argument : call.getArguments()) { - addDependency(argument, variableFact(parameter)); + Element receiver = call.getReceiver(); + List parameters = implementation.getParameters(); + for (int i = 0; i < parameters.size(); i++) { + ImVar parameter = parameters.get(i); + addDependency(receiver, variableFact(parameter)); + for (int j = 0; j < arguments.size(); j++) { + addDependency(arguments.get(j), variableFact(parameter)); } } } @@ -487,8 +507,9 @@ private boolean collectMethodImplementations(ImMethod method, return method != null && method.getImplementation() != null; } implementations.add(method.getImplementation()); - for (ImMethod subMethod : method.getSubMethods()) { - if (!collectMethodImplementations(subMethod, implementations, visited)) { + List subMethods = method.getSubMethods(); + for (int i = 0; i < subMethods.size(); i++) { + if (!collectMethodImplementations(subMethods.get(i), implementations, visited)) { return false; } } @@ -508,9 +529,11 @@ private void forEachAssignedVariable(ImLExpr left, Consumer consumer) { forEachAssignedVariable((ImLExpr) tupleExpr, consumer); } } else if (left instanceof ImTupleExpr) { - for (ImExpr expr : ((ImTupleExpr) left).getExprs()) { - if (expr instanceof ImLExpr) { - forEachAssignedVariable((ImLExpr) expr, consumer); + ImExprs exprs = ((ImTupleExpr) left).getExprs(); + for (int i = 0; i < exprs.size(); i++) { + ImExpr expr = exprs.get(i); + if (expr instanceof ImLExpr lExpr) { + forEachAssignedVariable(lExpr, consumer); } } } else if (left instanceof ImStatementExpr) { @@ -539,8 +562,11 @@ private void propagateFacts() { } while (!worklist.isEmpty()) { Object fact = worklist.removeFirst(); - for (Object dependent : dependents.getOrDefault(fact, Collections.emptyList())) { - activateFact(dependent, worklist); + List factDependents = dependents.get(fact); + if (factDependents != null) { + for (int i = 0; i < factDependents.size(); i++) { + activateFact(factDependents.get(i), worklist); + } } } } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java index 5b37c05e3..99799890a 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/Flatten.java @@ -10,7 +10,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import static de.peeeq.wurstscript.jassIm.JassIm.*; @@ -136,7 +135,8 @@ public static class Result { public Result(List stmts, ImExpr expr) { Preconditions.checkArgument(expr.getParent() == null, "expression must not have a parent"); boolean b = true; - for (ImStmt s : stmts) { + for (int i = 0; i < stmts.size(); i++) { + ImStmt s = stmts.get(i); if (s.getParent() != null) { b = false; break; @@ -286,8 +286,8 @@ private static ImStmts flattenStatements(ImStmts statements, ImTranslator t, ImF } private static void flattenStatementsInto(List result, ImStmts statements, ImTranslator t, ImFunction f) { - for (ImStmt s : statements) { - s.flatten(t, f).intoStatements(result, t, f); + for (int i = 0; i < statements.size(); i++) { + statements.get(i).flatten(t, f).intoStatements(result, t, f); } } @@ -492,37 +492,54 @@ public static void flattenFunc(ImFunction f, ImTranslator translator) { public static void flattenProg(ImProg imProg, ImTranslator translator) { // Choose execution strategy based on flags and size + List classes = imProg.getClasses(); if (USE_PARALLEL_EXECUTION) { int total = imProg.getFunctions().size(); - for (ImClass c : imProg.getClasses()) { - total += c.getFunctions().size(); + for (int i = 0; i < classes.size(); i++) { + total += classes.get(i).getFunctions().size(); } if (total >= PARALLEL_THRESHOLD) { // Collect once for parallel traversal. List allFunctions = new ArrayList<>(total); - allFunctions.addAll(imProg.getFunctions()); - for (ImClass c : imProg.getClasses()) { - allFunctions.addAll(c.getFunctions()); + List functions = imProg.getFunctions(); + for (int i = 0; i < functions.size(); i++) { + allFunctions.add(functions.get(i)); + } + for (int i = 0; i < classes.size(); i++) { + List classFunctions = classes.get(i).getFunctions(); + for (int j = 0; j < classFunctions.size(); j++) { + allFunctions.add(classFunctions.get(j)); + } } allFunctions.parallelStream().forEach(f -> f.flatten(translator)); } else { - for (ImFunction f : imProg.getFunctions()) { - f.flatten(translator); + List functions = imProg.getFunctions(); + for (int i = 0; i < functions.size(); i++) { + ImFunction function = functions.get(i); + function.flatten(translator); } - for (ImClass c : imProg.getClasses()) { - for (ImFunction f : c.getFunctions()) { - f.flatten(translator); + for (int i = 0; i < classes.size(); i++) { + ImClass c = classes.get(i); + List classFunctions = c.getFunctions(); + for (int j = 0; j < classFunctions.size(); j++) { + ImFunction function = classFunctions.get(j); + function.flatten(translator); } } } } else { // Sequential processing avoids intermediate list/lambda overhead. - for (ImFunction f : imProg.getFunctions()) { - f.flatten(translator); + List functions = imProg.getFunctions(); + for (int i = 0; i < functions.size(); i++) { + ImFunction function = functions.get(i); + function.flatten(translator); } - for (ImClass c : imProg.getClasses()) { - for (ImFunction f : c.getFunctions()) { - f.flatten(translator); + for (int i = 0; i < classes.size(); i++) { + ImClass c = classes.get(i); + List classFunctions = c.getFunctions(); + for (int j = 0; j < classFunctions.size(); j++) { + ImFunction function = classFunctions.get(j); + function.flatten(translator); } } } @@ -665,9 +682,12 @@ public static Result flatten(ImVarargLoop s, ImTranslator translator, ImFunction } private static ImVarargLoopVars copyVarargLoopVars(ImVarargLoopVars loopVars) { - return JassIm.ImVarargLoopVars(loopVars.stream() - .map(v -> JassIm.ImVarargLoopVar(v.getVar())) - .collect(Collectors.toList())); + int n = loopVars.size(); + List copiedVars = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + copiedVars.add(JassIm.ImVarargLoopVar(loopVars.get(i).getVar())); + } + return JassIm.ImVarargLoopVars(copiedVars); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java index 015bd7da7..96a472617 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImHelper.java @@ -21,25 +21,40 @@ public class ImHelper { * rather than counting parameters. */ public static int flattenedJassArity(ImType type) { - if (type instanceof ImTupleType) { - return ((ImTupleType) type).getTypes().stream() - .mapToInt(ImHelper::flattenedJassArity) - .sum(); + if (type instanceof ImTupleType tupleType) { + int result = 0; + List types = tupleType.getTypes(); + for (int i = 0; i < types.size(); i++) { + result += flattenedJassArity(types.get(i)); + } + return result; } return 1; } public static Set calculateFunctionsOfProg(ImProg prog) { - Set allFunctions = new HashSet<>(prog.getFunctions()); - for(ImClass c : prog.getClasses()) { - allFunctions.addAll(c.getFunctions()); + ImFunctions functions = prog.getFunctions(); + ImClasses classes = prog.getClasses(); + int functionCount = functions.size(); + for (int i = 0; i < classes.size(); i++) { + functionCount += classes.get(i).getFunctions().size(); + } + Set allFunctions = HashSet.newHashSet(functionCount); + for (int i = 0; i < functions.size(); i++) { + allFunctions.add(functions.get(i)); + } + for (int i = 0; i < classes.size(); i++) { + ImFunctions classFunctions = classes.get(i).getFunctions(); + for (int j = 0; j < classFunctions.size(); j++) { + allFunctions.add(classFunctions.get(j)); + } } return allFunctions; } static void translateParameters(WParameters params, ImVars result, ImTranslator t) { - for (WParameter p : params) { - result.add(t.getVarFor(p)); + for (int i = 0; i < params.size(); i++) { + result.add(t.getVarFor(params.get(i))); } } @@ -58,8 +73,8 @@ public static ImType toArray(ImType t) { } public static void replaceVar(List stmts, final ImVar oldVar, final ImVar newVar) { - for (ImStmt s : stmts) { - replaceVar(s, oldVar, newVar); + for (int i = 0; i < stmts.size(); i++) { + replaceVar(stmts.get(i), oldVar, newVar); } } @@ -164,8 +179,9 @@ public ImExpr case_ImAnyType(ImAnyType at) { @Override public ImExpr case_ImTupleType(ImTupleType tt) { ImExprs res = JassIm.ImExprs(); - for (ImType it : tt.getTypes()) { - res.add(defaultValueForComplexType(it)); + List types = tt.getTypes(); + for (int i = 0; i < types.size(); i++) { + res.add(defaultValueForComplexType(types.get(i))); } return JassIm.ImTupleExpr(res); } diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LuaDispatchPreparation.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LuaDispatchPreparation.java index 0eb4dc0dd..f6b58dada 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LuaDispatchPreparation.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/LuaDispatchPreparation.java @@ -10,6 +10,7 @@ import de.peeeq.wurstscript.jassIm.ImFunction; import de.peeeq.wurstscript.jassIm.ImMethod; import de.peeeq.wurstscript.jassIm.ImProg; +import de.peeeq.wurstscript.jassIm.ImVar; import de.peeeq.wurstscript.jassIm.ImType; import de.peeeq.wurstscript.jassIm.ImTypeVarRef; import de.peeeq.wurstscript.jassIm.ImVars; @@ -45,19 +46,30 @@ public static void prepare(ImProg prog, ImTranslator tr) { private static List collectAllMethods(ImProg prog) { List methods = new ArrayList<>(); - for (ImClass c : prog.getClasses()) { - methods.addAll(c.getMethods()); + List classes = prog.getClasses(); + for (int i = 0; i < classes.size(); i++) { + ImClass c = classes.get(i); + List classMethods = c.getMethods(); + for (int j = 0; j < classMethods.size(); j++) { + methods.add(classMethods.get(j)); + } } methods.sort(Comparator.comparing(LuaDispatchPreparation::methodSortKey)); return methods; } private static void assignDispatchGroupKeys(List allMethods) { - Set knownMethods = new HashSet<>(allMethods); + Set knownMethods = HashSet.newHashSet(allMethods.size()); + for (int i = 0; i < allMethods.size(); i++) { + knownMethods.add(allMethods.get(i)); + } UnionFind unions = new UnionFind<>(); - for (ImMethod method : allMethods) { + for (int i = 0; i < allMethods.size(); i++) { + ImMethod method = allMethods.get(i); unions.find(method); - for (ImMethod subMethod : method.getSubMethods()) { + List subMethods = method.getSubMethods(); + for (int j = 0; j < subMethods.size(); j++) { + ImMethod subMethod = subMethods.get(j); if (knownMethods.contains(subMethod)) { unions.union(method, subMethod); } @@ -65,7 +77,8 @@ private static void assignDispatchGroupKeys(List allMethods) { } Map> grouped = new LinkedHashMap<>(); - for (ImMethod method : allMethods) { + for (int i = 0; i < allMethods.size(); i++) { + ImMethod method = allMethods.get(i); ImMethod root = unions.find(method); grouped.computeIfAbsent(root, ignored -> new ArrayList<>()).add(method); } @@ -73,7 +86,8 @@ private static void assignDispatchGroupKeys(List allMethods) { for (List group : grouped.values()) { Map> partitions = new LinkedHashMap<>(); group.sort(Comparator.comparing(LuaDispatchPreparation::methodSortKey)); - for (ImMethod method : group) { + for (int j = 0; j < group.size(); j++) { + ImMethod method = group.get(j); partitions.computeIfAbsent(dispatchSignatureKey(method), ignored -> new ArrayList<>()).add(method); } for (List partition : partitions.values()) { @@ -82,7 +96,8 @@ private static void assignDispatchGroupKeys(List allMethods) { continue; } String key = methodSortKey(partition.get(0)) + "|" + dispatchSignatureKey(partition.get(0)); - for (ImMethod method : partition) { + for (int k = 0; k < partition.size(); k++) { + ImMethod method = partition.get(k); method.setLuaDispatchGroupKey(key); } } @@ -94,12 +109,14 @@ private static void normalizeMethodNames(ImProg prog, List allMethods, collectPredefinedNames(prog, usedNames); Map> groupedMethods = new TreeMap<>(); - for (ImMethod method : allMethods) { + for (int i = 0; i < allMethods.size(); i++) { + ImMethod method = allMethods.get(i); groupedMethods.computeIfAbsent(method.getLuaDispatchGroupKey(), ignored -> new ArrayList<>()).add(method); } List> groups = new ArrayList<>(groupedMethods.values()); groups.sort(Comparator.comparing(g -> g.isEmpty() ? "" : methodSortKey(g.get(0)))); - for (List group : groups) { + for (int i = 0; i < groups.size(); i++) { + List group = groups.get(i); if (group.isEmpty()) { continue; } @@ -113,7 +130,8 @@ private static void normalizeMethodNames(ImProg prog, List allMethods, // whose own name appears nowhere in it - which is why no method can work this out for // itself afterwards. String segment = segmentOf(name, group.get(0)); - for (ImMethod method : group) { + for (int j = 0; j < group.size(); j++) { + ImMethod method = group.get(j); method.setName(name); tr.recordDispatchSegment(method, segment); } @@ -127,7 +145,8 @@ private static void assignDispatchAliases(ImProg prog, List allMethods Set ambiguousDirectAliases = ambiguousDirectAliases(allMethods, tr); - for (ImMethod method : allMethods) { + for (int i = 0; i < allMethods.size(); i++) { + ImMethod method = allMethods.get(i); TreeSet aliases = new TreeSet<>(); addDirectAliases(method, aliases, ambiguousDirectAliases, tr); addHierarchyAliases(method, aliases, sortedMethodsByClass, tr); @@ -137,16 +156,20 @@ private static void assignDispatchAliases(ImProg prog, List allMethods } private static void collectPredefinedNames(ImProg prog, Set usedNames) { - prog.getFunctions().forEach(function -> { + List functions = prog.getFunctions(); + for (int i = 0; i < functions.size(); i++) { + ImFunction function = functions.get(i); if (function.isBj() || function.isExtern() || function.isNative()) { usedNames.add(function.getName()); } - }); - prog.getGlobals().forEach(global -> { + } + List globals = prog.getGlobals(); + for (int i = 0; i < globals.size(); i++) { + ImVar global = globals.get(i); if (global.getIsBJ()) { usedNames.add(global.getName()); } - }); + } } private static String uniqueName(String name, Set usedNames) { @@ -172,7 +195,8 @@ private static String uniqueName(String name, Set usedNames) { private static Set ambiguousDirectAliases(List allMethods, ImTranslator tr) { Map claimedBy = new LinkedHashMap<>(); Set ambiguous = new HashSet<>(); - for (ImMethod method : allMethods) { + for (int i = 0; i < allMethods.size(); i++) { + ImMethod method = allMethods.get(i); String composed = directAliasFor(method, tr); if (composed == null) { continue; @@ -246,7 +270,9 @@ private static void collectHierarchyAliases(ImClass c, ImMethod method, String d if (c == null || !visited.add(c)) { return; } - for (ImMethod candidate : sortedMethodsForClass(c, sortedMethodsByClass)) { + List candidates = sortedMethodsForClass(c, sortedMethodsByClass); + for (int i = 0; i < candidates.size(); i++) { + ImMethod candidate = candidates.get(i); if (!dispatchKey.equals(dispatchParameterSignatureKey(candidate))) { continue; } @@ -262,7 +288,9 @@ private static void collectHierarchyAliases(ImClass c, ImMethod method, String d aliases.add(c.getName() + "_" + candidateName); } } - for (ImClassType sc : c.getSuperClasses()) { + List superClasses = c.getSuperClasses(); + for (int i = 0; i < superClasses.size(); i++) { + ImClassType sc = superClasses.get(i); collectHierarchyAliases(sc.getClassDef(), method, dispatchKey, semanticNames, aliases, sortedMethodsByClass, visited, tr); } } @@ -281,8 +309,12 @@ private static void addClosureFamilyAliases(ImProg prog, ImMethod method, Set candidateClasses = closureFamilyClassesForAnchor(prog, anchor, closureFamilyClassesByAnchor); + for (int j = 0; j < candidateClasses.size(); j++) { + ImClass candidateClass = candidateClasses.get(j); + List candidates = sortedMethodsForClass(candidateClass, sortedMethodsByClass); + for (int k = 0; k < candidates.size(); k++) { + ImMethod candidate = candidates.get(k); if (!runtimeKey.equals(closureRuntimeDispatchKey(candidate))) { continue; } @@ -377,7 +409,9 @@ private static void collectClosureFamilyAnchors(ImClass c, Set anchors, if (!isClosureGeneratedClass(c)) { anchors.add(c); } - for (ImClassType sc : c.getSuperClasses()) { + List superClasses = c.getSuperClasses(); + for (int i = 0; i < superClasses.size(); i++) { + ImClassType sc = superClasses.get(i); collectClosureFamilyAnchors(sc.getClassDef(), anchors, visited); } } @@ -385,7 +419,9 @@ private static void collectClosureFamilyAnchors(ImClass c, Set anchors, private static List closureFamilyClassesForAnchor(ImProg prog, ImClass anchor, Map> cache) { return cache.computeIfAbsent(anchor, a -> { List result = new ArrayList<>(); - for (ImClass candidate : prog.getClasses()) { + List classes = prog.getClasses(); + for (int i = 0; i < classes.size(); i++) { + ImClass candidate = classes.get(i); if (sharesClosureFamilyAnchor(candidate, a, new HashSet<>())) { result.add(candidate); } @@ -402,7 +438,9 @@ private static boolean sharesClosureFamilyAnchor(ImClass c, ImClass anchor, Set< if (c == anchor) { return true; } - for (ImClassType sc : c.getSuperClasses()) { + List superClasses = c.getSuperClasses(); + for (int i = 0; i < superClasses.size(); i++) { + ImClassType sc = superClasses.get(i); if (sharesClosureFamilyAnchor(sc.getClassDef(), anchor, visited)) { return true; } @@ -517,7 +555,9 @@ private static boolean reaches(ImMethod current, ImMethod target, Set if (current == target) { return true; } - for (ImMethod subMethod : current.getSubMethods()) { + List subMethods = current.getSubMethods(); + for (int i = 0; i < subMethods.size(); i++) { + ImMethod subMethod = subMethods.get(i); if (reaches(subMethod, target, visited)) { return true; } @@ -558,7 +598,8 @@ private static ImFunction resolveDispatchSignatureImplementation(ImMethod method } List subMethods = new ArrayList<>(method.getSubMethods()); subMethods.sort(Comparator.comparing(LuaDispatchPreparation::methodSortKey)); - for (ImMethod subMethod : subMethods) { + for (int i = 0; i < subMethods.size(); i++) { + ImMethod subMethod = subMethods.get(i); ImFunction resolved = resolveDispatchSignatureImplementation(subMethod, visited); if (resolved != null) { return resolved; diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/RemoveGarbage.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/RemoveGarbage.java index 0781c22ec..bf412d3ed 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/RemoveGarbage.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/RemoveGarbage.java @@ -3,7 +3,6 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import de.peeeq.wurstscript.jassIm.*; -import de.peeeq.wurstscript.translation.imtranslation.ImHelper; import de.peeeq.wurstscript.translation.imtranslation.ImTranslator; import de.peeeq.wurstscript.validation.NamePreservation; @@ -98,11 +97,13 @@ public boolean addClass(ImClass c, boolean dispatchReachable) { } if (newDispatchClass) { Collection imMethods = waitingMethods.get(c); - Iterator it = imMethods.iterator(); - while (it.hasNext()) { - ImMethod m = it.next(); - visitMethod(m, this); - it.remove(); + // This is a HashMultimap set view, not an indexed list. Keep the one iterator: + // taking an array snapshot here allocates one entry for every waiting method. + Iterator iterator = imMethods.iterator(); + while (iterator.hasNext()) { + ImMethod method = iterator.next(); + visitMethod(method, this); + iterator.remove(); } } return newClass || newDispatchClass; @@ -112,8 +113,9 @@ public void addInstantiatedClass(ImClass c) { if (!instantiatedClasses.add(c)) { return; } - for (ImClassType superClass : c.getSuperClasses()) { - addInstantiatedClass(superClass.getClassDef()); + List superClasses = c.getSuperClasses(); + for (int i = 0; i < superClasses.size(); i++) { + addInstantiatedClass(superClasses.get(i).getClassDef()); } } } @@ -125,20 +127,24 @@ public static void removeGarbage(ImProg prog, ImTranslator translator) { prog.getGlobals().removeIf(g -> !used.getVars().contains(g) && !NamePreservation.isPreserved(g)); prog.getFunctions().removeIf(f -> !used.getFunctions().contains(f)); prog.getMethods().removeIf(m -> !used.getMethods().contains(m)); - for (ImMethod m : prog.getMethods()) { - m.getSubMethods().removeIf(sm -> !used.getMethods().contains(sm)); + List methods = prog.getMethods(); + for (int i = 0; i < methods.size(); i++) { + methods.get(i).getSubMethods().removeIf(sm -> !used.getMethods().contains(sm)); } // A field of a specialised class is a copy which nothing refers to, an access made before // specialisation still naming the original's variable. It is live exactly when the field it // was copied from is; dropping it leaves an instance of the specialised class allocated with // no fields at all while the emitted code goes on reading them. - for (ImClass c : prog.getClasses()) { + List classes = prog.getClasses(); + for (int i = 0; i < classes.size(); i++) { + ImClass c = classes.get(i); c.getFields().removeIf(g -> !used.getVars().contains(g) && !used.getVars().contains(translator.canonical(g))); c.getFunctions().removeIf(f -> !used.getFunctions().contains(f)); c.getMethods().removeIf(m -> !used.getMethods().contains(m)); - for (ImMethod m : c.getMethods()) { - m.getSubMethods().removeIf(sm -> !used.getMethods().contains(sm)); + List classMethods = c.getMethods(); + for (int j = 0; j < classMethods.size(); j++) { + classMethods.get(j).getSubMethods().removeIf(sm -> !used.getMethods().contains(sm)); } } @@ -151,19 +157,30 @@ private static Used collectUsed(ImProg prog, ImTranslator translator) { private static Used collectUsed(ImProg prog, ImTranslator translator, Set ignoredInitializers) { Used used = new Used(translator, ignoredInitializers); - for (ImFunction f : ImHelper.calculateFunctionsOfProg(prog)) { + visitRootFunctions(prog.getFunctions(), used); + List classes = prog.getClasses(); + for (int i = 0; i < classes.size(); i++) { + visitRootFunctions(classes.get(i).getFunctions(), used); + } + return used; + } + + private static void visitRootFunctions(List functions, Used used) { + for (int i = 0; i < functions.size(); i++) { + ImFunction f = functions.get(i); if (f.getName().equals("main") || f.getName().equals("config") || NamePreservation.isPreserved(f)) { visitFunction(f, used); } } - return used; } public static void removePhantomGenericStaticInitializers(ImProg prog, ImTranslator translator) { Map> candidates = new LinkedHashMap<>(); - for (ImVar global : prog.getGlobals()) { + List globals = prog.getGlobals(); + for (int i = 0; i < globals.size(); i++) { + ImVar global = globals.get(i); ImTranslator.Specialisation specialization = translator.specialisationOf(global); if (specialization != null && specialization.original() instanceof ImVar original && translator.genericStaticOwnerOf(original) != null) { @@ -184,7 +201,10 @@ public static void removePhantomGenericStaticInitializers(ImProg prog, ImTransla Set ignored = Collections.newSetFromMap(new IdentityHashMap<>()); for (Map.Entry> candidate : candidates.entrySet()) { if (!liveOriginals.contains(candidate.getKey())) { - ignored.addAll(candidate.getValue()); + List initializers = candidate.getValue(); + for (int i = 0; i < initializers.size(); i++) { + ignored.add(initializers.get(i)); + } } } Used used = collectUsed(prog, translator, ignored); @@ -205,7 +225,9 @@ public static void removePhantomGenericStaticInitializers(ImProg prog, ImTransla continue; } prog.getGlobalInits().remove(candidate.getKey()); - for (ImSet initializer : candidate.getValue()) { + List initSetters = candidate.getValue(); + for (int j = 0; j < initSetters.size(); j++) { + ImSet initializer = initSetters.get(j); if (initializer.getParent() == null) { continue; } @@ -322,8 +344,9 @@ private static void visitMethod(ImMethod m, Used used) { // abstract methods can have no implementation visitFunction(m.getImplementation(), used); } - for (ImMethod subMethod : m.getSubMethods()) { - used.maybeVisitMethod(subMethod); + List subMethods = m.getSubMethods(); + for (int i = 0; i < subMethods.size(); i++) { + used.maybeVisitMethod(subMethods.get(i)); } } @@ -335,8 +358,9 @@ private static void visitClass(ImClass c, Used used, boolean dispatchReachable) if (!used.addClass(c, dispatchReachable)) { return; } - for (ImClassType superClass : c.getSuperClasses()) { - visitClass(superClass.getClassDef(), used, dispatchReachable); + List superClasses = c.getSuperClasses(); + for (int i = 0; i < superClasses.size(); i++) { + visitClass(superClasses.get(i).getClassDef(), used, dispatchReachable); } } @@ -350,8 +374,9 @@ public void case_ImAnyType(ImAnyType imAnyType) { @Override public void case_ImTupleType(ImTupleType tt) { - for (ImType type : tt.getTypes()) { - visitType(type, used); + List types = tt.getTypes(); + for (int i = 0; i < types.size(); i++) { + visitType(types.get(i), used); } } @@ -378,8 +403,9 @@ public void case_ImArrayTypeMulti(ImArrayTypeMulti tt) { @Override public void case_ImClassType(ImClassType tt) { visitClass(tt.getClassDef(), used, false); - for (ImTypeArgument ta : tt.getTypeArguments()) { - visitType(ta.getType(), used); + List tArgs = tt.getTypeArguments(); + for (int i = 0; i < tArgs.size(); i++) { + visitType(tArgs.get(i).getType(), used); } }