Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class ILconstArray extends ILconstAbstract {
Expand Down Expand Up @@ -72,6 +74,13 @@ public ILconst get(int index) {
return v;
}

/** Returns the explicitly stored entries in deterministic index order. */
public List<Int2ObjectMap.Entry<ILconst>> entries() {
List<Int2ObjectMap.Entry<ILconst>> result = new ArrayList<>(values.int2ObjectEntrySet());
result.sort(java.util.Comparator.comparingInt(Int2ObjectMap.Entry::getIntKey));
return result;
}

private void checkIndex(int index) {
if (index < 0) {
throw new InterpreterException("Array index " + index + " was negative.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public class ProgramState extends State implements AutoCloseable {
private final Map<ImVar, ImClass> genericStaticOwner = new HashMap<>();

private final Object2ObjectOpenHashMap<String, ILconstArray> genericStaticArrays = new Object2ObjectOpenHashMap<>();
private final Set<String> modifiedGenericArrays = new HashSet<>();
private final Map<String, Set<List<Integer>>> modifiedGenericArrayIndexes = new HashMap<>();
private final Map<String, List<ImTypeArgument>> genericArrayTypeArguments = new HashMap<>();
private final IdentityHashMap<ImVar, Object2ObjectOpenHashMap<String, ILconst>> genericStaticVals = new IdentityHashMap<>();
private final Object2ObjectOpenHashMap<String, ILconst> genericStaticScalarVals = new Object2ObjectOpenHashMap<>();

Expand Down Expand Up @@ -762,6 +765,117 @@ protected ILconstArray getArray(ImVar v) {
return r;
}

@Override
public void setArrayVal(ImVar v, List<Integer> indexes, ILconst val) {
String key = genericStaticKey(v);
super.setArrayVal(v, indexes, val);
if (key != null) {
modifiedGenericArrays.add(key);
modifiedGenericArrayIndexes.computeIfAbsent(key, ignored -> new HashSet<>())
.add(Collections.unmodifiableList(new ArrayList<>(indexes)));
genericArrayTypeArguments.computeIfAbsent(key, ignored -> genericStaticTypeArguments(v));
}
}

private List<ImTypeArgument> genericStaticTypeArguments(ImVar v) {
ImClass owner = genericStaticOwner.get(v);
if (owner == null) {
return Collections.emptyList();
}

ImClassType receiver = currentReceiverInstantiationFor(owner);
if (receiver != null && receiver.getClassDef() == owner) {
return copyTypeArguments(receiver.getTypeArguments());
}

List<ImTypeArgument> result = new ArrayList<>();
for (ImTypeVar typeVar : owner.getTypeVariables()) {
ImType resolved = resolveType(JassIm.ImTypeVarRef(typeVar));
if (resolved instanceof ImTypeVarRef) {
return Collections.emptyList();
}
result.add(JassIm.ImTypeArgument(resolved, Collections.emptyMap()));
}
return result;
}

private static List<ImTypeArgument> copyTypeArguments(ImTypeArguments typeArguments) {
List<ImTypeArgument> result = new ArrayList<>(typeArguments.size());
for (ImTypeArgument typeArgument : typeArguments) {
result.add(typeArgument.copy());
}
return result;
}

/** Snapshot of an array's explicitly initialized entries for compiletime migration. */
public ILconstArray getArrayValue(ImVar v) {
return getArray(v);
Comment thread
Frotty marked this conversation as resolved.
}

public static final class ArrayState {
private final ILconstArray value;
private final List<ImTypeArgument> typeArguments;
private final boolean generic;
private final Set<List<Integer>> modifiedIndexes;

public ArrayState(ILconstArray value, List<ImTypeArgument> typeArguments) {
this(value, typeArguments, !typeArguments.isEmpty(), Collections.emptySet());
}

public ArrayState(ILconstArray value, List<ImTypeArgument> typeArguments, boolean generic) {
this(value, typeArguments, generic, Collections.emptySet());
}

public ArrayState(ILconstArray value, List<ImTypeArgument> typeArguments, boolean generic,
Set<List<Integer>> modifiedIndexes) {
this.value = value;
this.typeArguments = Collections.unmodifiableList(new ArrayList<>(typeArguments));
this.generic = generic;
Set<List<Integer>> indexSnapshot = new HashSet<>();
for (List<Integer> indexes : modifiedIndexes) {
indexSnapshot.add(Collections.unmodifiableList(new ArrayList<>(indexes)));
}
this.modifiedIndexes = Collections.unmodifiableSet(indexSnapshot);
}

public ILconstArray getValue() {
return value;
}

public List<ImTypeArgument> getTypeArguments() {
return typeArguments;
}

public boolean isGeneric() {
return generic;
}

public Set<List<Integer>> getModifiedIndexes() {
return modifiedIndexes;
}
}

public Collection<ArrayState> getArrayStates(ImVar v) {
String prefix = v.getName() + "|";
List<String> keys = new ArrayList<>(modifiedGenericArrays);
Collections.sort(keys);
List<ArrayState> result = new ArrayList<>();
for (String key : keys) {
if (key.startsWith(prefix)) {
ILconstArray value = genericStaticArrays.get(key);
if (value != null) {
result.add(new ArrayState(value,
genericArrayTypeArguments.getOrDefault(key, Collections.emptyList()), true,
modifiedGenericArrayIndexes.getOrDefault(key, Collections.emptySet())));
}
}
}
if (result.isEmpty() && genericStaticKey(v) == null) {
result.add(new ArrayState(getArray(v), Collections.emptyList(), false, getModifiedArrayIndexes(v)));
}
return result;
}


public Collection<ILconstObject> getAllObjects() {
List<ILconstObject> values = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.eclipse.jdt.annotation.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Lazily allocates internal maps ONLY when needed.
Expand All @@ -19,6 +24,7 @@ public abstract class State {
// in State:
private @Nullable Object2ObjectOpenHashMap<ImVar, ILconst> values;
private @Nullable Object2ObjectOpenHashMap<ImVar, ILconstArray> arrayValues;
private final Map<ImVar, Set<List<Integer>>> modifiedArrayIndexes = new IdentityHashMap<>();


private Object2ObjectOpenHashMap<ImVar, ILconst> ensureValues() {
Expand Down Expand Up @@ -77,13 +83,23 @@ static ILconstArray createArrayConstantFromType(ImType vType) {
}

public void setArrayVal(ImVar v, List<Integer> indexes, ILconst val) {
modifiedArrayIndexes.computeIfAbsent(v, ignored -> new HashSet<>())
.add(Collections.unmodifiableList(new ArrayList<>(indexes)));
ILconstArray ar = getArray(v);
for (int i = 0; i < indexes.size() - 1; i++) {
ar = (ILconstArray) ar.get(indexes.get(i));
}
ar.set(indexes.get(indexes.size() - 1), val);
}

public Set<ImVar> getModifiedArrays() {
return modifiedArrayIndexes.keySet();
}

public Set<List<Integer>> getModifiedArrayIndexes(ImVar v) {
return modifiedArrayIndexes.getOrDefault(v, Collections.emptySet());
}

public @Nullable ILconst getArrayVal(ImVar v, List<Integer> indexes) {
ILconstArray ar = getArray(v);
for (int i = 0; i < indexes.size() - 1; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public static void splitFunc(ImTranslator tr, ImFunction func) {
}

private void optimize() {
Preconditions.checkArgument(func.getTypeVariables().isEmpty(), "func must not be generic");
Preconditions.checkArgument(func.getParameters().isEmpty(), "func parameters must be empty");
Preconditions.checkArgument(func.getReturnType() instanceof ImVoid, "func must return void");
// run some basic optimizations first:
Expand All @@ -47,6 +46,10 @@ private void optimize() {
Set<ImVar> usedVars = UsedVariables.calculate(func);
func.getLocals().removeIf(v -> !usedVars.contains(v));
func.flatten(tr);
boolean generic = !func.getTypeVariables().isEmpty();
Preconditions.checkArgument(!generic || func.getLocals().isEmpty(),
"generic split functions must not have locals");
ImFunction genericTemplate = generic ? func.copyWithRefs() : null;
List<List<ImStmt>> splitResult = split(func.getBody().removeAll());

ImProg prog = tr.getImProg();
Expand All @@ -55,19 +58,29 @@ private void optimize() {

// create helper functions
List<ImFunction> helperFuncs = new ArrayList<>();
int statementOffset = 0;
for (int i = 0; i < splitResult.size(); i++) {
List<ImStmt> stmts = splitResult.get(i);
ImFunction helperFunc = JassIm.ImFunction(
func.getTrace(),
func.getName() + "_" + i,
JassIm.ImTypeVars(),
JassIm.ImVars(),
JassIm.ImVoid(),
JassIm.ImVars(),
JassIm.ImStmts(stmts),
Collections.emptyList()
);
ImFunction helperFunc;
if (generic) {
helperFunc = genericTemplate.copyWithRefs();
List<ImStmt> copiedStatements = helperFunc.getBody().removeAll();
helperFunc.getBody().addAll(copiedStatements.subList(statementOffset, statementOffset + stmts.size()));
helperFunc.setName(func.getName() + "_" + i);
} else {
helperFunc = JassIm.ImFunction(
func.getTrace(),
func.getName() + "_" + i,
JassIm.ImTypeVars(),
JassIm.ImVars(),
JassIm.ImVoid(),
JassIm.ImVars(),
JassIm.ImStmts(stmts),
Collections.emptyList()
);
}
helperFuncs.add(helperFunc);
statementOffset += stmts.size();
}
prog.getFunctions().addAll(helperFuncs);

Expand All @@ -76,14 +89,22 @@ private void optimize() {
func.getBody().add(JassIm.ImFunctionCall(
func.getTrace(),
helperFunc,
JassIm.ImTypeArguments(),
typeArgumentsForCurrentFunction(),
JassIm.ImExprs(),
false,
CallType.EXECUTE
));
}
}

private ImTypeArguments typeArgumentsForCurrentFunction() {
ImTypeArguments result = JassIm.ImTypeArguments();
for (ImTypeVar typeVar : func.getTypeVariables()) {
result.add(JassIm.ImTypeArgument(JassIm.ImTypeVarRef(typeVar), Collections.emptyMap()));
}
return result;
}

private List<List<ImStmt>> split(List<ImStmt> body) {
List<List<ImStmt>> result = new ArrayList<>();
int fuel = 0;
Expand Down
Loading
Loading