001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2005 Thomas E. Enebo <enebo@acm.org>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jruby.runtime;
028:
029: import java.util.WeakHashMap;
030: import java.util.Iterator;
031: import java.util.Map;
032: import org.jruby.Ruby;
033:
034: import org.jruby.RubyModule;
035: import org.jruby.internal.runtime.methods.DynamicMethod;
036: import org.jruby.util.WeakIdentityHashMap;
037:
038: /**
039: * This class represents mappings between methods that have been cached and the classes which
040: * have cached them. Methods within RubyModule will update this cacheMap as needed. Here is
041: * a list of scenarios when cached methods will become invalid:
042: *
043: * 1. Redefine a method in a base class
044: * 2. Add an alias in a superclass that is the same name as a cached method in a base class
045: * 3. Include a module that has a same-named method as one already caches in a base class
046: * 4. Remove a method definition
047: * 5. Add a same-named method in super class that has been cached in a super class
048: *
049: * Concurrency is another concern with managing this structure. Rather than synchronize this
050: * we are going to rely on synchronization further upstream. RubyModule methods that directly
051: * call this is responsible for synchronization.
052: */
053: public class CacheMap {
054: private final Map mappings = new WeakHashMap();
055: private final Ruby runtime;
056:
057: public CacheMap(Ruby runtime) {
058: this .runtime = runtime;
059: }
060:
061: /**
062: * Add another class to the list of classes which are caching the method.
063: *
064: * @param method which is cached
065: * @param module which is caching method
066: */
067: public void add(DynamicMethod method, RubyModule module) {
068: Map classList = (Map) mappings.get(method);
069:
070: if (classList == null) {
071: classList = new WeakIdentityHashMap();
072: mappings.put(method, classList);
073: }
074:
075: classList.put(module, null);
076: }
077:
078: /**
079: * Remove all method caches associated with the provided method. This signature
080: * relies on having the methods valid name passed with it since the caching classes
081: * store the cache by name.
082: *
083: * @param name of the method to remove
084: * @param method to remove all caches of
085: */
086: public void remove(String name, DynamicMethod method) {
087: Map classList = (Map) mappings.remove(method);
088:
089: // Removed method has never been used so it has not been cached
090: if (classList == null) {
091: return;
092: }
093: for (Iterator iter = classList.keySet().iterator(); iter
094: .hasNext();) {
095: RubyModule module = (RubyModule) iter.next();
096: if (module != null) {
097: module.removeCachedMethod(name);
098:
099: if (module.index != 0) {
100: runtime.getSelectorTable().table[module.index][MethodIndex
101: .getIndex(name)] = 0;
102: }
103: }
104: }
105: }
106: }
|