1 /*
   2  * Copyright (c) 2000, 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * 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 visitNarrowOopLocation(Address narrowOopAddr) {
  72       addressVisitor.visitCompOopAddress(narrowOopAddr);
  73     }
  74   }
  75 
  76   static {
  77     VM.registerVMInitializedObserver(new Observer() {
  78         public void update(Observable o, Object data) {
  79           initialize(VM.getVM().getTypeDataBase());
  80         }
  81       });
  82   }
  83 
  84   private static void initialize(TypeDataBase db) {
  85     Type type = db.lookupType("OopMapSet");
  86 
  87     omCountField  = type.getCIntegerField("_om_count");
  88     omSizeField   = type.getCIntegerField("_om_size");
  89     omDataField   = type.getAddressField("_om_data");
  90 
  91     if (!VM.getVM().isCore()) {
  92       REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue();
  93       if (VM.getVM().isServerCompiler()) {
  94         SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue();
  95         C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue();
  96       }
  97     }
  98   }
  99 
 100   public OopMapSet(Address addr) {
 101     super(addr);
 102   }
 103 
 104   /** Returns the number of OopMaps in this OopMapSet */
 105   public long getSize() {
 106     return omCountField.getValue(addr);
 107   }
 108 
 109   /** returns the OopMap at a given index */
 110   public OopMap getMapAt(int index) {
 111     if (Assert.ASSERTS_ENABLED) {
 112       Assert.that((index >= 0) && (index <= getSize()),"bad index");
 113     }
 114     Address omDataAddr = omDataField.getValue(addr);
 115     Address oopMapAddr = omDataAddr.getAddressAt(index * VM.getVM().getAddressSize());
 116     if (oopMapAddr == null) {
 117       return null;
 118     }
 119     return new OopMap(oopMapAddr);
 120   }
 121 
 122   public OopMap findMapAtOffset(long pcOffset, boolean debugging) {
 123     int i;
 124     int len = (int) getSize();
 125     if (Assert.ASSERTS_ENABLED) {
 126       Assert.that(len > 0, "must have pointer maps");
 127     }
 128 
 129     // Scan through oopmaps. Stop when current offset is either equal or greater
 130     // than the one we are looking for.
 131     for (i = 0; i < len; i++) {
 132       if (getMapAt(i).getOffset() >= pcOffset) {
 133         break;
 134       }
 135     }
 136 
 137     if (!debugging) {
 138       if (Assert.ASSERTS_ENABLED) {
 139         Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len);
 140         Assert.that(getMapAt(i).getOffset() == pcOffset, "oopmap not found");
 141       }
 142     } else {
 143       if (i == len) {
 144         if (DEBUG) {
 145           System.out.println("can't find oopmap at " + pcOffset);
 146           System.out.print("Oopmap offsets are [ ");
 147           for (i = 0; i < len; i++) {
 148             System.out.print(getMapAt(i).getOffset());
 149           }
 150           System.out.println("]");
 151         }
 152         i = len - 1;
 153         return getMapAt(i);
 154       }
 155     }
 156 
 157     OopMap m = getMapAt(i);
 158     return m;
 159   }
 160 
 161   /** Visitation -- iterates through the frame for a compiled method.
 162       This is a very generic mechanism that requires the Address to be
 163       dereferenced by the callee. Other, more specialized, visitation
 164       mechanisms are given below. */
 165   public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) {
 166     allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging);
 167   }
 168 
 169   /** Note that there are 4 required AddressVisitors: one for oops,
 170       one for derived oops, one for values, and one for dead values */
 171   public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) {
 172     if (Assert.ASSERTS_ENABLED) {
 173       CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC());
 174       Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in");
 175     }
 176 
 177     OopMapSet maps = cb.getOopMaps();
 178     OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
 179     if (Assert.ASSERTS_ENABLED) {
 180       Assert.that(map != null, "no ptr map found");
 181     }
 182 
 183     // handle derived pointers first (otherwise base pointer may be
 184     // changed before derived pointer offset has been collected)
 185     OopMapValue omv;
 186     {
 187       for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) {
 188         if (VM.getVM().isClientCompiler()) {
 189           Assert.that(false, "should not reach here");
 190         }
 191         omv = oms.getCurrent();
 192         Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
 193         if (loc != null) {
 194           Address baseLoc    = fr.oopMapRegToLocation(omv.getContentReg(), regMap);
 195           Address derivedLoc = loc;
 196           visitor.visitDerivedOopLocation(baseLoc, derivedLoc);
 197         }
 198       }
 199     }
 200 
 201     // We want narow oop, value and oop oop_types
 202     OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] {
 203       OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE
 204     };
 205 
 206     {
 207       for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) {
 208         omv = oms.getCurrent();
 209         Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
 210         if (loc != null) {
 211           if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) {
 212             // This assert commented out because this will be useful
 213             // to detect in the debugging system
 214             // assert(Universe::is_heap_or_null(*loc), "found non oop pointer");
 215             visitor.visitOopLocation(loc);
 216           } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) {
 217             visitor.visitValueLocation(loc);
 218           } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) {
 219             visitor.visitNarrowOopLocation(loc);
 220           }
 221         }
 222       }
 223     }
 224   }
 225 
 226   /** Update callee-saved register info for the following frame.
 227       Should only be called in non-core builds. */
 228   public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) {
 229     if (Assert.ASSERTS_ENABLED) {
 230       Assert.that(!VM.getVM().isCore(), "non-core builds only");
 231     }
 232 
 233     if (!VM.getVM().isDebugging()) {
 234       if (Assert.ASSERTS_ENABLED) {
 235         OopMapSet maps = cb.getOopMaps();
 236         Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty OopMapSet for CodeBlob");
 237       }
 238     } else {
 239       // Hack for some topmost frames that have been found with empty
 240       // OopMapSets. (Actually have not seen the null case, but don't
 241       // want to take any chances.) See HSDB.showThreadStackMemory().
 242       OopMapSet maps = cb.getOopMaps();
 243       if ((maps == null) || (maps.getSize() == 0)) {
 244         return;
 245       }
 246     }
 247 
 248     // Check if caller must update oop argument
 249     regMap.setIncludeArgumentOops(cb.callerMustGCArguments());
 250 
 251     int nofCallee = 0;
 252     Address[] locs = new Address[2 * REG_COUNT + 1];
 253     VMReg  [] regs = new VMReg  [2 * REG_COUNT + 1];
 254     // ("+1" because REG_COUNT might be zero)
 255 
 256     // Scan through oopmap and find location of all callee-saved registers
 257     // (we do not do update in place, since info could be overwritten)
 258     OopMap map  = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
 259     if (Assert.ASSERTS_ENABLED) {
 260       Assert.that(map != null, "no ptr map found");
 261     }
 262 
 263     OopMapValue omv = null;
 264     for(OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) {
 265       omv = oms.getCurrent();
 266       if (Assert.ASSERTS_ENABLED) {
 267         Assert.that(nofCallee < 2 * REG_COUNT, "overflow");
 268       }
 269       regs[nofCallee] = omv.getContentReg();
 270       locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap);
 271       nofCallee++;
 272     }
 273 
 274     // Check that runtime stubs save all callee-saved registers
 275     // After adapter frames were deleted C2 doesn't use callee save registers at present
 276     if (Assert.ASSERTS_ENABLED) {
 277       if (VM.getVM().isServerCompiler()) {
 278         Assert.that(!cb.isRuntimeStub() ||
 279                     (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT),
 280                     "must save all");
 281       }
 282     }
 283 
 284     // Copy found callee-saved register to reg_map
 285     for (int i = 0; i < nofCallee; i++) {
 286       regMap.setLocation(regs[i], locs[i]);
 287     }
 288   }
 289 }