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