/*
* @(#)FMIrefConstant.java 1.21 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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 program 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 at /legal/license.txt).
*
* 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 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package components;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import consts.Const;
import jcc.Str2ID;
import util.Assert;
import util.*;
/**
* An abstract class to represent CP constants which define class members.
* This class will serve as a common super class for the classes which will
* contain the CP constants: CONSTANT_Fieldref, CONSTANT_Methodref, and
* CONSTANT_InterfaceMethodref.
*/
public abstract
class FMIrefConstant extends ConstantObject
{
// These fields are filled in by Clas.resolveConstant().
public NameAndTypeConstant sig;
public ClassConstant clas;
boolean computedID;
int ID;
// These fields are read from the class file
public int classIndex;
public int sigIndex;
FMIrefConstant(int tag) { super(tag); }
protected FMIrefConstant(int tag, ClassConstant c, NameAndTypeConstant s) {
super(tag);
clas = c;
sig = s;
isFlat = true;
}
/**
* Read in the constant pool data for this constant member object.
* This method should only be called by the read() factory methods of
* its concrete subclasses.
*/
protected void readIndexes(DataInput in) throws IOException {
classIndex = in.readUnsignedShort();
sigIndex = in.readUnsignedShort();
}
public void flatten(ConstantPool cp) {
if (isFlat) return;
Assert.disallowClassloading();
sig = (NameAndTypeConstant)cp.elementAt(sigIndex);
clas = (ClassConstant)cp.elementAt(classIndex);
isFlat = true;
Assert.allowClassloading();
}
public void write(DataOutput out) throws IOException {
out.writeByte(tag);
if (isFlat) {
out.writeShort(clas.index);
out.writeShort(sig.index);
} else {
throw new DataFormatException(Localizer.getString(
"fmirefconstant.unresolved_fmirefconstant.dataformatexception"));
//out.writeShort( classIndex );
//out.writeShort( sigIndex );
}
}
public String toString(){
String t = (tag==Const.CONSTANT_FIELD)?/*NOI18N*/"FieldRef: ":
(tag==Const.CONSTANT_METHOD)?/*NOI18N*/"MethodRef: ":
/*NOI18N*/"InterfaceRef: ";
if (isFlat)
return t+clas.name.string+/*NOI18N*/" . "+
sig.name.string+/*NOI18N*/" : "+sig.type.string;
else
return t+/*NOI18N*/"[ "+classIndex+/*NOI18N*/" . "+
sigIndex+/*NOI18N*/" ]";
}
public String prettyPrint(){
switch (tag){
case Const.CONSTANT_FIELD:
return Localizer.getString("classclass.field_with_class",
clas.name, sig.name);
case Const.CONSTANT_METHOD:
case Const.CONSTANT_INTERFACEMETHOD:
return Localizer.getString("classclass.method_with_class",
clas.name, sig.name, sig.type);
default:
return toString();
}
}
public void incReference() {
super.incReference();
// if this member reference is not resolved,
// then the sig & class entries must also be in the
// constant pool.
if (!isResolved()){
sig.incReference();
clas.incReference();
}
}
public void decReference() {
super.decReference();
sig.decReference();
clas.decReference();
}
public int hashCode() {
return tag + sig.hashCode() + clas.hashCode();
}
public boolean equals(Object o) {
if (o instanceof FMIrefConstant) {
FMIrefConstant f = (FMIrefConstant) o;
return tag == f.tag && clas.name.equals(f.clas.name) &&
sig.name.equals(f.sig.name) && sig.type.equals(f.sig.type);
} else {
return false;
}
}
public int getID(){
if ( ! computedID ){
ID = Str2ID.sigHash.getID( sig.name, sig.type );
computedID = true;
}
return ID;
}
private ClassComponent findMember(ClassMemberInfo[] t, int thisID) {
for (int i = 0; i < t.length; i++) {
if (thisID == t[i].getID()) {
return t[i];
}
}
return null;
}
// Recursively looks up a method (specified by thisID) in the interfaces
// that class c implements and their superinterfaces.
private ClassComponent findMethodInSuperInterfaces(ClassInfo c, int thisID) {
ClassComponent m;
ClassMemberInfo t[];
// Fail if no interfaces to check:
if (c.interfaces == null) {
return null;
}
// Search direct superinterfaces:
for (int j = 0; j < c.interfaces.length; j++) {
ClassInfo itf = (c.interfaces[j]).find();
if (itf != null) {
t = (ClassMemberInfo[])itf.methods;
m = findMember(t, thisID);
if (m != null) {
return m;
} else {
// Search superinterface's superface:
m = findMethodInSuperInterfaces(itf, thisID);
if (m != null) {
return m;
}
}
}
}
return null;
}
// Recursively looks up a field (specified by thisID) in the interfaces
// that class c implements and their superinterfaces.
private ClassComponent findFieldInSuperInterfaces(ClassInfo c, int thisID) {
ClassComponent m;
ClassMemberInfo t[];
// Fail if no interfaces to check:
if (c.interfaces == null) {
return null;
}
// Search direct superinterfaces:
for (int j = 0; j < c.interfaces.length; j++) {
ClassInfo itf = (c.interfaces[j]).find();
if (itf != null) {
t = (ClassMemberInfo[])itf.fields;
m = findMember(t, thisID);
if (m != null) {
return m;
} else {
// Search superinterface's superface:
m = findFieldInSuperInterfaces(itf, thisID);
if (m != null) {
return m;
}
}
}
}
return null;
}
public ClassComponent find (int tag) {
if ( ! computedID ){
ID = Str2ID.sigHash.getID( sig.name, sig.type );
computedID = true;
}
ClassComponent m;
ClassInfo c = clas.find();
int thisID = this.getID();
ClassMemberInfo t[];
/* If the class itself is unresolved, all members are too */
if (c == null){
return null;
}
if (tag == Const.CONSTANT_METHOD) {
ClassInfo origClass = c;
// Verify some assertions:
if (c.isInterface()) {
System.err.println(Localizer.getString(
"fmirefconstant.class_should_be_a_class", c));
return null;
}
// Method resolution follows the lookup order specified in the
// VM spec ($5.4.3.3).
//
// 1. Look up method in the current class.
// 2. Look up method in the superclasses recursively.
// 3. If not found, look up method in superinterfaces
// recursively.
// 1. Lookup method in the current class, and
// 2. Lookup method in the superclasses:
while (c != null) {
// First, search for the method in the current class:
t = (ClassMemberInfo[])c.methods;
m = findMember(t, thisID);
if (m != null) {
return m;
}
// If not found, try again with the superclass:
c = c.superClassInfo;
}
// 3. Lookup method in the superinterfaces:
c = origClass;
while (c != null) {
// First, search for the method in the implemented interfaces
// and their superinterfaces:
m = findMethodInSuperInterfaces(c, thisID);
if (m != null) {
return m;
}
// If not found, repeat for interface methods in superclass:
c = c.superClassInfo;
}
// 4. If still not found, method/interfacemethod lookup fails.
} else if (tag == Const.CONSTANT_INTERFACEMETHOD) {
ClassInfo origClass = c;
// Verify some assertions:
if (!c.isInterface()) {
System.err.println(Localizer.getString(
"fmirefconstant.class_should_be_an_interface", c));
return null;
}
// NOTE: In the case of Const.CONSTANT_INTERFACEMETHOD, then
// there can only be one superclass i.e. java.lang.Object.
ClassInfo cSuper = c.superClassInfo;
if (!cSuper.isJavaLangObject()) {
System.err.println(Localizer.getString(
"fmirefconstant.interface_super_should_be_java_lang_object",
c, cSuper));
return null;
}
// InterfaceMethod resolution follows the lookup order specifed
// in the VM spec ($5.4.3.4).
//
// 1. Look up method in the current interface.
// 2. If not found, look up method in superclass
// java.lang.Object (including its interfaces).
// 1. Lookup method in the current class:
t = (ClassMemberInfo[])c.methods;
m = findMember(t, thisID);
if (m != null) {
return m;
}
// Lookup method in the implemented interfaces and their
// superinterfaces:
m = findMethodInSuperInterfaces(c, thisID);
if (m != null) {
return m;
}
// 2. Lookup method in the super class:
t = (ClassMemberInfo[])cSuper.methods;
m = findMember(t, thisID);
if (m != null) {
return m;
}
// Lookup method in the implemented interfaces and their
// superinterfaces:
m = findMethodInSuperInterfaces(cSuper, thisID);
if (m != null) {
return m;
}
// 3. If still not found, method/interfacemethod lookup fails.
} else {
// tag should be Const.CONSTANT_FIELD.
// Field resolution follows the lookup order specified in the
// VM spec ($5.4.3.2).
//
// 1. Look up field in current class.
// 2. If not found, look up field in implemented interfaces
// and their super-interfaces.
// 3. If not found, recurse into the superclass of the current
// class and repeat steps 1, 2, and 3 as necessary.
while (c != null) {
// 1. Lookup field in the current class:
t = (ClassMemberInfo[])c.fields;
m = findMember(t, thisID);
if (m != null) {
return m;
}
// 2. Lookup field in implemented interfaces and recursively
// in their implemented superinterfaces:
m = findFieldInSuperInterfaces(c, thisID);
if (m != null) {
return m;
}
// 3. Otherwise, repeat with superclass: */
c = c.superClassInfo;
}
// 4. If still not found, field lookup fails.
}
return null;
}
/*
* validate: see ConstantObject.validate. The clas and sig entries may
* or may not end up in any constant pool. If they do it can be because
* of a reference from this entry.
*/
public boolean isResolved(){ return find(tag) != null; }
}