001: /*
002: * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.util;
027:
028: import com.sun.tools.javac.Main;
029: import java.util.*;
030:
031: /**
032: * Support for an abstract context, modelled loosely after ThreadLocal
033: * but using a user-provided context instead of the current thread.
034: *
035: * <p>Within the compiler, a single Context is used for each
036: * invocation of the compiler. The context is then used to ensure a
037: * single copy of each compiler phase exists per compiler invocation.
038: *
039: * <p>The context can be used to assist in extending the compiler by
040: * extending its components. To do that, the extended component must
041: * be registered before the base component. We break initialization
042: * cycles by (1) registering a factory for the component rather than
043: * the component itself, and (2) a convention for a pattern of usage
044: * in which each base component registers itself by calling an
045: * instance method that is overridden in extended components. A base
046: * phase supporting extension would look something like this:
047: *
048: * <p><pre>
049: * public class Phase {
050: * protected static final Context.Key<Phase> phaseKey =
051: * new Context.Key<Phase>();
052: *
053: * public static Phase instance(Context context) {
054: * Phase instance = context.get(phaseKey);
055: * if (instance == null)
056: * // the phase has not been overridden
057: * instance = new Phase(context);
058: * return instance;
059: * }
060: *
061: * protected Phase(Context context) {
062: * context.put(phaseKey, this);
063: * // other intitialization follows...
064: * }
065: * }
066: * </pre>
067: *
068: * <p>In the compiler, we simply use Phase.instance(context) to get
069: * the reference to the phase. But in extensions of the compiler, we
070: * must register extensions of the phases to replace the base phase,
071: * and this must be done before any reference to the phase is accessed
072: * using Phase.instance(). An extended phase might be declared thus:
073: *
074: * <p><pre>
075: * public class NewPhase extends Phase {
076: * protected NewPhase(Context context) {
077: * super(context);
078: * }
079: * public static void preRegister(final Context context) {
080: * context.put(phaseKey, new Context.Factory<Phase>() {
081: * public Phase make() {
082: * return new NewPhase(context);
083: * }
084: * });
085: * }
086: * }
087: * </pre>
088: *
089: * <p>And is registered early in the extended compiler like this
090: *
091: * <p><pre>
092: * NewPhase.preRegister(context);
093: * </pre>
094: *
095: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
096: * you write code that depends on this, you do so at your own risk.
097: * This code and its internal interfaces are subject to change or
098: * deletion without notice.</b>
099: */
100: @Version("@(#)Context.java 1.27 07/05/05")
101: public class Context {
102: /** The client creates an instance of this class for each key.
103: */
104: public static class Key<T> {
105: // note: we inherit identity equality from Object.
106: }
107:
108: /**
109: * The client can register a factory for lazy creation of the
110: * instance.
111: */
112: public static interface Factory<T> {
113: T make();
114: };
115:
116: /**
117: * The underlying map storing the data.
118: * We maintain the invariant that this table contains only
119: * mappings of the form
120: * Key<T> -> T or Key<T> -> Factory<T> */
121: private Map<Key, Object> ht = new HashMap<Key, Object>();
122:
123: /** Set the factory for the key in this context. */
124: public <T> void put(Key<T> key, Factory<T> fac) {
125: checkState(ht);
126: Object old = ht.put(key, fac);
127: if (old != null)
128: throw new AssertionError("duplicate context value");
129: }
130:
131: /** Set the value for the key in this context. */
132: public <T> void put(Key<T> key, T data) {
133: if (data instanceof Factory)
134: throw new AssertionError("T extends Context.Factory");
135: checkState(ht);
136: Object old = ht.put(key, data);
137: if (old != null && !(old instanceof Factory) && old != data
138: && data != null)
139: throw new AssertionError("duplicate context value");
140: }
141:
142: /** Get the value for the key in this context. */
143: public <T> T get(Key<T> key) {
144: checkState(ht);
145: Object o = ht.get(key);
146: if (o instanceof Factory) {
147: Factory fac = (Factory) o;
148: o = fac.make();
149: if (o instanceof Factory)
150: throw new AssertionError("T extends Context.Factory");
151: assert ht.get(key) == o;
152: }
153:
154: /* The following cast can't fail unless there was
155: * cheating elsewhere, because of the invariant on ht.
156: * Since we found a key of type Key<T>, the value must
157: * be of type T.
158: */
159: return Context.<T> uncheckedCast(o);
160: }
161:
162: public Context() {
163: }
164:
165: private Map<Class<?>, Key<?>> kt = new HashMap<Class<?>, Key<?>>();
166:
167: private <T> Key<T> key(Class<T> clss) {
168: checkState(kt);
169: Key<T> k = uncheckedCast(kt.get(clss));
170: if (k == null) {
171: k = new Key<T>();
172: kt.put(clss, k);
173: }
174: return k;
175: }
176:
177: public <T> T get(Class<T> clazz) {
178: return get(key(clazz));
179: }
180:
181: public <T> void put(Class<T> clazz, T data) {
182: put(key(clazz), data);
183: }
184:
185: public <T> void put(Class<T> clazz, Factory<T> fac) {
186: put(key(clazz), fac);
187: }
188:
189: /**
190: * TODO: This method should be removed and Context should be made type safe.
191: * This can be accomplished by using class literals as type tokens.
192: */
193: @SuppressWarnings("unchecked")
194: private static <T> T uncheckedCast(Object o) {
195: return (T) o;
196: }
197:
198: public void dump() {
199: for (Object value : ht.values())
200: System.err.println(value == null ? null : value.getClass());
201: }
202:
203: public void clear() {
204: ht = null;
205: kt = null;
206: }
207:
208: private static void checkState(Map<?, ?> t) {
209: if (t == null)
210: throw new IllegalStateException();
211: }
212: }
|