001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.classloader;
014
015 import org.jikesrvm.VM;
016 import org.jikesrvm.SizeConstants;
017 import org.vmmagic.pragma.Uninterruptible;
018
019 /**
020 * A class to represent the reference in a class file to a field.
021 */
022 public final class FieldReference extends MemberReference implements SizeConstants {
023
024 /**
025 * The field's type
026 */
027 private final TypeReference fieldContentsType;
028
029 /**
030 * The RVMField that this field reference resolved to (null if not yet resolved).
031 */
032 private RVMField resolvedMember;
033
034 /**
035 * @param tr a type reference
036 * @param mn the field or method name
037 * @param d the field or method descriptor
038 * @param id the new ID of the member were a new member required
039 */
040 FieldReference(TypeReference tr, Atom mn, Atom d, int id) {
041 super(tr, mn, d, id);
042 fieldContentsType = TypeReference.findOrCreate(tr.getClassLoader(), d);
043 }
044
045 /**
046 * @return the type of the field's value
047 */
048 @Uninterruptible
049 public TypeReference getFieldContentsType() {
050 return fieldContentsType;
051 }
052
053 /**
054 * How many stackslots do value of this type take?
055 */
056 public int getNumberOfStackSlots() {
057 return getFieldContentsType().getStackWords();
058 }
059
060 /**
061 * Get size of the field's value, in bytes.
062 */
063 @Uninterruptible
064 public int getSize() {
065 return fieldContentsType.getMemoryBytes();
066 }
067
068 /**
069 * Do this and that definitely refer to the different fields?
070 */
071 public boolean definitelyDifferent(FieldReference that) {
072 if (this == that) return false;
073 if (getName() != that.getName() || getDescriptor() != that.getDescriptor()) {
074 return true;
075 }
076 RVMField mine = peekResolvedField();
077 RVMField theirs = that.peekResolvedField();
078 if (mine == null || theirs == null) return false;
079 return mine != theirs;
080 }
081
082 /**
083 * Do this and that definitely refer to the same field?
084 */
085 public boolean definitelySame(FieldReference that) {
086 if (this == that) return true;
087 if (getName() != that.getName() || getDescriptor() != that.getDescriptor()) {
088 return false;
089 }
090 RVMField mine = peekResolvedField();
091 RVMField theirs = that.peekResolvedField();
092 if (mine == null || theirs == null) return false;
093 return mine == theirs;
094 }
095
096 /**
097 * Has the field reference already been resolved into a target method?
098 */
099 public boolean isResolved() {
100 return resolvedMember != null;
101 }
102
103 /**
104 * For use by RVMField constructor
105 */
106 void setResolvedMember(RVMField it) {
107 if (VM.VerifyAssertions) VM._assert(resolvedMember == null || resolvedMember == it);
108 resolvedMember = it;
109 }
110
111 /**
112 * Find the RVMField that this field reference refers to using
113 * the search order specified in JVM spec 5.4.3.2.
114 * @return the RVMField that this method ref resolved to or null if it cannot be resolved.
115 */
116 public RVMField peekResolvedField() {
117 if (resolvedMember != null) return resolvedMember;
118
119 // Hasn't been resolved yet. Try to do it now without triggering class loading.
120 RVMClass declaringClass = (RVMClass) type.peekType();
121 if (declaringClass == null) return null;
122 return resolveInternal(declaringClass);
123 }
124
125 /**
126 * Find the RVMField that this field reference refers to using
127 * the search order specified in JVM spec 5.4.3.2.
128 * @return the RVMField that this method ref resolved to.
129 */
130 public synchronized RVMField resolve() {
131 if (resolvedMember != null) return resolvedMember;
132
133 // Hasn't been resolved yet. Do it now triggering class loading if necessary.
134 return resolveInternal((RVMClass) type.resolve());
135 }
136
137 private RVMField resolveInternal(RVMClass declaringClass) {
138 if (!declaringClass.isResolved()) {
139 declaringClass.resolve();
140 }
141 for (RVMClass c = declaringClass; c != null; c = c.getSuperClass()) {
142 // Look in this class
143 RVMField it = c.findDeclaredField(name, descriptor);
144 if (it != null) {
145 resolvedMember = it;
146 return resolvedMember;
147 }
148 // Look at all interfaces directly and indirectly implemented by this class.
149 for (RVMClass i : c.getDeclaredInterfaces()) {
150 it = searchInterfaceFields(i);
151 if (it != null) {
152 resolvedMember = it;
153 return resolvedMember;
154 }
155 }
156 }
157 throw new NoSuchFieldError(this.toString());
158 }
159
160 private RVMField searchInterfaceFields(RVMClass c) {
161 RVMField it = c.findDeclaredField(name, descriptor);
162 if (it != null) return it;
163 for (RVMClass i : c.getDeclaredInterfaces()) {
164 it = searchInterfaceFields(i);
165 if (it != null) return it;
166 }
167 return null;
168 }
169 }