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 ImmutableOopMapSet extends VMObject {
  36   private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.ImmutableOopMapSet.DEBUG") != null;
  37 
  38   private static CIntegerField countField;
  39   private static CIntegerField sizeField;
  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 long classSize;
  45 
  46   private static class MyVisitor implements OopMapVisitor {
  47     private AddressVisitor addressVisitor;
  48 
  49     public MyVisitor(AddressVisitor oopVisitor) {
  50       setAddressVisitor(oopVisitor);
  51     }
  52 
  53     public void setAddressVisitor(AddressVisitor addressVisitor) {
  54       this.addressVisitor = addressVisitor;
  55     }
  56 
  57     public void visitOopLocation(Address oopAddr) {
  58       addressVisitor.visitAddress(oopAddr);
  59     }
  60 
  61     public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) {
  62       if (VM.getVM().isClientCompiler()) {
  63         Assert.that(false, "should not reach here");
  64       } else if (VM.getVM().isServerCompiler() &&
  65           VM.getVM().useDerivedPointerTable()) {
  66         Assert.that(false, "FIXME: add derived pointer table");
  67       }
  68     }
  69 
  70     public void visitNarrowOopLocation(Address narrowOopAddr) {
  71       addressVisitor.visitCompOopAddress(narrowOopAddr);
  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("ImmutableOopMapSet");
  85 
  86     countField = type.getCIntegerField("_count");
  87     sizeField = type.getCIntegerField("_size");
  88     classSize = type.getSize();
  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 ImmutableOopMapSet(Address addr) {
 100     super(addr);
 101   }
 102 
 103   /**
 104    * Returns the number of OopMaps in this ImmutableOopMapSet
 105    */
 106   public int getCount() { return (int) countField.getValue(addr); }
 107 
 108   private Address dataStart() {
 109     return (pairStart().addOffsetTo(ImmutableOopMapPair.classSize() * getCount()));
 110   }
 111 
 112   private Address pairStart() {
 113     return addr.addOffsetTo(ImmutableOopMapSet.classSize);
 114   }
 115 
 116   public ImmutableOopMapPair pairAt(int index) {
 117     Assert.that((index >= 0) && (index < getCount()), "bad index");
 118     return new ImmutableOopMapPair(pairStart().addOffsetTo(index * ImmutableOopMapPair.classSize()));
 119   }
 120 
 121   /**
 122    * returns the OopMap at a given index
 123    */
 124   public ImmutableOopMap getMapAt(int index) {
 125     if (Assert.ASSERTS_ENABLED) {
 126       Assert.that((index >= 0) && (index <= getCount()), "bad index");
 127     }
 128 
 129     ImmutableOopMapPair immutableOopMapPair = pairAt(index);
 130     return getMap(immutableOopMapPair);
 131   }
 132 
 133   public ImmutableOopMap findMapAtOffset(long pcOffset, boolean debugging) {
 134     int i;
 135     int len = getCount();
 136     if (Assert.ASSERTS_ENABLED) {
 137       Assert.that(len > 0, "must have pointer maps");
 138     }
 139 
 140     // Scan through oopmaps. Stop when current offset is either equal or greater
 141     // than the one we are looking for.
 142     for (i = 0; i < len; i++) {
 143       if (pairAt(i).getPC() >= pcOffset) {
 144         break;
 145       }
 146     }
 147 
 148     if (!debugging) {
 149       if (Assert.ASSERTS_ENABLED) {
 150         Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len);
 151         Assert.that(pairAt(i).getPC() == pcOffset, "oopmap not found");
 152       }
 153     } else {
 154       if (i == len) {
 155         if (DEBUG) {
 156           System.out.println("can't find oopmap at " + pcOffset);
 157           System.out.print("Oopmap offsets are [ ");
 158           for (i = 0; i < len; i++) {
 159             System.out.print(pairAt(i).getPC());
 160           }
 161           System.out.println("]");
 162         }
 163         i = len - 1;
 164         return getMapAt(i);
 165       }
 166     }
 167 
 168     ImmutableOopMap m = getMapAt(i);
 169     return m;
 170   }
 171 
 172   /**
 173    * Visitation -- iterates through the frame for a compiled method.
 174    * This is a very generic mechanism that requires the Address to be
 175    * dereferenced by the callee. Other, more specialized, visitation
 176    * mechanisms are given below.
 177    */
 178   public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) {
 179     allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging);
 180   }
 181 
 182   /**
 183    * Note that there are 4 required AddressVisitors: one for oops,
 184    * one for derived oops, one for values, and one for dead values
 185    */
 186   public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) {
 187     if (Assert.ASSERTS_ENABLED) {
 188       CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC());
 189       Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in");
 190     }
 191 
 192     ImmutableOopMapSet maps = cb.getOopMaps();
 193     ImmutableOopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
 194     if (Assert.ASSERTS_ENABLED) {
 195       Assert.that(map != null, "no ptr map found");
 196     }
 197 
 198     // handle derived pointers first (otherwise base pointer may be
 199     // changed before derived pointer offset has been collected)
 200     OopMapValue omv;
 201     {
 202       for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) {
 203         if (VM.getVM().isClientCompiler()) {
 204           Assert.that(false, "should not reach here");
 205         }
 206         omv = oms.getCurrent();
 207         Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
 208         if (loc != null) {
 209           Address baseLoc = fr.oopMapRegToLocation(omv.getContentReg(), regMap);
 210           Address derivedLoc = loc;
 211           visitor.visitDerivedOopLocation(baseLoc, derivedLoc);
 212         }
 213       }
 214     }
 215 
 216     // We want narow oop and oop oop_types
 217     OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] {
 218         OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE
 219     };
 220 
 221     {
 222       for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) {
 223         omv = oms.getCurrent();
 224         Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap);
 225         if (loc != null) {
 226           if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) {
 227             // This assert commented out because this will be useful
 228             // to detect in the debugging system
 229             // assert(Universe::is_heap_or_null(*loc), "found non oop pointer");
 230             visitor.visitOopLocation(loc);
 231           } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) {
 232             visitor.visitNarrowOopLocation(loc);
 233           }
 234         }
 235       }
 236     }
 237   }
 238 
 239   /**
 240    * Update callee-saved register info for the following frame.
 241    * Should only be called in non-core builds.
 242    */
 243   public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) {
 244     if (Assert.ASSERTS_ENABLED) {
 245       Assert.that(!VM.getVM().isCore(), "non-core builds only");
 246     }
 247 
 248     if (!VM.getVM().isDebugging()) {
 249       if (Assert.ASSERTS_ENABLED) {
 250         ImmutableOopMapSet maps = cb.getOopMaps();
 251         Assert.that((maps != null) && (maps.getCount() > 0), "found null or empty ImmutableOopMapSet for CodeBlob");
 252       }
 253     } else {
 254       // Hack for some topmost frames that have been found with empty
 255       // OopMapSets. (Actually have not seen the null case, but don't
 256       // want to take any chances.) See HSDB.showThreadStackMemory().
 257       ImmutableOopMapSet maps = cb.getOopMaps();
 258       if ((maps == null) || (maps.getCount() == 0)) {
 259         return;
 260       }
 261     }
 262 
 263     // Check if caller must update oop argument
 264     regMap.setIncludeArgumentOops(cb.callerMustGCArguments());
 265 
 266     int nofCallee = 0;
 267     Address[] locs = new Address[2 * REG_COUNT + 1];
 268     VMReg[] regs = new VMReg[2 * REG_COUNT + 1];
 269     // ("+1" because REG_COUNT might be zero)
 270 
 271     // Scan through oopmap and find location of all callee-saved registers
 272     // (we do not do update in place, since info could be overwritten)
 273     ImmutableOopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging);
 274     if (Assert.ASSERTS_ENABLED) {
 275       Assert.that(map != null, "no ptr map found");
 276     }
 277 
 278     OopMapValue omv = null;
 279     for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) {
 280       omv = oms.getCurrent();
 281       if (Assert.ASSERTS_ENABLED) {
 282         Assert.that(nofCallee < 2 * REG_COUNT, "overflow");
 283       }
 284       regs[nofCallee] = omv.getContentReg();
 285       locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap);
 286       nofCallee++;
 287     }
 288 
 289     // Check that runtime stubs save all callee-saved registers
 290     // After adapter frames were deleted C2 doesn't use callee save registers at present
 291     if (Assert.ASSERTS_ENABLED) {
 292       if (VM.getVM().isServerCompiler()) {
 293         Assert.that(!cb.isRuntimeStub() ||
 294                 (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT),
 295             "must save all");
 296       }
 297     }
 298 
 299     // Copy found callee-saved register to reg_map
 300     for (int i = 0; i < nofCallee; i++) {
 301       regMap.setLocation(regs[i], locs[i]);
 302     }
 303   }
 304 
 305   public ImmutableOopMapPair getPairAt(int index) {
 306     return pairAt(index);
 307   }
 308 
 309   private int getSize() {
 310     return (int) sizeField.getValue(addr);
 311   }
 312 
 313   public ImmutableOopMap getMap(ImmutableOopMapPair pair) {
 314     Assert.that(pair.getOffset() < getSize(), "boundary check: this: " + this + " offset: " + pair);
 315     return new ImmutableOopMap(dataStart().addOffsetTo(pair.getOffset()));
 316   }
 317 
 318   public String toString() {
 319     StringBuilder builder = new StringBuilder();
 320     builder.append("Set{ ")
 321       .append("addr = ").append(addr)
 322       .append(", count = ").append(getCount())
 323       .append(", size = ").append(getSize())
 324       .append(", pairs = [");
 325 
 326     for (int i = 0; i < getCount(); ++i) {
 327       builder.append(getPairAt(i));
 328     }
 329 
 330     builder.append("]");
 331     return builder.toString();
 332   }
 333 }