View Javadoc
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 }