001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino code, released
017: * May 6, 1999.
018: *
019: * The Initial Developer of the Original Code is
020: * Netscape Communications Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Igor Bukanov, igor@fastmail.fm
026: * Norris Boyd
027: *
028: * Alternatively, the contents of this file may be used under the terms of
029: * the GNU General Public License Version 2 or later (the "GPL"), in which
030: * case the provisions of the GPL are applicable instead of those above. If
031: * you wish to allow use of your version of this file only under the terms of
032: * the GPL and not to allow others to use your version of this file under the
033: * MPL, indicate your decision by deleting the provisions above and replacing
034: * them with the notice and other provisions required by the GPL. If you do
035: * not delete the provisions above, a recipient may use your version of this
036: * file under either the MPL or the GPL.
037: *
038: * ***** END LICENSE BLOCK ***** */
039:
040: package org.mozilla.javascript;
041:
042: import java.util.Map;
043: import java.util.HashMap;
044:
045: /**
046: * Cache of generated classes and data structures to access Java runtime
047: * from JavaScript.
048: *
049: * @author Igor Bukanov
050: *
051: * @since Rhino 1.5 Release 5
052: */
053: public class ClassCache {
054: private static final Object AKEY = new Object();
055: private volatile boolean cachingIsEnabled = true;
056: private HashMap<Class<?>, JavaMembers> classTable = new HashMap<Class<?>, JavaMembers>();
057: private HashMap<Class<?>, JavaMembers> javaAdapterGeneratedClasses = new HashMap<Class<?>, JavaMembers>();
058: private HashMap<JavaAdapter.JavaAdapterSignature, Class<?>> classAdapterCache = new HashMap<JavaAdapter.JavaAdapterSignature, Class<?>>();
059: private HashMap<Class<?>, Object> interfaceAdapterCache;
060: private int generatedClassSerial;
061:
062: /**
063: * Search for ClassCache object in the given scope.
064: * The method first calls
065: * {@link ScriptableObject#getTopLevelScope(Scriptable scope)}
066: * to get the top most scope and then tries to locate associated
067: * ClassCache object in the prototype chain of the top scope.
068: *
069: * @param scope scope to search for ClassCache object.
070: * @return previously associated ClassCache object or a new instance of
071: * ClassCache if no ClassCache object was found.
072: *
073: * @see #associate(ScriptableObject topScope)
074: */
075: public static ClassCache get(Scriptable scope) {
076: ClassCache cache = (ClassCache) ScriptableObject
077: .getTopScopeValue(scope, AKEY);
078: if (cache == null) {
079: throw new RuntimeException(
080: "Can't find top level scope for "
081: + "ClassCache.get");
082: }
083: return cache;
084: }
085:
086: /**
087: * Associate ClassCache object with the given top-level scope.
088: * The ClassCache object can only be associated with the given scope once.
089: *
090: * @param topScope scope to associate this ClassCache object with.
091: * @return true if no previous ClassCache objects were embedded into
092: * the scope and this ClassCache were successfully associated
093: * or false otherwise.
094: *
095: * @see #get(Scriptable scope)
096: */
097: public boolean associate(ScriptableObject topScope) {
098: if (topScope.getParentScope() != null) {
099: // Can only associate cache with top level scope
100: throw new IllegalArgumentException();
101: }
102: if (this == topScope.associateValue(AKEY, this )) {
103: return true;
104: }
105: return false;
106: }
107:
108: /**
109: * Empty caches of generated Java classes and Java reflection information.
110: */
111: public synchronized void clearCaches() {
112: classTable.clear();
113: javaAdapterGeneratedClasses.clear();
114: classAdapterCache.clear();
115: interfaceAdapterCache = null;
116: }
117:
118: /**
119: * Check if generated Java classes and Java reflection information
120: * is cached.
121: */
122: public final boolean isCachingEnabled() {
123: return cachingIsEnabled;
124: }
125:
126: /**
127: * Set whether to cache some values.
128: * <p>
129: * By default, the engine will cache the results of
130: * <tt>Class.getMethods()</tt> and similar calls.
131: * This can speed execution dramatically, but increases the memory
132: * footprint. Also, with caching enabled, references may be held to
133: * objects past the lifetime of any real usage.
134: * <p>
135: * If caching is enabled and this method is called with a
136: * <code>false</code> argument, the caches will be emptied.
137: * <p>
138: * Caching is enabled by default.
139: *
140: * @param enabled if true, caching is enabled
141: *
142: * @see #clearCaches()
143: */
144: public synchronized void setCachingEnabled(boolean enabled) {
145: if (enabled == cachingIsEnabled)
146: return;
147: if (!enabled)
148: clearCaches();
149: cachingIsEnabled = enabled;
150: }
151:
152: /**
153: * @return a map from classes to associated JavaMembers objects
154: */
155: Map<Class<?>, JavaMembers> getClassCacheMap() {
156: return classTable;
157: }
158:
159: Map<JavaAdapter.JavaAdapterSignature, Class<?>> getInterfaceAdapterCacheMap() {
160: return classAdapterCache;
161: }
162:
163: /**
164: * @deprecated
165: * The method always returns false.
166: * @see #setInvokerOptimizationEnabled(boolean enabled)
167: */
168: public boolean isInvokerOptimizationEnabled() {
169: return false;
170: }
171:
172: /**
173: * @deprecated
174: * The method does nothing.
175: * Invoker optimization is no longer used by Rhino.
176: * On modern JDK like 1.4 or 1.5 the disadvantages of the optimization
177: * like increased memory usage or longer initialization time overweight
178: * small speed increase that can be gained using generated proxy class
179: * to replace reflection.
180: */
181: public synchronized void setInvokerOptimizationEnabled(
182: boolean enabled) {
183: }
184:
185: /**
186: * Internal engine method to return serial number for generated classes
187: * to ensure name uniqueness.
188: */
189: public final synchronized int newClassSerialNumber() {
190: return ++generatedClassSerial;
191: }
192:
193: Object getInterfaceAdapter(Class<?> cl) {
194: return interfaceAdapterCache == null ? null
195: : interfaceAdapterCache.get(cl);
196: }
197:
198: synchronized void cacheInterfaceAdapter(Class<?> cl, Object iadapter) {
199: if (cachingIsEnabled) {
200: if (interfaceAdapterCache == null) {
201: interfaceAdapterCache = new HashMap<Class<?>, Object>();
202: }
203: interfaceAdapterCache.put(cl, iadapter);
204: }
205: }
206: }
|