/* * 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; import com.google.gwt.dev.jjs.Correlation.Axis; import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory; import com.google.gwt.dev.util.StringInterner; import com.google.gwt.dev.util.Util; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; /** * Describes where a SourceInfo's node came from. This class currently includes * only physical origin information, but could be extended to provide support * for source-Module and -Generators. * * TODO: rename this class to make it parallel to {@link SourceInfoCorrelation}? * * TODO: make this package-protected? */ public class SourceOrigin implements SourceInfo { private static class SourceOriginPos extends SourceOrigin { private final int endPos; private final int startPos; private SourceOriginPos(String location, int startLine, int startPos, int endPos) { super(location, startLine); this.startPos = startPos; this.endPos = endPos; } @Override public int getEndPos() { return endPos; } @Override public int getStartPos() { return startPos; } // super.equals and hashCode call getStartPos() and getEndPos(), // so there is no need to implement them in this subclass } public static final SourceOrigin UNKNOWN = new SourceOrigin("Unknown", 0) { private Object readResolve() { return UNKNOWN; } }; /** * Cache to reuse recently-created origins. This is very useful for JS nodes, * since {@link com.google.gwt.dev.js.JsParser} currently only provides line * numbers rather than character positions, so we get a lot of reuse there. We * get barely any reuse in the Java AST. Synchronized since several threads * could operate on it at once during parallel optimization phases. */ private static final Map<SourceOrigin, SourceOrigin> CANONICAL_SOURCE_ORIGINS = Collections .synchronizedMap(new LinkedHashMap<SourceOrigin, SourceOrigin>(150, 0.75f, true) { @Override protected boolean removeEldestEntry(Entry<SourceOrigin, SourceOrigin> eldest) { return size() > 100; } }); private static final Correlation[] NO_CORRELATIONS = new Correlation[0]; /** * Creates SourceOrigin nodes. */ public static SourceOrigin create(int startPos, int endPos, int startLine, String fileName) { if (startPos < 0 && endPos < 0) { return create(startLine, fileName); } return new SourceOriginPos(fileName, startLine, startPos, endPos); } /** * Creates SourceOrigin nodes. This factory method will attempt to provide * canonicalized instances of SourceOrigin objects. */ public static SourceOrigin create(int startLine, String fileName) { SourceOrigin newInstance = new SourceOrigin(fileName, startLine); SourceOrigin canonical = CANONICAL_SOURCE_ORIGINS.get(newInstance); assert canonical == null || (newInstance != canonical && newInstance.equals(canonical)); if (canonical != null) { return canonical; } else { CANONICAL_SOURCE_ORIGINS.put(newInstance, newInstance); return newInstance; } } // TODO: Add Module and Generator tracking private final String fileName; private final int startLine; private SourceOrigin(String location, int startLine) { this.fileName = StringInterner.get().intern(Util.stripJarPathPrefix(location)); this.startLine = startLine; } public void addCorrelation(Correlation c) { } @Override public boolean equals(Object o) { if (!(o instanceof SourceOrigin)) { return false; } SourceOrigin other = (SourceOrigin) o; return startLine == other.startLine && getEndPos() == other.getEndPos() && getStartPos() == other.getStartPos() && fileName.equals(other.fileName); } public Correlation getCorrelation(Axis axis) { return null; } public Correlation[] getCorrelations() { return NO_CORRELATIONS; } public CorrelationFactory getCorrelator() { return DummyCorrelationFactory.INSTANCE; } public int getEndPos() { return -1; } public String getFileName() { return fileName; } public SourceOrigin getOrigin() { return this; } public int getStartLine() { return startLine; } public int getStartPos() { return -1; } @Override public int hashCode() { return 2 + 13 * fileName.hashCode() + 17 * startLine + 29 * getStartPos() + 31 * getEndPos(); } public SourceInfo makeChild() { return this; } public SourceInfo makeChild(SourceOrigin origin) { return origin; } @Override public String toString() { return getFileName() + '(' + getStartLine() + ')'; } }