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.mm.mminterface;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.RVMArray;
017    import org.jikesrvm.classloader.RVMType;
018    import org.jikesrvm.objectmodel.ObjectModel;
019    import org.jikesrvm.objectmodel.TIB;
020    import org.jikesrvm.runtime.BootRecord;
021    import org.jikesrvm.runtime.Magic;
022    import org.jikesrvm.scheduler.RVMThread;
023    import org.mmtk.policy.Space;
024    import org.mmtk.utility.heap.Mmapper;
025    import org.vmmagic.pragma.Interruptible;
026    import org.vmmagic.pragma.Uninterruptible;
027    import org.vmmagic.unboxed.Address;
028    import org.vmmagic.unboxed.ObjectReference;
029    
030    /**
031     * Common debugging utility functions used by various garbage collectors
032     */
033    @Uninterruptible
034    public class DebugUtil implements org.mmtk.utility.Constants, org.jikesrvm.Constants {
035    
036      private static TIB tibForArrayType;
037      private static TIB tibForClassType;
038      private static TIB tibForPrimitiveType;
039    
040      @Interruptible
041      static void boot(BootRecord theBootRecord) {
042        // get addresses of TIBs for RVMArray & RVMClass used for testing Type ptrs
043        RVMType t = RVMArray.IntArray;
044        tibForArrayType = ObjectModel.getTIB(t);
045        tibForPrimitiveType = ObjectModel.getTIB(RVMType.IntType);
046        t = Magic.getObjectType(BootRecord.the_boot_record);
047        tibForClassType = ObjectModel.getTIB(t);
048      }
049    
050      /**
051       * Check if an address appears to point to an instance of RVMType
052       *
053       * @param typeAddress the address to check
054       */
055      @Uninterruptible
056      public static boolean validType(ObjectReference typeAddress) {
057        if (!Space.isMappedObject(typeAddress)) {
058          return false;  // type address is outside of heap
059        }
060    
061        // check if types tib is one of three possible values
062        TIB typeTib = ObjectModel.getTIB(typeAddress);
063        return ((typeTib == tibForClassType) || (typeTib == tibForArrayType) || (typeTib == tibForPrimitiveType));
064      }
065    
066      /**
067       * Dump all threads & their stacks starting at the frame identified
068       * by the threads saved contextRegisters (ip & fp fields).
069       */
070      @Uninterruptible
071      public static void dumpAllThreadStacks() {
072        RVMThread.dumpVirtualMachine();
073      }  // dumpAllThreadStacks
074    
075      /**
076       * Check if a ref, its tib pointer & type pointer are all in the heap
077       */
078      @Uninterruptible
079      public static boolean validObject(Object ref) {
080        return validRef(ObjectReference.fromObject(ref));
081      }
082    
083      @Uninterruptible
084      public static boolean validRef(ObjectReference ref) {
085    
086        if (ref.isNull()) return true;
087        if (!Space.isMappedObject(ref)) {
088          VM.sysWrite("validRef: REF outside heap, ref = ");
089          VM.sysWrite(ref);
090          VM.sysWrite("\n");
091          Space.printVMMap();
092          return false;
093        }
094        if (MemoryManagerConstants.MOVES_OBJECTS) {
095          /*
096          TODO: Work out how to check if forwarded
097          if (Plan.isForwardedOrBeingForwarded(ref)) {
098            // TODO: actually follow forwarding pointer
099            // (need to bound recursion when things are broken!!)
100            return true;
101          }
102          */
103        }
104    
105        TIB tib = ObjectModel.getTIB(ref);
106        Address tibAddr = Magic.objectAsAddress(tib);
107        if (!Space.isMappedObject(ObjectReference.fromObject(tib))) {
108          VM.sysWrite("validRef: TIB outside heap, ref = ");
109          VM.sysWrite(ref);
110          VM.sysWrite(" tib = ");
111          VM.sysWrite(tibAddr);
112          VM.sysWrite("\n");
113          ObjectModel.dumpHeader(ref);
114          return false;
115        }
116        if (tibAddr.isZero()) {
117          VM.sysWrite("validRef: TIB is Zero! ");
118          VM.sysWrite(ref);
119          VM.sysWrite("\n");
120          ObjectModel.dumpHeader(ref);
121          return false;
122        }
123        if (tib.length() == 0) {
124          VM.sysWrite("validRef: TIB length zero, ref = ");
125          VM.sysWrite(ref);
126          VM.sysWrite(" tib = ");
127          VM.sysWrite(tibAddr);
128          VM.sysWrite("\n");
129          ObjectModel.dumpHeader(ref);
130          return false;
131        }
132    
133        ObjectReference type = ObjectReference.fromObject(tib.getType());
134        if (!validType(type)) {
135          VM.sysWrite("validRef: invalid TYPE, ref = ");
136          VM.sysWrite(ref);
137          VM.sysWrite(" tib = ");
138          VM.sysWrite(Magic.objectAsAddress(tib));
139          VM.sysWrite(" type = ");
140          VM.sysWrite(type);
141          VM.sysWrite("\n");
142          ObjectModel.dumpHeader(ref);
143          return false;
144        }
145        return true;
146      }  // validRef
147    
148      @Uninterruptible
149      public static boolean mappedVMRef(ObjectReference ref) {
150        return Space.isMappedObject(ref) && Mmapper.objectIsMapped(ref);
151      }
152    
153      @Uninterruptible
154      public static void dumpRef(ObjectReference ref) {
155        VM.sysWrite("REF=");
156        if (ref.isNull()) {
157          VM.sysWrite("NULL\n");
158          return;
159        }
160        VM.sysWrite(ref);
161        if (!mappedVMRef(ref)) {
162          VM.sysWrite(" (REF OUTSIDE OF HEAP OR NOT MAPPED)\n");
163          return;
164        }
165        ObjectModel.dumpHeader(ref);
166        ObjectReference tib = ObjectReference.fromObject(ObjectModel.getTIB(ref));
167        if (!MemoryManager.mightBeTIB(tib)) {
168          VM.sysWrite(" (INVALID TIB: CLASS NOT ACCESSIBLE)\n");
169          return;
170        }
171        RVMType type = Magic.getObjectType(ref.toObject());
172        ObjectReference itype = ObjectReference.fromObject(type);
173        VM.sysWrite(" TYPE=");
174        VM.sysWrite(itype);
175        if (!validType(itype)) {
176          VM.sysWrite(" (INVALID TYPE: CLASS NOT ACCESSIBLE)\n");
177          return;
178        }
179        VM.sysWrite(" CLASS=");
180        VM.sysWrite(type.getDescriptor());
181        VM.sysWrite("\n");
182      }
183    
184      public static boolean addrInBootImage(Address addr) {
185        return (addr.GE(BOOT_IMAGE_DATA_START) && addr.LT(BOOT_IMAGE_DATA_END)) ||
186               (addr.GE(BOOT_IMAGE_CODE_START) && addr.LT(BOOT_IMAGE_CODE_END));
187      }
188    }