/* * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ package sun.jvm.hotspot.compiler; import java.util.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; public class OopMapSet extends VMObject { private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.OopMapSet.DEBUG") != null; private static CIntegerField omCountField; private static CIntegerField omSizeField; private static AddressField omDataField; private static int REG_COUNT; private static int SAVED_ON_ENTRY_REG_COUNT; private static int C_SAVED_ON_ENTRY_REG_COUNT; private static class MyVisitor implements OopMapVisitor { private AddressVisitor addressVisitor; public MyVisitor(AddressVisitor oopVisitor) { setAddressVisitor(oopVisitor); } public void setAddressVisitor(AddressVisitor addressVisitor) { this.addressVisitor = addressVisitor; } public void visitOopLocation(Address oopAddr) { addressVisitor.visitAddress(oopAddr); } public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) { if (VM.getVM().isClientCompiler()) { Assert.that(false, "should not reach here"); } else if (VM.getVM().isServerCompiler() && VM.getVM().useDerivedPointerTable()) { Assert.that(false, "FIXME: add derived pointer table"); } } public void visitValueLocation(Address valueAddr) { } public void visitNarrowOopLocation(Address narrowOopAddr) { addressVisitor.visitCompOopAddress(narrowOopAddr); } } static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } }); } private static void initialize(TypeDataBase db) { Type type = db.lookupType("OopMapSet"); omCountField = type.getCIntegerField("_om_count"); omSizeField = type.getCIntegerField("_om_size"); omDataField = type.getAddressField("_om_data"); if (!VM.getVM().isCore()) { REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue(); if (VM.getVM().isServerCompiler()) { SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue(); C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue(); } } } public OopMapSet(Address addr) { super(addr); } /** Returns the number of OopMaps in this OopMapSet */ public long getSize() { return omCountField.getValue(addr); } /** returns the OopMap at a given index */ public OopMap getMapAt(int index) { if (Assert.ASSERTS_ENABLED) { Assert.that((index >= 0) && (index <= getSize()),"bad index"); } Address omDataAddr = omDataField.getValue(addr); Address oopMapAddr = omDataAddr.getAddressAt(index * VM.getVM().getAddressSize()); if (oopMapAddr == null) { return null; } return new OopMap(oopMapAddr); } public OopMap findMapAtOffset(long pcOffset, boolean debugging) { int i; int len = (int) getSize(); if (Assert.ASSERTS_ENABLED) { Assert.that(len > 0, "must have pointer maps"); } // Scan through oopmaps. Stop when current offset is either equal or greater // than the one we are looking for. for (i = 0; i < len; i++) { if (getMapAt(i).getOffset() >= pcOffset) { break; } } if (!debugging) { if (Assert.ASSERTS_ENABLED) { Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len); Assert.that(getMapAt(i).getOffset() == pcOffset, "oopmap not found"); } } else { if (i == len) { if (DEBUG) { System.out.println("can't find oopmap at " + pcOffset); System.out.print("Oopmap offsets are [ "); for (i = 0; i < len; i++) { System.out.print(getMapAt(i).getOffset()); } System.out.println("]"); } i = len - 1; return getMapAt(i); } } OopMap m = getMapAt(i); return m; } /** Visitation -- iterates through the frame for a compiled method. This is a very generic mechanism that requires the Address to be dereferenced by the callee. Other, more specialized, visitation mechanisms are given below. */ public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) { allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging); } /** Note that there are 4 required AddressVisitors: one for oops, one for derived oops, one for values, and one for dead values */ public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) { if (Assert.ASSERTS_ENABLED) { CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC()); Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in"); } OopMapSet maps = cb.getOopMaps(); OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); if (Assert.ASSERTS_ENABLED) { Assert.that(map != null, "no ptr map found"); } // handle derived pointers first (otherwise base pointer may be // changed before derived pointer offset has been collected) OopMapValue omv; { for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) { if (VM.getVM().isClientCompiler()) { Assert.that(false, "should not reach here"); } omv = oms.getCurrent(); Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); if (loc != null) { Address baseLoc = fr.oopMapRegToLocation(omv.getContentReg(), regMap); Address derivedLoc = loc; visitor.visitDerivedOopLocation(baseLoc, derivedLoc); } } } // We want narow oop, value and oop oop_types OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] { OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE }; { for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) { omv = oms.getCurrent(); Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); if (loc != null) { if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) { // This assert commented out because this will be useful // to detect in the debugging system // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); visitor.visitOopLocation(loc); } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) { visitor.visitValueLocation(loc); } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) { visitor.visitNarrowOopLocation(loc); } } } } } /** Update callee-saved register info for the following frame. Should only be called in non-core builds. */ public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) { if (Assert.ASSERTS_ENABLED) { Assert.that(!VM.getVM().isCore(), "non-core builds only"); } if (!VM.getVM().isDebugging()) { if (Assert.ASSERTS_ENABLED) { OopMapSet maps = cb.getOopMaps(); Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty OopMapSet for CodeBlob"); } } else { // Hack for some topmost frames that have been found with empty // OopMapSets. (Actually have not seen the null case, but don't // want to take any chances.) See HSDB.showThreadStackMemory(). OopMapSet maps = cb.getOopMaps(); if ((maps == null) || (maps.getSize() == 0)) { return; } } // Check if caller must update oop argument regMap.setIncludeArgumentOops(cb.callerMustGCArguments(regMap.getThread())); int nofCallee = 0; Address[] locs = new Address[2 * REG_COUNT + 1]; VMReg [] regs = new VMReg [2 * REG_COUNT + 1]; // ("+1" because REG_COUNT might be zero) // Scan through oopmap and find location of all callee-saved registers // (we do not do update in place, since info could be overwritten) OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); if (Assert.ASSERTS_ENABLED) { Assert.that(map != null, "no ptr map found"); } OopMapValue omv = null; for(OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) { omv = oms.getCurrent(); if (Assert.ASSERTS_ENABLED) { Assert.that(nofCallee < 2 * REG_COUNT, "overflow"); } regs[nofCallee] = omv.getContentReg(); locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap); nofCallee++; } // Check that runtime stubs save all callee-saved registers // After adapter frames were deleted C2 doesn't use callee save registers at present if (Assert.ASSERTS_ENABLED) { if (VM.getVM().isServerCompiler()) { Assert.that(!cb.isRuntimeStub() || (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT), "must save all"); } } // Copy found callee-saved register to reg_map for (int i = 0; i < nofCallee; i++) { regMap.setLocation(regs[i], locs[i]); } } }