/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.dev.jjs.impl.gflow.copy; import com.google.gwt.dev.jjs.ast.HasName; import com.google.gwt.dev.jjs.ast.JVariable; import com.google.gwt.dev.jjs.impl.gflow.Assumption; import com.google.gwt.dev.util.Preconditions; import com.google.gwt.dev.util.collect.Lists; import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; /** * Assumption class for CopyAnalysis. */ public class CopyAssumption implements Assumption<CopyAssumption> { /** * Top value for copy analysis. Means nothing is the copy of anything. */ public static final CopyAssumption TOP = new CopyAssumption(); /** * Updates the assumption by copying it on first write. */ public static class Updater { private CopyAssumption assumption; private boolean copied = false; public Updater(CopyAssumption assumption) { this.assumption = assumption; } public void addCopy(JVariable original, JVariable targetVariable) { Preconditions.checkArgument(original != targetVariable, "Variable is a copy of itself: %s", original); copyIfNeeded(); assumption.addCopy(original, targetVariable); } public JVariable getMostOriginal(JVariable variable) { for (int i = 0; i < 10000; ++i) { JVariable original = getOriginal(variable); if (original == null) { return variable; } variable = original; } // We shouldn't have cycle if we always call getMostOriginal() before // invoking addCopy. // This is a rudimentary cycle detection :) throw new IllegalStateException("Possible cycle detected for: variable"); } public JVariable getOriginal(JVariable variable) { if (assumption == null || assumption == TOP) { return null; } return assumption.getOriginal(variable); } public void kill(JVariable targetVariable) { if (assumption == TOP) { return; } copyIfNeeded(); assumption.kill(targetVariable); } public CopyAssumption unwrap() { if (assumption == TOP) { return assumption; } if (assumption != null && assumption.copyToOriginal.isEmpty()) { return null; } return assumption; } private void copyIfNeeded() { if (!copied) { assumption = new CopyAssumption(assumption); copied = true; } } } /** * Map from copies to original values. */ private final Map<JVariable, JVariable> copyToOriginal; public CopyAssumption() { copyToOriginal = new IdentityHashMap<JVariable, JVariable>(); } public CopyAssumption(CopyAssumption result) { if (result != null) { copyToOriginal = new IdentityHashMap<JVariable, JVariable>(result.copyToOriginal); } else { copyToOriginal = new IdentityHashMap<JVariable, JVariable>(); } } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } CopyAssumption other = (CopyAssumption) obj; return other.copyToOriginal.equals(copyToOriginal); } public JVariable getOriginal(JVariable v) { return copyToOriginal.get(v); } @Override public int hashCode() { return copyToOriginal.hashCode(); } public CopyAssumption join(CopyAssumption value) { if (value == null) { return this; } if (this == TOP || value == TOP) { return TOP; } if (value.copyToOriginal.isEmpty() || copyToOriginal.isEmpty()) { return null; } CopyAssumption result = new CopyAssumption(); for (JVariable v : copyToOriginal.keySet()) { JVariable original = copyToOriginal.get(v); if (original == value.copyToOriginal.get(v)) { result.copyToOriginal.put(v, original); } else { result.copyToOriginal.put(v, null); } } return result; } @Override public String toString() { if (this == TOP) { return "T"; } StringBuffer result = new StringBuffer(); result.append("{"); List<JVariable> variables = new ArrayList<JVariable>( copyToOriginal.keySet()); HasName.Util.sortByName(variables); for (JVariable variable : variables) { if (result.length() > 1) { result.append(", "); } result.append(variable.getName()); result.append(" = "); if (copyToOriginal.get(variable) == null) { result.append("T"); } else { result.append(copyToOriginal.get(variable).getName()); } } result.append("}"); return result.toString(); } private void addCopy(JVariable original, JVariable copy) { Preconditions.checkArgument(this != TOP); copyToOriginal.put(copy, original); } private void kill(JVariable variable) { copyToOriginal.put(variable, null); for (JVariable v : Lists.create(copyToOriginal.keySet())) { JVariable original = copyToOriginal.get(v); if (original == variable) { copyToOriginal.put(v, null); } } } }