/*
* 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.code;
import java.io.*;
import java.util.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
A Location describes a concrete machine variable location
(such as integer or floating point register or a stack-held
variable). Used when generating debug-information for
nmethods.
Encoding:
bits:
Type: [3..0]
Where: [4]
Offset: [31..5]
/** <P> A Location describes a concrete machine variable location
(such as integer or floating point register or a stack-held
variable). Used when generating debug-information for
nmethods. </P>
<P> Encoding: </P>
<PRE>
bits:
Type: [3..0]
Where: [4]
Offset: [31..5]
</PRE>
*/
public class Location {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static void initialize(TypeDataBase db) {
if (Assert.ASSERTS_ENABLED) {
Assert.that(!VM.getVM().isCore(), "Debug info not used in core build");
}
OFFSET_MASK = db.lookupIntConstant("Location::OFFSET_MASK").intValue();
OFFSET_SHIFT = db.lookupIntConstant("Location::OFFSET_SHIFT").intValue();
TYPE_MASK = db.lookupIntConstant("Location::TYPE_MASK").intValue();
TYPE_SHIFT = db.lookupIntConstant("Location::TYPE_SHIFT").intValue();
WHERE_MASK = db.lookupIntConstant("Location::WHERE_MASK").intValue();
WHERE_SHIFT = db.lookupIntConstant("Location::WHERE_SHIFT").intValue();
// Location::Type constants
TYPE_NORMAL = db.lookupIntConstant("Location::normal").intValue();
TYPE_OOP = db.lookupIntConstant("Location::oop").intValue();
TYPE_NARROWOOP = db.lookupIntConstant("Location::narrowoop").intValue();
TYPE_INT_IN_LONG = db.lookupIntConstant("Location::int_in_long").intValue();
TYPE_LNG = db.lookupIntConstant("Location::lng").intValue();
TYPE_FLOAT_IN_DBL = db.lookupIntConstant("Location::float_in_dbl").intValue();
TYPE_DBL = db.lookupIntConstant("Location::dbl").intValue();
TYPE_ADDR = db.lookupIntConstant("Location::addr").intValue();
TYPE_INVALID = db.lookupIntConstant("Location::invalid").intValue();
// Location::Where constants
WHERE_ON_STACK = db.lookupIntConstant("Location::on_stack").intValue();
WHERE_IN_REGISTER = db.lookupIntConstant("Location::in_register").intValue();
}
private int value;
// type safe enum for "Where"
public static class Where {
public static final Where ON_STACK = new Where("on_stack");
public static final Where IN_REGISTER = new Where("in_register");
private Where(String value) {
this.value = value;
}
public String toString() {
return value;
}
private String value;
public int getValue() {
if (this == ON_STACK) {
return WHERE_ON_STACK;
} else if (this == IN_REGISTER) {
return WHERE_IN_REGISTER;
} else {
throw new RuntimeException("should not reach here");
}
}
}
// type safe enum for "Type"
public static class Type {
Ints, floats, double halves /** Ints, floats, double halves */
public static final Type NORMAL = new Type("normal");
Oop (please GC me!) /** Oop (please GC me!) */
public static final Type OOP = new Type("oop");
NarrowOop (please GC me!) /** NarrowOop (please GC me!) */
public static final Type NARROWOOP = new Type("narrowoop");
Long held in one register /** Long held in one register */
public static final Type INT_IN_LONG = new Type("int_in_long");
Long held in one register /** Long held in one register */
public static final Type LNG = new Type("lng");
Float held in double register /** Float held in double register */
public static final Type FLOAT_IN_DBL = new Type("float_in_dbl");
Double held in one register /** Double held in one register */
public static final Type DBL = new Type("dbl");
JSR return address /** JSR return address */
public static final Type ADDR = new Type("addr");
Invalid location /** Invalid location */
public static final Type INVALID = new Type("invalid");
private Type(String value) {
this.value = value;
}
private String value;
public String toString() {
return value;
}
public int getValue() {
if (this == NORMAL) {
return TYPE_NORMAL;
} else if (this == OOP) {
return TYPE_OOP;
} else if (this == NARROWOOP) {
return TYPE_NARROWOOP;
} else if (this == INT_IN_LONG) {
return TYPE_INT_IN_LONG;
} else if (this == LNG) {
return TYPE_LNG;
} else if (this == FLOAT_IN_DBL) {
return TYPE_FLOAT_IN_DBL;
} else if (this == DBL) {
return TYPE_DBL;
} else if (this == ADDR) {
return TYPE_ADDR;
} else if (this == INVALID) {
return TYPE_INVALID;
} else {
throw new RuntimeException("should not reach here");
}
}
}
private static int OFFSET_MASK;
private static int OFFSET_SHIFT;
private static int TYPE_MASK;
private static int TYPE_SHIFT;
private static int WHERE_MASK;
private static int WHERE_SHIFT;
// constants in Type enum
private static int TYPE_NORMAL;
private static int TYPE_OOP;
private static int TYPE_NARROWOOP;
private static int TYPE_INT_IN_LONG;
private static int TYPE_LNG;
private static int TYPE_FLOAT_IN_DBL;
private static int TYPE_DBL;
private static int TYPE_ADDR;
private static int TYPE_INVALID;
// constants in Where enum
private static int WHERE_ON_STACK;
private static int WHERE_IN_REGISTER;
Create a bit-packed Location /** Create a bit-packed Location */
Location(Where where, Type type, int offset) {
setWhere(where);
setType(type);
setOffset(offset);
}
public Where getWhere() {
int where = (value & WHERE_MASK) >> WHERE_SHIFT;
if (where == WHERE_ON_STACK) {
return Where.ON_STACK;
} else if (where == WHERE_IN_REGISTER) {
return Where.IN_REGISTER;
} else {
throw new RuntimeException("should not reach here");
}
}
public Type getType() {
int type = (value & TYPE_MASK) >> TYPE_SHIFT;
if (type == TYPE_NORMAL) {
return Type.NORMAL;
} else if (type == TYPE_OOP) {
return Type.OOP;
} else if (type == TYPE_NARROWOOP) {
return Type.NARROWOOP;
} else if (type == TYPE_INT_IN_LONG) {
return Type.INT_IN_LONG;
} else if (type == TYPE_LNG) {
return Type.LNG;
} else if (type == TYPE_FLOAT_IN_DBL) {
return Type.FLOAT_IN_DBL;
} else if (type == TYPE_DBL) {
return Type.DBL;
} else if (type == TYPE_ADDR) {
return Type.ADDR;
} else if (type == TYPE_INVALID) {
return Type.INVALID;
} else {
throw new RuntimeException("should not reach here");
}
}
public short getOffset() {
return (short) ((value & OFFSET_MASK) >> OFFSET_SHIFT);
}
public boolean isRegister() {
return getWhere() == Where.IN_REGISTER;
}
public boolean isStack() {
return getWhere() == Where.ON_STACK;
}
public boolean holdsOop() {
return getType() == Type.OOP;
}
public boolean holdsNarrowOop() {
return getType() == Type.NARROWOOP;
}
public boolean holdsInt() {
return getType() == Type.INT_IN_LONG;
}
public boolean holdsLong() {
return getType() == Type.LNG;
}
public boolean holdsFloat() {
return getType() == Type.FLOAT_IN_DBL;
}
public boolean holdsDouble() {
return getType() == Type.DBL;
}
public boolean holdsAddr() {
return getType() == Type.ADDR;
}
public boolean isIllegal() {
return getType() == Type.INVALID;
}
public int getStackOffset() {
if (Assert.ASSERTS_ENABLED) {
Assert.that(getWhere() == Where.ON_STACK, "wrong Where");
}
return getOffset() * (int)VM.getVM().getIntSize();
}
public int getRegisterNumber() {
if (Assert.ASSERTS_ENABLED) {
Assert.that(getWhere() == Where.IN_REGISTER, "wrong Where");
}
return getOffset();
}
public void print() {
printOn(System.out);
}
public void printOn(PrintStream tty) {
tty.print("Value " + value + ", ");
if (isIllegal()) {
tty.print("Illegal");
} else {
Where w = getWhere();
if (w == Where.ON_STACK) {
tty.print("stack[" + getStackOffset() + "]");
} else if (w == Where.IN_REGISTER) {
tty.print("reg " + getRegisterNumber());
}
Type type = getType();
if (type == Type.NORMAL) {
} else if (type == Type.OOP) {
tty.print(",oop");
} else if (type == Type.NARROWOOP) {
tty.print(",narrowoop");
} else if (type == Type.INT_IN_LONG) {
tty.print(",int");
} else if (type == Type.LNG) {
tty.print(",long");
} else if (type == Type.FLOAT_IN_DBL) {
tty.print(",float");
} else if (type == Type.DBL) {
tty.print(",double");
} else if (type == Type.ADDR) {
tty.print(",address");
} else if (type == Type.INVALID) {
tty.print(",invalid");
}
}
}
Serialization of debugging information /** Serialization of debugging information */
public Location(DebugInfoReadStream stream) {
value = stream.readInt();
}
// FIXME: not yet implementable
// void write_on(DebugInfoWriteStream* stream);
//-----------------------------------------------------------------------------
// Internals only below this point
//
private void setWhere(Where where) {
value |= ((where.getValue() << WHERE_SHIFT) & WHERE_MASK);
}
private void setType(Type type) {
value |= ((type.getValue() << TYPE_SHIFT) & TYPE_MASK);
}
private void setOffset(int offset) {
value |= ((offset << OFFSET_SHIFT) & OFFSET_MASK);
}
}