/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* 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/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.classloader;
import org.jikesrvm.VM;
import org.jikesrvm.VM_SizeConstants;
import org.vmmagic.pragma.Uninterruptible;
/**
* A class to represent the reference in a class file to a field.
*/
public final class VM_FieldReference extends VM_MemberReference implements VM_SizeConstants {
/**
* The VM_Field that this field reference resolved to (null if not yet resolved).
*/
private VM_Field resolvedMember;
/**
* The field's type
*/
private final VM_TypeReference fieldContentsType;
/**
* @param tr a type reference
* @param mn the field or method name
* @param d the field or method descriptor
*/
VM_FieldReference(VM_TypeReference tr, VM_Atom mn, VM_Atom d) {
super(tr, mn, d);
fieldContentsType = VM_TypeReference.findOrCreate(tr.getClassLoader(), d);
}
/**
* @return the type of the field's value
*/
@Uninterruptible
public VM_TypeReference getFieldContentsType() {
return fieldContentsType;
}
/**
* How many stackslots do value of this type take?
*/
public int getNumberOfStackSlots() {
return getFieldContentsType().getStackWords();
}
/**
* Get size of the field's value, in bytes.
*/
@Uninterruptible
public int getSize() {
return fieldContentsType.getMemoryBytes();
}
/**
* Do this and that definitely refer to the different fields?
*/
public boolean definitelyDifferent(VM_FieldReference that) {
if (this == that) return false;
if (getName() != that.getName() || getDescriptor() != that.getDescriptor()) {
return true;
}
VM_Field mine = peekResolvedField(false);
VM_Field theirs = that.peekResolvedField(false);
if (mine == null || theirs == null) return false;
return mine != theirs;
}
/**
* Do this and that definitely refer to the same field?
*/
public boolean definitelySame(VM_FieldReference that) {
if (this == that) return true;
if (getName() != that.getName() || getDescriptor() != that.getDescriptor()) {
return false;
}
VM_Field mine = peekResolvedField(false);
VM_Field theirs = that.peekResolvedField(false);
if (mine == null || theirs == null) return false;
return mine == theirs;
}
/**
* Has the field reference already been resolved into a target method?
*/
public boolean isResolved() {
return resolvedMember != null;
}
/**
* For use by VM_Field constructor
*/
void setResolvedMember(VM_Field it) {
if (VM.VerifyAssertions) VM._assert(resolvedMember == null || resolvedMember == it);
resolvedMember = it;
}
/**
* Find the VM_Field that this field reference refers to using
* the search order specified in JVM spec 5.4.3.2.
* @return the VM_Field that this method ref resolved to or null if it cannot be resolved.
*/
public VM_Field peekResolvedField(boolean forSubArch) {
if (resolvedMember != null) return resolvedMember;
// Hasn't been resolved yet. Try to do it now without triggering class loading.
VM_Class declaringClass = (VM_Class) type.peekType();
if (declaringClass == null) return null;
return resolveInternal(declaringClass, forSubArch);
}
/**
* Find the VM_Field that this field reference refers to using
* the search order specified in JVM spec 5.4.3.2.
* @return the VM_Field that this method ref resolved to.
*/
public synchronized VM_Field resolve(boolean forSubArch) {
if (resolvedMember != null) return resolvedMember;
// Hasn't been resolved yet. Do it now triggering class loading if necessary.
return resolveInternal((VM_Class) type.resolve(forSubArch), forSubArch);
}
private VM_Field resolveInternal(VM_Class declaringClass, boolean forSubArch) {
if (!declaringClass.isResolved(forSubArch)) {
declaringClass.resolve(forSubArch);
}
for (VM_Class c = declaringClass; c != null; c = c.getSuperClass()) {
// Look in this class
VM_Field it = c.findDeclaredField(name, descriptor);
if (it != null) {
resolvedMember = it;
return resolvedMember;
}
// Look at all interfaces directly and indirectly implemented by this class.
for (VM_Class i : c.getDeclaredInterfaces()) {
it = searchInterfaceFields(i);
if (it != null) {
resolvedMember = it;
return resolvedMember;
}
}
}
throw new NoSuchFieldError(this.toString());
}
private VM_Field searchInterfaceFields(VM_Class c) {
VM_Field it = c.findDeclaredField(name, descriptor);
if (it != null) return it;
for (VM_Class i : c.getDeclaredInterfaces()) {
it = searchInterfaceFields(i);
if (it != null) return it;
}
return null;
}
}