blob: ca0b982a48a47f20ff3dbc6b4d268e72cbd6e2fa [file] [log] [blame]
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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 ImmutableOopMapSet extends VMObject {
private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.ImmutableOopMapSet.DEBUG") != null;
private static CIntegerField countField;
private static CIntegerField sizeField;
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 long classSize;
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 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("ImmutableOopMapSet");
countField = type.getCIntegerField("_count");
sizeField = type.getCIntegerField("_size");
classSize = type.getSize();
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 ImmutableOopMapSet(Address addr) {
super(addr);
}
/**
* Returns the number of OopMaps in this ImmutableOopMapSet
*/
public int getCount() { return (int) countField.getValue(addr); }
private Address dataStart() {
return (pairStart().addOffsetTo(ImmutableOopMapPair.classSize() * getCount()));
}
private Address pairStart() {
return addr.addOffsetTo(ImmutableOopMapSet.classSize);
}
public ImmutableOopMapPair pairAt(int index) {
Assert.that((index >= 0) && (index < getCount()), "bad index");
return new ImmutableOopMapPair(pairStart().addOffsetTo(index * ImmutableOopMapPair.classSize()));
}
/**
* returns the OopMap at a given index
*/
public ImmutableOopMap getMapAt(int index) {
if (Assert.ASSERTS_ENABLED) {
Assert.that((index >= 0) && (index <= getCount()), "bad index");
}
ImmutableOopMapPair immutableOopMapPair = pairAt(index);
return getMap(immutableOopMapPair);
}
public ImmutableOopMap findMapAtOffset(long pcOffset, boolean debugging) {
int i;
int len = getCount();
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 (pairAt(i).getPC() >= pcOffset) {
break;
}
}
if (!debugging) {
if (Assert.ASSERTS_ENABLED) {
Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len);
Assert.that(pairAt(i).getPC() == 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(pairAt(i).getPC());
}
System.out.println("]");
}
i = len - 1;
return getMapAt(i);
}
}
ImmutableOopMap 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");
}
ImmutableOopMapSet maps = cb.getOopMaps();
ImmutableOopMap 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 and oop oop_types
OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] {
OopMapValue.OopTypes.OOP_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.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) {
ImmutableOopMapSet maps = cb.getOopMaps();
Assert.that((maps != null) && (maps.getCount() > 0), "found null or empty ImmutableOopMapSet 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().
ImmutableOopMapSet maps = cb.getOopMaps();
if ((maps == null) || (maps.getCount() == 0)) {
return;
}
}
// Check if caller must update oop argument
regMap.setIncludeArgumentOops(cb.callerMustGCArguments());
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)
ImmutableOopMap 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]);
}
}
public ImmutableOopMapPair getPairAt(int index) {
return pairAt(index);
}
private int getSize() {
return (int) sizeField.getValue(addr);
}
public ImmutableOopMap getMap(ImmutableOopMapPair pair) {
Assert.that(pair.getOffset() < getSize(), "boundary check: this: " + this + " offset: " + pair);
return new ImmutableOopMap(dataStart().addOffsetTo(pair.getOffset()));
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Set{ ")
.append("addr = ").append(addr)
.append(", count = ").append(getCount())
.append(", size = ").append(getSize())
.append(", pairs = [");
for (int i = 0; i < getCount(); ++i) {
builder.append(getPairAt(i));
}
builder.append("]");
return builder.toString();
}
}