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