001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.inlining;
014    
015    import java.io.FileOutputStream;
016    import java.io.IOException;
017    import java.io.PrintStream;
018    import java.util.Iterator;
019    
020    import org.jikesrvm.VM;
021    import org.jikesrvm.classloader.RVMClass;
022    import org.jikesrvm.classloader.ClassLoadingListener;
023    import org.jikesrvm.classloader.RVMMethod;
024    import org.jikesrvm.compilers.common.CompiledMethod;
025    import org.jikesrvm.compilers.common.CompiledMethods;
026    import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
027    
028    /**
029     * This class acts as an intermediary between RVMClassLoader and the
030     * optimizing compiler's dependency database.  Just before a class
031     * is marked as INITIALIZED, RVMClass.initialize() invokes
032     * ClassLoadingDependencyManager.classInitialized(), which is responsible
033     * for identifying and performing all necessary invalidations of
034     * opt compiler code.
035     */
036    public final class ClassLoadingDependencyManager implements ClassLoadingListener {
037    
038      /** Database holding information on class loading */
039      private final InvalidationDatabase db = new InvalidationDatabase();
040    
041      /** Debug execution */
042      static final boolean DEBUG = false;
043      /** Trace execution */
044      static final boolean TRACE = false;
045      /** Stream used in debug tracing */
046      private static PrintStream log;
047    
048      ////////////////////////
049      // Entrypoints from RVMClass
050      ////////////////////////
051      @Override
052      public synchronized void classInitialized(RVMClass c, boolean writingBootImage) {
053        // Process any dependencies on methods not being overridden.
054        if (!writingBootImage) {
055          if (DEBUG) {
056            report("CLDM: " + c + " is about to be marked as initialized.\n");
057          }
058          handleOverriddenMethods(c);
059          handleSubclassing(c);
060        }
061        InterfaceHierarchy.notifyClassInitialized(c);
062      }
063    
064      /////////////////////////
065      // Entrypoints for the opt compiler to record dependencies
066      /////////////////////////
067    
068      /**
069       * Record that the code currently being compiled (cm) must be
070       * invalidated if source is overridden.
071       */
072      public synchronized void addNotOverriddenDependency(RVMMethod source, CompiledMethod cm) {
073        int cmid = cm.getId();
074        if (TRACE || DEBUG) {
075          report("CLDM: " + cmid + "(" + cm.getMethod() + ") is dependent on " + source + " not being overridden\n");
076        }
077        db.addNotOverriddenDependency(source, cmid);
078      }
079    
080      /**
081       * Record that the code currently being compiled (cm) must be
082       * invalidated if source ever has a subclass.
083       */
084      public synchronized void addNoSubclassDependency(RVMClass source, CompiledMethod cm) {
085        int cmid = cm.getId();
086        if (TRACE || DEBUG) {
087          report("CLDM: " + cmid + "(" + cm.getMethod() + ") is dependent on " + source + " not having a subclass\n");
088        }
089        db.addNoSubclassDependency(source, cmid);
090      }
091    
092      ////////////////////////
093      // Implementation
094      ////////////////////////
095    
096      /**
097       * Take action when a method is overridden.
098       * @param c a class that has just been loaded.
099       */
100      private void handleOverriddenMethods(RVMClass c) {
101        if (c.isJavaLangObjectType() || c.isInterface()) return; // nothing to do.
102        RVMClass sc = c.getSuperClass();
103        // for each virtual method of sc, if it is overriden by
104        // a virtual method declared by c, then handle any required invalidations.
105        RVMMethod[] sc_methods = sc.getVirtualMethods();
106        RVMMethod[] c_methods = c.getVirtualMethods();
107        for (int i = 0; i < sc_methods.length; i++) {
108          if (sc_methods[i] != c_methods[i]) {
109            processOverride(sc_methods[i]);
110          }
111        }
112        // for each interface implmented by c, note that c provides an overridding
113        // implementation
114        for (RVMClass intf : c.getAllImplementedInterfaces()) {
115          for (RVMMethod m : intf.getVirtualMethods()) {
116            processOverride(m);
117          }
118        }
119      }
120    
121      private void processOverride(RVMMethod overridden) {
122        Iterator<Integer> invalidatedMethods = db.invalidatedByOverriddenMethod(overridden);
123        if (invalidatedMethods != null) {
124          while (invalidatedMethods.hasNext()) {
125            int cmid = invalidatedMethods.next();
126            CompiledMethod im = CompiledMethods.getCompiledMethod(cmid);
127            if (im != null) { // im == null implies that the code has been GCed already
128              invalidate(im);
129            }
130          }
131          db.removeNotOverriddenDependency(overridden);
132        }
133      }
134    
135      private void handleSubclassing(RVMClass c) {
136        if (c.isJavaLangObjectType() || c.isInterface()) return; // nothing to do
137        RVMClass sc = c.getSuperClass();
138        Iterator<Integer> invalidatedMethods = db.invalidatedBySubclass(sc);
139        if (invalidatedMethods != null) {
140          while (invalidatedMethods.hasNext()) {
141            int cmid = invalidatedMethods.next();
142            CompiledMethod im = CompiledMethods.getCompiledMethod(cmid);
143            if (im != null) { // im == null implies that the code has been GCed already
144              invalidate(im);
145            }
146          }
147          db.removeNoSubclassDependency(sc);
148        }
149      }
150    
151      /**
152       * helper method to invalidate a particular compiled method
153       */
154      private void invalidate(CompiledMethod cm) {
155        RVMMethod m = cm.getMethod();
156        if (TRACE || DEBUG) {
157          report("CLDM: Invalidating compiled method " + cm.getId() + "(" + m + ")\n");
158        }
159    
160        // (1) Mark the compiled method as invalid.
161        synchronized (cm) {
162          if (cm.isInvalid()) {
163            if (TRACE || DEBUG) report("\tcmid was alrady invalid; nothing more to do\n");
164            return;
165          }
166    
167          // (2) Apply any code patches to protect invocations already executing
168          //     in the soon to be invalid code.
169          ((OptCompiledMethod)cm).applyCodePatches(cm);
170    
171          cm.setInvalid();
172        }
173    
174        // (3) Inform its RVMMethod that cm is invalid;
175        //     This will update all the dispatching entries (TIB, JTOC, IMTs)
176        //     so that no new invocations will reach the invalid compiled code.
177        //     It also marks cm as obsolete so it can eventually be reclaimed by GC.
178        m.invalidateCompiledMethod(cm);
179      }
180    
181      void report(String s) {
182        if (VM.runningVM) {
183          if (log == null) {
184            if (true || !VM.fullyBooted) {
185              VM.sysWriteln("CLDM: VM not fully booted ", s);
186              return;
187            }
188            try {
189              log = new PrintStream(new FileOutputStream("PREEX_OPTS.TRACE"));
190            } catch (IOException e) {
191              VM.sysWrite("\n\nCLDM: Error opening logging file!!\n\n");
192            }
193          }
194        } else {
195          System.out.print(s);
196        }
197      }
198    }