Skip to content

Commit ff1979a

Browse files
authored
Preserve externally visible names during optimization (#1277)
1 parent c1173c9 commit ff1979a

15 files changed

Lines changed: 433 additions & 56 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/WurstChecker.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import de.peeeq.wurstscript.attributes.names.DesugarArrayLength;
88
import de.peeeq.wurstscript.gui.WurstGui;
99
import de.peeeq.wurstscript.validation.GlobalCaches;
10-
import de.peeeq.wurstscript.validation.TRVEHelper;
1110
import de.peeeq.wurstscript.validation.WurstValidator;
1211

1312
import java.util.ArrayList;
@@ -36,7 +35,6 @@ public void checkProg(WurstModel root, Collection<CompilationUnit> toCheck) {
3635
if (root.isEmpty()) {
3736
return;
3837
}
39-
TRVEHelper.protectedVariables.clear();
4038
new DesugarArrayLength().run(root);
4139
gui.sendProgress("Checking Files");
4240

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/GlobalsInliner.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import de.peeeq.wurstscript.translation.imtranslation.ImHelper;
77
import de.peeeq.wurstscript.translation.imtranslation.ImTranslator;
88
import de.peeeq.wurstscript.utils.Utils;
9-
import de.peeeq.wurstscript.validation.TRVEHelper;
9+
import de.peeeq.wurstscript.validation.NamePreservation;
1010
import org.jetbrains.annotations.Nullable;
1111

1212
import java.util.ArrayList;
@@ -47,8 +47,8 @@ public int optimize(ImTranslator trans) {
4747
// cannot optimize arrays yet
4848
continue;
4949
}
50-
if (TRVEHelper.protectedVariables.contains(v.getName())) {
51-
// keep TRVE vars
50+
if (NamePreservation.isPreserved(v)) {
51+
// keep names which are part of the external Warcraft III API
5252
continue;
5353
}
5454

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImCompressor.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,32 @@
55
import de.peeeq.wurstscript.jassIm.ImVar;
66
import de.peeeq.wurstscript.translation.imtranslation.ImHelper;
77
import de.peeeq.wurstscript.translation.imtranslation.ImTranslator;
8-
import de.peeeq.wurstscript.validation.TRVEHelper;
8+
import de.peeeq.wurstscript.validation.NamePreservation;
9+
10+
import java.util.HashSet;
11+
import java.util.Set;
912

1013
public class ImCompressor {
1114

1215
private final ImTranslator trans;
1316
private final ImProg prog;
1417
private final NameGenerator ng;
18+
private final Set<String> preservedNames = new HashSet<>();
1519

1620
public ImCompressor(ImTranslator translator) {
1721
this.trans = translator;
1822
this.prog = translator.getImProg();
1923
ng = new NameGenerator();
24+
for (ImVar global : prog.getGlobals()) {
25+
if (NamePreservation.isPreserved(global)) {
26+
preservedNames.add(global.getName());
27+
}
28+
}
29+
for (ImFunction function : ImHelper.calculateFunctionsOfProg(prog)) {
30+
if (NamePreservation.isPreserved(function)) {
31+
preservedNames.add(function.getName());
32+
}
33+
}
2034
}
2135

2236
public void compressNames() {
@@ -27,21 +41,21 @@ public void compressNames() {
2741

2842
public void compressGlobals() {
2943
for (final ImVar global : prog.getGlobals()) {
30-
if (global.getIsBJ() || TRVEHelper.protectedVariables.contains(global.getName())) {
31-
// do not rename bj constants
32-
// do not rename TRVE vars
44+
if (global.getIsBJ() || NamePreservation.isPreserved(global)) {
45+
// do not rename bj constants or names exposed to Warcraft III
3346
continue;
3447
}
3548

36-
String replacement = ng.getUniqueToken();
49+
String replacement = nextCompressedName();
3750

3851
global.setName(replacement);
3952
}
4053
}
4154

4255
public void compressFunctions() {
4356
for (ImFunction func : ImHelper.calculateFunctionsOfProg(prog)) {
44-
if (func.isNative() || func.isBj() || func.isCompiletime() || func.isExtern()) {
57+
if (func.isNative() || func.isBj() || func.isCompiletime() || func.isExtern()
58+
|| NamePreservation.isPreserved(func)) {
4559
// do not rename builtin an bj functions
4660
continue;
4761
}
@@ -50,12 +64,20 @@ public void compressFunctions() {
5064
// do not rename main and config functions
5165
continue;
5266
}
53-
String rname = ng.getUniqueToken();
67+
String rname = nextCompressedName();
5468
func.setName(rname);
5569
}
5670

5771
}
5872

73+
private String nextCompressedName() {
74+
String replacement;
75+
do {
76+
replacement = ng.getUniqueToken();
77+
} while (preservedNames.contains(replacement));
78+
return replacement;
79+
}
80+
5981
private void compressLocals(ImFunction func) {
6082
// TODO compressing locals should not use the global name pool but use a own pool
6183
for (ImVar local : func.getParameters()) {

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImOptimizer.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import de.peeeq.wurstscript.translation.imtranslation.ImTranslator;
1818
import de.peeeq.wurstscript.types.TypesHelper;
1919
import de.peeeq.wurstscript.utils.Pair;
20-
import de.peeeq.wurstscript.validation.TRVEHelper;
20+
import de.peeeq.wurstscript.validation.NamePreservation;
2121

2222
import java.util.stream.Collectors;
2323

@@ -174,13 +174,13 @@ public void visit(ImSet e) {
174174
super.visit(e);
175175
if (e.getLeft() instanceof ImVarAccess) {
176176
ImVarAccess va = (ImVarAccess) e.getLeft();
177-
if (!readVars.contains(va.getVar()) && !TRVEHelper.protectedVariables.contains(va.getVar().getName())) {
177+
if (!readVars.contains(va.getVar()) && !NamePreservation.isPreserved(va.getVar())) {
178178
List<ImExpr> sideEffects = collectSideEffects(e.getRight(), sideEffectAnalyzer);
179179
replacements.add(Pair.create(e, sideEffects));
180180
}
181181
} else if (e.getLeft() instanceof ImVarArrayAccess) {
182182
ImVarArrayAccess va = (ImVarArrayAccess) e.getLeft();
183-
if (!readVars.contains(va.getVar()) && !TRVEHelper.protectedVariables.contains(va.getVar().getName())) {
183+
if (!readVars.contains(va.getVar()) && !NamePreservation.isPreserved(va.getVar())) {
184184
List<ImExpr> exprs = new ArrayList<>();
185185
for (ImExpr index : va.getIndexes()) {
186186
exprs.addAll(collectSideEffects(index, sideEffectAnalyzer));
@@ -190,13 +190,13 @@ public void visit(ImSet e) {
190190
}
191191
} else if (e.getLeft() instanceof ImTupleSelection) {
192192
ImVar var = TypesHelper.getTupleVar((ImTupleSelection) e.getLeft());
193-
if(var != null && !readVars.contains(var) && !TRVEHelper.protectedVariables.contains(var.getName())) {
193+
if(var != null && !readVars.contains(var) && !NamePreservation.isPreserved(var)) {
194194
List<ImExpr> sideEffects = collectSideEffects(e.getRight(), sideEffectAnalyzer);
195195
replacements.add(Pair.create(e, sideEffects));
196196
}
197197
} else if(e.getLeft() instanceof ImMemberAccess) {
198198
ImMemberAccess va = ((ImMemberAccess) e.getLeft());
199-
if (!readVars.contains(va.getVar()) && !TRVEHelper.protectedVariables.contains(va.getVar().getName())) {
199+
if (!readVars.contains(va.getVar()) && !NamePreservation.isPreserved(va.getVar())) {
200200
List<ImExpr> sideEffects = collectSideEffects(e.getRight(), sideEffectAnalyzer);
201201
replacements.add(Pair.create(e, sideEffects));
202202
}

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtojass/ImToJassTranslator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import de.peeeq.wurstscript.translation.imoptimizer.RestrictedCompressedNames;
1010
import de.peeeq.wurstscript.translation.imtranslation.FunctionFlagEnum;
1111
import de.peeeq.wurstscript.translation.imtranslation.ImHelper;
12+
import de.peeeq.wurstscript.validation.NamePreservation;
1213
import de.peeeq.wurstscript.utils.Utils;
1314
import org.eclipse.jdt.annotation.Nullable;
1415

@@ -50,6 +51,11 @@ public JassProg translate() {
5051

5152
translateFunctionTransitive(mainFunc);
5253
translateFunctionTransitive(confFunction);
54+
for (ImFunction function : ImHelper.calculateFunctionsOfProg(imProg)) {
55+
if (NamePreservation.isPreserved(function)) {
56+
translateFunctionTransitive(function);
57+
}
58+
}
5359

5460
return prog;
5561
}

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ExprTranslation.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import de.peeeq.wurstscript.attributes.names.OtherLink;
1515
import de.peeeq.wurstscript.jassIm.*;
1616
import de.peeeq.wurstscript.types.*;
17+
import de.peeeq.wurstscript.validation.NamePreservation;
1718
import de.peeeq.wurstscript.utils.Utils;
1819
import io.vavr.control.Either;
1920
import io.vavr.control.Option;
@@ -588,6 +589,7 @@ private static ImExpr translateFunctionCall(FunctionCall e, ImTranslator t, ImFu
588589
String exFunc = s.getValS();
589590
NameLink func = Utils.getFirst(e.lookupFuncs(exFunc));
590591
ImFunction executedFunc = t.getFuncFor((TranslatedToImFunction) func.getDef());
592+
NamePreservation.preserve(executedFunc);
591593
return ImFunctionCall(e, executedFunc, ImTypeArguments(), JassIm.ImExprs(), true, CallType.EXECUTE);
592594
}
593595

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/FunctionFlagEnum.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public enum FunctionFlagEnum implements FunctionFlag {
66
IS_TEST,
77
IS_COMPILETIME_NATIVE,
88
IS_EXTERN,
9-
IS_VARARG
9+
IS_VARARG,
10+
PRESERVE_NAME
1011

11-
}
12+
}

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import de.peeeq.wurstscript.types.*;
2020
import de.peeeq.wurstscript.utils.Pair;
2121
import de.peeeq.wurstscript.utils.Utils;
22-
import de.peeeq.wurstscript.validation.TRVEHelper;
22+
import de.peeeq.wurstscript.validation.NamePreservation;
2323
import de.peeeq.wurstscript.validation.WurstValidator;
2424
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
2525
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
@@ -1067,6 +1067,9 @@ public ImFunction getFuncFor(TranslatedToImFunction funcDef) {
10671067
if (m instanceof Annotation) {
10681068
Annotation annotation = (Annotation) m;
10691069
flags.add(new FunctionFlagAnnotation(annotation.getAnnotationType()));
1070+
if (NamePreservation.isPreserveAnnotation(annotation.getAnnotationType())) {
1071+
flags.add(PRESERVE_NAME);
1072+
}
10701073
}
10711074
}
10721075
}
@@ -1462,13 +1465,18 @@ private void calculateCallRelationsAndVariables(boolean includeUsedVariables) {
14621465
final ImFunction conf = getConfFunc();
14631466
if (conf != null && conf != main) calculateCallRelations(conf, includeUsedVariables);
14641467

1465-
// mark protected globals as read
1466-
// TRVEHelper.protectedVariables is presumably a HashSet<String> (O(1) contains)
1467-
for (ImVar global : imProg.getGlobals()) {
1468-
if (TRVEHelper.protectedVariables.contains(global.getName())) {
1469-
readVariables.add(global);
1468+
// Preserved functions are externally visible entry points even when no Wurst code calls
1469+
// them. Keep their bodies and everything they call reachable for both backends.
1470+
for (ImFunction function : ImHelper.calculateFunctionsOfProg(imProg)) {
1471+
if (NamePreservation.isPreserved(function)) {
1472+
calculateCallRelations(function, includeUsedVariables);
14701473
}
14711474
}
1475+
1476+
// Mark externally visible globals as read so they survive garbage collection.
1477+
for (ImVar global : imProg.getGlobals()) {
1478+
if (NamePreservation.isPreserved(global)) readVariables.add(global);
1479+
}
14721480
}
14731481

14741482
private void calculateCallRelations(ImFunction rootFunction, boolean includeUsedVariables) {

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/LuaTranslator.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import de.peeeq.wurstscript.types.TypesHelper;
1515
import de.peeeq.wurstscript.utils.Lazy;
1616
import de.peeeq.wurstscript.utils.Utils;
17+
import de.peeeq.wurstscript.validation.NamePreservation;
1718

1819
import java.util.*;
1920
import java.util.stream.Collectors;
@@ -156,8 +157,10 @@ private static final class LazyArrayDefault {
156157
@Override
157158
public LuaVariable initFor(ImVar a) {
158159
String name = a.getName();
159-
if (!a.getIsBJ()) {
160+
if (!a.getIsBJ() && !NamePreservation.isPreserved(a)) {
160161
name = uniqueName(name);
162+
} else {
163+
usedNames.add(name);
161164
}
162165
return LuaAst.LuaVariable(name, LuaAst.LuaNoExpr());
163166
}
@@ -168,9 +171,10 @@ public LuaVariable initFor(ImVar a) {
168171
@Override
169172
public LuaFunction initFor(ImFunction a) {
170173
String name = a.getName();
171-
if (!a.isExtern() && !a.isBj() && !a.isNative() && !isFixedEntryPoint(a)) {
174+
if (!a.isExtern() && !a.isBj() && !a.isNative()
175+
&& !isFixedEntryPoint(a) && !NamePreservation.isPreserved(a)) {
172176
name = uniqueName(name);
173-
} else if (isFixedEntryPoint(a)) {
177+
} else if (isFixedEntryPoint(a) || NamePreservation.isPreserved(a)) {
174178
usedNames.add(name);
175179
}
176180

@@ -327,8 +331,8 @@ protected String uniqueName(String rawName) {
327331
}
328332

329333
public LuaCompilationUnit translate() {
330-
assertNoDanglingFunctionReferences(prog);
331334
collectPredefinedNames();
335+
assertNoDanglingFunctionReferences(prog);
332336

333337
normalizeFieldNames();
334338

@@ -488,7 +492,8 @@ private boolean isFixedEntryPoint(ImFunction function) {
488492

489493
private void collectPredefinedNames() {
490494
for (ImFunction function : prog.getFunctions()) {
491-
if (function.isBj() || function.isExtern() || function.isNative()) {
495+
if (function.isBj() || function.isExtern() || function.isNative()
496+
|| NamePreservation.isPreserved(function)) {
492497
// Don't rename Wurst-internal stubs (names starting with __wurst_)
493498
// since their names are intentionally different from their trace's source name.
494499
if (!function.getName().startsWith("__wurst_")) {
@@ -502,6 +507,8 @@ private void collectPredefinedNames() {
502507
if (global.getIsBJ()) {
503508
setNameFromTrace(global);
504509
usedNames.add(global.getName());
510+
} else if (NamePreservation.isPreserved(global)) {
511+
usedNames.add(global.getName());
505512
}
506513
}
507514
}

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/lua/translation/RemoveGarbage.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import de.peeeq.wurstscript.jassIm.*;
66
import de.peeeq.wurstscript.translation.imtranslation.ImHelper;
77
import de.peeeq.wurstscript.translation.imtranslation.ImTranslator;
8-
import de.peeeq.wurstscript.validation.TRVEHelper;
8+
import de.peeeq.wurstscript.validation.NamePreservation;
99

1010
import java.util.Collection;
1111
import java.util.Collections;
@@ -122,7 +122,7 @@ public static void removeGarbage(ImProg prog, ImTranslator translator) {
122122
Used used = collectUsed(prog, translator);
123123

124124
prog.getClasses().removeIf(c -> !used.getClasses().contains(c));
125-
prog.getGlobals().removeIf(g -> !used.getVars().contains(g) && !TRVEHelper.protectedVariables.contains(g.getName()));
125+
prog.getGlobals().removeIf(g -> !used.getVars().contains(g) && !NamePreservation.isPreserved(g));
126126
prog.getFunctions().removeIf(f -> !used.getFunctions().contains(f));
127127
prog.getMethods().removeIf(m -> !used.getMethods().contains(m));
128128
for (ImMethod m : prog.getMethods()) {
@@ -153,7 +153,8 @@ private static Used collectUsed(ImProg prog, ImTranslator translator,
153153
Used used = new Used(translator, ignoredInitializers);
154154
for (ImFunction f : ImHelper.calculateFunctionsOfProg(prog)) {
155155
if (f.getName().equals("main")
156-
|| f.getName().equals("config")) {
156+
|| f.getName().equals("config")
157+
|| NamePreservation.isPreserved(f)) {
157158
visitFunction(f, used);
158159
}
159160
}
@@ -221,7 +222,6 @@ private static void visitFunction(ImFunction f, Used used) {
221222
return;
222223
}
223224
used.addFunction(f);
224-
225225
visitType(f.getReturnType(), used);
226226
f.accept(new Element.DefaultVisitor() {
227227
@Override

0 commit comments

Comments
 (0)