| 1 | /* | 
| 2 |  * Copyright 2001-2006 Sun Microsystems, Inc.  All Rights Reserved. | 
| 3 |  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
| 4 |  * | 
| 5 |  * This code is free software; you can redistribute it and/or modify it | 
| 6 |  * under the terms of the GNU General Public License version 2 only, as | 
| 7 |  * published by the Free Software Foundation.  Sun designates this | 
| 8 |  * particular file as subject to the "Classpath" exception as provided | 
| 9 |  * by Sun in the LICENSE file that accompanied this code. | 
| 10 |  * | 
| 11 |  * This code is distributed in the hope that it will be useful, but WITHOUT | 
| 12 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
| 13 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
| 14 |  * version 2 for more details (a copy is included in the LICENSE file that | 
| 15 |  * accompanied this code). | 
| 16 |  * | 
| 17 |  * You should have received a copy of the GNU General Public License version | 
| 18 |  * 2 along with this work; if not, write to the Free Software Foundation, | 
| 19 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
| 20 |  * | 
| 21 |  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | 
| 22 |  * CA 95054 USA or visit www.sun.com if you need additional information or | 
| 23 |  * have any questions. | 
| 24 |  */ | 
| 25 |   | 
| 26 | package com.sun.tools.javac.util; | 
| 27 |   | 
| 28 | import com.sun.tools.javac.Main; | 
| 29 | import java.util.*; | 
| 30 |   | 
| 31 | /** | 
| 32 |  * Support for an abstract context, modelled loosely after ThreadLocal | 
| 33 |  * but using a user-provided context instead of the current thread. | 
| 34 |  * | 
| 35 |  * <p>Within the compiler, a single Context is used for each | 
| 36 |  * invocation of the compiler.  The context is then used to ensure a | 
| 37 |  * single copy of each compiler phase exists per compiler invocation. | 
| 38 |  * | 
| 39 |  * <p>The context can be used to assist in extending the compiler by | 
| 40 |  * extending its components.  To do that, the extended component must | 
| 41 |  * be registered before the base component.  We break initialization | 
| 42 |  * cycles by (1) registering a factory for the component rather than | 
| 43 |  * the component itself, and (2) a convention for a pattern of usage | 
| 44 |  * in which each base component registers itself by calling an | 
| 45 |  * instance method that is overridden in extended components.  A base | 
| 46 |  * phase supporting extension would look something like this: | 
| 47 |  * | 
| 48 |  * <p><pre> | 
| 49 |  * public class Phase { | 
| 50 |  *     protected static final Context.Key<Phase> phaseKey = | 
| 51 |  *         new Context.Key<Phase>(); | 
| 52 |  * | 
| 53 |  *     public static Phase instance(Context context) { | 
| 54 |  *         Phase instance = context.get(phaseKey); | 
| 55 |  *         if (instance == null) | 
| 56 |  *             // the phase has not been overridden | 
| 57 |  *             instance = new Phase(context); | 
| 58 |  *         return instance; | 
| 59 |  *     } | 
| 60 |  * | 
| 61 |  *     protected Phase(Context context) { | 
| 62 |  *         context.put(phaseKey, this); | 
| 63 |  *         // other intitialization follows... | 
| 64 |  *     } | 
| 65 |  * } | 
| 66 |  * </pre> | 
| 67 |  * | 
| 68 |  * <p>In the compiler, we simply use Phase.instance(context) to get | 
| 69 |  * the reference to the phase.  But in extensions of the compiler, we | 
| 70 |  * must register extensions of the phases to replace the base phase, | 
| 71 |  * and this must be done before any reference to the phase is accessed | 
| 72 |  * using Phase.instance().  An extended phase might be declared thus: | 
| 73 |  * | 
| 74 |  * <p><pre> | 
| 75 |  * public class NewPhase extends Phase { | 
| 76 |  *     protected NewPhase(Context context) { | 
| 77 |  *         super(context); | 
| 78 |  *     } | 
| 79 |  *     public static void preRegister(final Context context) { | 
| 80 |  *         context.put(phaseKey, new Context.Factory<Phase>() { | 
| 81 |  *             public Phase make() { | 
| 82 |  *                 return new NewPhase(context); | 
| 83 |  *             } | 
| 84 |  *         }); | 
| 85 |  *     } | 
| 86 |  * } | 
| 87 |  * </pre> | 
| 88 |  * | 
| 89 |  * <p>And is registered early in the extended compiler like this | 
| 90 |  * | 
| 91 |  * <p><pre> | 
| 92 |  *     NewPhase.preRegister(context); | 
| 93 |  * </pre> | 
| 94 |  * | 
| 95 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 96 |  *  you write code that depends on this, you do so at your own risk. | 
| 97 |  *  This code and its internal interfaces are subject to change or | 
| 98 |  *  deletion without notice.</b> | 
| 99 |  */ | 
| 100 | public class Context { | 
| 101 |     /** The client creates an instance of this class for each key. | 
| 102 |      */ | 
| 103 |     public static class Key<T> { | 
| 104 |         // note: we inherit identity equality from Object. | 
| 105 |     } | 
| 106 |   | 
| 107 |     /** | 
| 108 |      * The client can register a factory for lazy creation of the | 
| 109 |      * instance. | 
| 110 |      */ | 
| 111 |     public static interface Factory<T> { | 
| 112 |         T make(); | 
| 113 |     }; | 
| 114 |   | 
| 115 |     /** | 
| 116 |      * The underlying map storing the data. | 
| 117 |      * We maintain the invariant that this table contains only | 
| 118 |      * mappings of the form | 
| 119 |      * Key<T> -> T or Key<T> -> Factory<T> */ | 
| 120 |     private Map<Key,Object> ht = new HashMap<Key,Object>(); | 
| 121 |   | 
| 122 |     /** Set the factory for the key in this context. */ | 
| 123 |     public <T> void put(Key<T> key, Factory<T> fac) { | 
| 124 |         checkState(ht); | 
| 125 |         Object old = ht.put(key, fac); | 
| 126 |         if (old != null) | 
| 127 |             throw new AssertionError("duplicate context value"); | 
| 128 |     } | 
| 129 |   | 
| 130 |     /** Set the value for the key in this context. */ | 
| 131 |     public <T> void put(Key<T> key, T data) { | 
| 132 |         if (data instanceof Factory) | 
| 133 |             throw new AssertionError("T extends Context.Factory"); | 
| 134 |         checkState(ht); | 
| 135 |         Object old = ht.put(key, data); | 
| 136 |         if (old != null && !(old instanceof Factory) && old != data && data != null) | 
| 137 |             throw new AssertionError("duplicate context value"); | 
| 138 |     } | 
| 139 |   | 
| 140 |     /** Get the value for the key in this context. */ | 
| 141 |     public <T> T get(Key<T> key) { | 
| 142 |         checkState(ht); | 
| 143 |         Object o = ht.get(key); | 
| 144 |         if (o instanceof Factory) { | 
| 145 |             Factory fac = (Factory)o; | 
| 146 |             o = fac.make(); | 
| 147 |             if (o instanceof Factory) | 
| 148 |                 throw new AssertionError("T extends Context.Factory"); | 
| 149 |             assert ht.get(key) == o; | 
| 150 |         } | 
| 151 |   | 
| 152 |         /* The following cast can't fail unless there was | 
| 153 |          * cheating elsewhere, because of the invariant on ht. | 
| 154 |          * Since we found a key of type Key<T>, the value must | 
| 155 |          * be of type T. | 
| 156 |          */ | 
| 157 |         return Context.<T>uncheckedCast(o); | 
| 158 |     } | 
| 159 |   | 
| 160 |     public Context() {} | 
| 161 |   | 
| 162 |     private Map<Class<?>, Key<?>> kt = new HashMap<Class<?>, Key<?>>(); | 
| 163 |   | 
| 164 |     private <T> Key<T> key(Class<T> clss) { | 
| 165 |         checkState(kt); | 
| 166 |         Key<T> k = uncheckedCast(kt.get(clss)); | 
| 167 |         if (k == null) { | 
| 168 |             k = new Key<T>(); | 
| 169 |             kt.put(clss, k); | 
| 170 |         } | 
| 171 |         return k; | 
| 172 |     } | 
| 173 |   | 
| 174 |     public <T> T get(Class<T> clazz) { | 
| 175 |         return get(key(clazz)); | 
| 176 |     } | 
| 177 |   | 
| 178 |     public <T> void put(Class<T> clazz, T data) { | 
| 179 |         put(key(clazz), data); | 
| 180 |     } | 
| 181 |     public <T> void put(Class<T> clazz, Factory<T> fac) { | 
| 182 |         put(key(clazz), fac); | 
| 183 |     } | 
| 184 |   | 
| 185 |     /** | 
| 186 |      * TODO: This method should be removed and Context should be made type safe. | 
| 187 |      * This can be accomplished by using class literals as type tokens. | 
| 188 |      */ | 
| 189 |     @SuppressWarnings("unchecked") | 
| 190 |     private static <T> T uncheckedCast(Object o) { | 
| 191 |         return (T)o; | 
| 192 |     } | 
| 193 |   | 
| 194 |     public void dump() { | 
| 195 |         for (Object value : ht.values()) | 
| 196 |             System.err.println(value == null ? null : value.getClass()); | 
| 197 |     } | 
| 198 |   | 
| 199 |     public void clear() { | 
| 200 |         ht = null; | 
| 201 |         kt = null; | 
| 202 |     } | 
| 203 |   | 
| 204 |     private static void checkState(Map<?,?> t) { | 
| 205 |         if (t == null) | 
| 206 |             throw new IllegalStateException(); | 
| 207 |     } | 
| 208 | } |