1 /*
   2  * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *  
  23  */
  24 
  25 package sun.jvm.hotspot.compiler;
  26 
  27 import java.util.*;
  28 
  29 import sun.jvm.hotspot.code.*;
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.runtime.*;
  32 import sun.jvm.hotspot.types.*;
  33 import sun.jvm.hotspot.utilities.*;
  34 
  35 public class OopMapSet extends VMObject {
  36   private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.OopMapSet.DEBUG") != null;
  37 
  38   private static CIntegerField omCountField;
  39   private static CIntegerField omSizeField;
  40   private static AddressField  omDataField;
  41   private static int REG_COUNT;
  42   private static int SAVED_ON_ENTRY_REG_COUNT;
  43   private static int C_SAVED_ON_ENTRY_REG_COUNT;
  44   private static class MyVisitor implements OopMapVisitor {
  45     private AddressVisitor addressVisitor;
  46 
  47     public MyVisitor(AddressVisitor oopVisitor) {
  48       setAddressVisitor(oopVisitor);
  49     }
  50 
  51     public void setAddressVisitor(AddressVisitor addressVisitor) {
  52       this.addressVisitor = addressVisitor;
  53     }
  54 
  55     public void visitOopLocation(Address oopAddr) {
  56       addressVisitor.visitAddress(oopAddr);
  57     }
  58 
  59     public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) {
  60       if (VM.getVM().isClientCompiler()) {
  61         Assert.that(false, "should not reach here");
  62       } else if (VM.getVM().isServerCompiler() &&
  63                  VM.getVM().useDerivedPointerTable()) {
  64         Assert.that(false, "FIXME: add derived pointer table");
  65       }
  66     }
  67 
  68     public void visitValueLocation(Address valueAddr) {
  69     }
  70 
  71     public void visitDeadLocation(Address deadAddr) {
  72     }
  73   }
  74 
  75   static {
  76     VM.registerVMInitializedObserver(new Observer() {
  77         public void update(Observable o, Object data) {
  78           initialize(VM.getVM().getTypeDataBase());
  79         }
  80       });
  81   }
  82 
  83   private static void initialize(TypeDataBase db) {
  84     Type type = db.lookupType("OopMapSet");
  85 
  86     omCountField  = type.getCIntegerField("_om_count");
  87     omSizeField   = type.getCIntegerField("_om_size");
  88     omDataField   = type.getAddressField("_om_data");
  89 
  90     if (!VM.getVM().isCore()) {
  91       REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue();
  92       if (VM.getVM().isServerCompiler()) {
  93         SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue();
  94         C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue();
  95       }
  96     }
  97   }
  98 
  99   public OopMapSet(Address addr) {
 100     super(addr);
 101   }
 102 
 103   /** Returns the number of OopMaps in this OopMapSet */
 104   public long getSize() {
 105     return omCountField.getValue(addr);
 106   }
 107 
 108   /** returns the OopMap at a given index */
 109   public OopMap getMapAt(int index) {
 110     if (Assert.ASSERTS_ENABLED) {
 111       Assert.that((index >= 0) && (index <= getSize()),"bad index");
 112     }
 113     Address omDataAddr = omDataField.getValue(addr);
 114     Address oopMapAddr = omDataAddr.getAddressAt(index * VM.getVM().getAddressSize());
 115     if (oopMapAddr == null) {
 116       return null;
 117     }
 118     return new OopMap(oopMapAddr);
 119   }
 120 
 121   public OopMap findMapAtOffset(long pcOffset, boolean debugging) {
 122     int i;
 123     int len = (int) getSize();
 124     if (Assert.ASSERTS_ENABLED) {
 125       Assert.that(len > 0, "must have pointer maps");
 126     }
 127 
 128     // Scan through oopmaps. Stop when current offset is either equal or greater
 129     // than the one we are looking for.
 130     for (i = 0; i < len; i++) {
 131       if (getMapAt(i).getOffset() >= pcOffset) {
 132         break;
 133       }
 134     }
 135   
 136     if (!debugging) {
 137       if (Assert.ASSERTS_ENABLED) {
 138         Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len);
 139         Assert.that(getMapAt(i).getOffset() == pcOffset, "oopmap not found");
 140       }
 141     } else {
 142       if (i == len) {
 143         if (DEBUG) {
 144           System.out.println("can't find oopmap at " + pcOffset);
 145           System.out.print("Oopmap offsets are [ ");
 146           for (i = 0; i < len; i++) {
 147             System.out.print(getMapAt(i).getOffset());
 148           }
 149           System.out.println("]");
 150         }
 151         i = len - 1;
 152         return getMapAt(i);
 153       }
 154     }
 155 
 156     OopMap m = getMapAt(i);
 157     return m;
 158   }
 159 
 160   /** Visitation -- iterates through the frame for a compiled method.
 161       This is a very generic mechanism that requires the Address to be
 162       dereferenced by the callee. Other, more specialized, visitation
 163       mechanisms are given below. */
 164   public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) {
 165     allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging);
 166   }
 167 
 168   /** Note that there are 4 required AddressVisitors: one for oops,
 169       one for derived oops, one for values, and one for dead values */
 170   public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) {
 171     if (Assert.ASSERTS_ENABLED) {
 172       CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC());
 173       Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in");
 174     }
 175 
 176     OopMapSet maps = cb.getOopMaps();
 177     OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
 178     if (Assert.ASSERTS_ENABLED) {
 179       Assert.that(map != null, "no ptr map found");
 180     }
 181 
 182     // handle derived pointers first (otherwise base pointer may be
 183     // changed before derived pointer offset has been collected)
 184     OopMapValue omv;
 185     {    
 186       for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) {
 187         if (VM.getVM().isClientCompiler()) {
 188           Assert.that(false, "should not reach here");
 189         }
 190         omv = oms.getCurrent();
 191         Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
 192         if (loc != null) {
 193           Address baseLoc    = fr.oopMapRegToLocation(omv.getContentReg(), regMap);
 194           Address derivedLoc = loc;
 195           visitor.visitDerivedOopLocation(baseLoc, derivedLoc);
 196         }
 197       }   
 198     }
 199 
 200     // We want dead, value and oop oop_types
 201     OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] {
 202       OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.DEAD_VALUE
 203     };
 204 
 205     {
 206       for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) {
 207         omv = oms.getCurrent();
 208         Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
 209         if (loc != null) {
 210           if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) {
 211             // This assert commented out because this will be useful
 212             // to detect in the debugging system
 213             // assert(Universe::is_heap_or_null(*loc), "found non oop pointer");
 214             visitor.visitOopLocation(loc);
 215           } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) {
 216             visitor.visitValueLocation(loc);
 217           } else if (omv.getType() == OopMapValue.OopTypes.DEAD_VALUE) {
 218             visitor.visitDeadLocation(loc);
 219           }
 220         }
 221       }
 222     }
 223   }
 224 
 225   /** Update callee-saved register info for the following frame.
 226       Should only be called in non-core builds. */
 227   public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) {
 228     if (Assert.ASSERTS_ENABLED) {
 229       Assert.that(!VM.getVM().isCore(), "non-core builds only");
 230     }
 231     
 232     if (!VM.getVM().isDebugging()) {
 233       if (Assert.ASSERTS_ENABLED) {
 234         OopMapSet maps = cb.getOopMaps();
 235         Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty OopMapSet for CodeBlob");
 236       }
 237     } else {
 238       // Hack for some topmost frames that have been found with empty
 239       // OopMapSets. (Actually have not seen the null case, but don't
 240       // want to take any chances.) See HSDB.showThreadStackMemory().
 241       OopMapSet maps = cb.getOopMaps();
 242       if ((maps == null) || (maps.getSize() == 0)) {
 243         return;
 244       }
 245     }
 246 
 247     // Check if caller must update oop argument  
 248     regMap.setIncludeArgumentOops(cb.callerMustGCArguments(regMap.getThread()));
 249 
 250     int nofCallee = 0;
 251     Address[] locs = new Address[2 * REG_COUNT + 1];
 252     VMReg  [] regs = new VMReg  [2 * REG_COUNT + 1];
 253     // ("+1" because REG_COUNT might be zero)
 254 
 255     // Scan through oopmap and find location of all callee-saved registers
 256     // (we do not do update in place, since info could be overwritten)
 257     OopMap map  = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
 258     if (Assert.ASSERTS_ENABLED) {
 259       Assert.that(map != null, "no ptr map found");
 260     }
 261 
 262     OopMapValue omv = null;
 263     for(OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) {
 264       omv = oms.getCurrent();
 265       if (Assert.ASSERTS_ENABLED) {
 266         Assert.that(nofCallee < 2 * REG_COUNT, "overflow");
 267       }
 268       regs[nofCallee] = omv.getContentReg();
 269       locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap);
 270       nofCallee++;
 271     }
 272     
 273     // Check that runtime stubs save all callee-saved registers
 274     // After adapter frames were deleted C2 doesn't use callee save registers at present
 275     if (Assert.ASSERTS_ENABLED) {
 276       if (VM.getVM().isServerCompiler()) {
 277         Assert.that(!cb.isRuntimeStub() || 
 278                     (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT),
 279                     "must save all");
 280       }
 281     }
 282 
 283     // Copy found callee-saved register to reg_map
 284     for (int i = 0; i < nofCallee; i++) {
 285       regMap.setLocation(regs[i], locs[i]);
 286     }
 287   }
 288 }