/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.osr;
import static org.jikesrvm.osr.OSRConstants.DOUBLE;
import static org.jikesrvm.osr.OSRConstants.FLOAT;
import static org.jikesrvm.osr.OSRConstants.INT;
import static org.jikesrvm.osr.OSRConstants.LOCAL;
import static org.jikesrvm.osr.OSRConstants.LONG;
import static org.jikesrvm.osr.OSRConstants.REF;
import static org.jikesrvm.osr.OSRConstants.RET_ADDR;
import static org.jikesrvm.osr.OSRConstants.WORD;
import org.jikesrvm.VM;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.util.Services;
import org.vmmagic.unboxed.Word;
/**
* An instance of VariableElement represents a byte code variable
* (local or stack element). It is used to generate prologue to
* recover the runtime state. It refers to VM architecture.
*/
public class VariableElement {
//////////////////////////////////
// instance fields
//////////////////////////////////
/** the kind of this element : LOCAL or STACK */
private final boolean kind;
/**
* the number of element, e.g., with kind we
* can know it is L0 or S1.
*/
private final char num;
/** type code, can only be INT, FLOAT, LONG, DOUBLE, RET_ADDR, WORD or REF */
private final byte tcode;
/**
* The value of this element.
* For type INT, FLOAT, RET_ADDR and WORD (32-bit), the lower 32 bits are valid.
* For type LONG and DOUBLE and WORD(64-bit), 64 bits are valid.
* For REF type, next field 'ref' is valid.
*
* For FLOAT, and DOUBLE, use Magic.intBitsAsFloat
* or Magic.longBitsAsDouble
* to convert bits to floating-point value.
*/
private final long value;
/** for reference type value */
private final Object ref;
//////////////////////////////////
// class auxiliary methods
/////////////////////////////////
static boolean isIBitsType(int tcode) {
switch (tcode) {
case INT:
case FLOAT:
case RET_ADDR:
return true;
case WORD:
return VM.BuildFor32Addr;
default:
return false;
}
}
static boolean isLBitsType(int tcode) {
switch (tcode) {
case LONG:
case DOUBLE:
return true;
case WORD:
return VM.BuildFor64Addr;
default:
return false;
}
}
static boolean isRefType(int tcode) {
return tcode == REF;
}
static boolean isWordType(int tcode) {
return tcode == WORD;
}
//////////////////////////////////////
// Initializer
/////////////////////////////////////
/**
* Constructor for 32-bit value.
*
* @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
* @param which_num the variable's number
* @param type the variable's type code
* @param ibits the variable's value
*/
public VariableElement(boolean what_kind, int which_num, byte type, int ibits) {
if (VM.VerifyAssertions) {
VM._assert(isIBitsType(type));
VM._assert(which_num < 0xFFFF);
}
this.kind = what_kind;
this.num = (char)which_num;
this.tcode = type;
this.value = ibits & 0x0FFFFFFFFL;
this.ref = null;
}
/**
* Constructor for 64-bit value.
*
* @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
* @param which_num the variable's number
* @param type the variable's type code
* @param lbits the variable's value
*/
public VariableElement(boolean what_kind, int which_num, byte type, long lbits) {
if (VM.VerifyAssertions) {
VM._assert(isLBitsType(type));
VM._assert(which_num < 0xFFFF);
}
this.kind = what_kind;
this.num = (char)which_num;
this.tcode = type;
this.value = lbits;
this.ref = null;
}
/**
* Constructor for reference type.
*
* @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
* @param which_num the variable's number
* @param type the variable's type code
* @param ref the reference
*/
public VariableElement(boolean what_kind, int which_num, byte type, Object ref) {
if (VM.VerifyAssertions) {
VM._assert(isRefType(type));
VM._assert(which_num < 0xFFFF);
}
this.kind = what_kind;
this.num = (char)which_num;
this.tcode = type;
this.value = 0;
this.ref = ref;
}
/**
* Constructor for word type.
*
* @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
* @param which_num the variable's number
* @param type the variable's type code
* @param word the word
*/
public VariableElement(boolean what_kind, int which_num, byte type, Word word) {
if (VM.VerifyAssertions) {
VM._assert(isWordType(type));
VM._assert(which_num < 0xFFFF);
}
this.kind = what_kind;
this.num = (char)which_num;
this.tcode = type;
if (VM.BuildFor32Addr) {
this.value = (word.toInt()) & 0x0FFFFFFFFL;
} else {
this.value = word.toLong();
}
this.ref = null;
}
////////////////////////////////
// instance method
////////////////////////////////
/** @return whether this is a local or stack element */
boolean isLocal() {
return kind == LOCAL;
}
byte getTypeCode() {
return tcode;
}
char getNumber() {
return num;
}
boolean isRefType() {
return (this.tcode == REF);
}
Object getObject() {
return ref;
}
boolean isWordType() {
return (this.tcode == WORD);
}
Word getWord() {
return (VM.BuildFor32Addr) ? Word.fromIntSignExtend((int) value) : Word.fromLong(value);
}
int getIntBits() {
return (int) (value & 0x0FFFFFFFF);
}
long getLongBits() {
return value;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder("(");
if (kind == LOCAL) {
buf.append('L');
} else {
buf.append('S');
}
buf.append((int)num);
buf.append(",");
char t = 'V';
switch (tcode) {
case INT:
t = 'I';
break;
case FLOAT:
t = 'F';
break;
case LONG:
t = 'J';
break;
case DOUBLE:
t = 'D';
break;
case RET_ADDR:
t = 'R';
break;
case REF:
t = 'L';
break;
case WORD:
t = 'W';
break;
}
buf.append(t);
buf.append(",");
switch (tcode) {
case REF:
// it is legal to have a null reference.
if (ref == null) {
buf.append("null");
} else {
buf.append(Services.addressAsHexString(Magic.objectAsAddress(ref)));
buf.append(" ");
// buf.append(ref.toString());
}
break;
case WORD:
buf.append("0x");
if (VM.BuildFor32Addr) {
buf.append(Integer.toHexString((int) (value & 0x0FFFFFFFFL)));
} else {
buf.append(Long.toHexString(value));
}
buf.append(" ");
break;
case FLOAT:
buf.append(Magic.intBitsAsFloat((int) (value & 0x0FFFFFFFF)));
break;
case LONG:
buf.append(value);
break;
case DOUBLE:
buf.append(Magic.longBitsAsDouble(value));
break;
default:
buf.append((int) (value & 0x0FFFFFFFF));
break;
}
buf.append(")");
return buf.toString();
}
}