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 ({@code 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    }