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 */ 013package org.jikesrvm.classloader; 014 015import org.jikesrvm.VM; 016import org.vmmagic.pragma.Uninterruptible; 017 018/** 019 * A class to represent the reference in a class file to a field. 020 */ 021public final class FieldReference extends MemberReference { 022 023 /** 024 * The field's type 025 */ 026 private final TypeReference fieldContentsType; 027 028 /** 029 * The RVMField that this field reference resolved to ({@code null} if not yet resolved). 030 */ 031 private RVMField resolvedMember; 032 033 /** 034 * @param tr a type reference 035 * @param mn the field or method name 036 * @param d the field or method descriptor 037 * @param id the new ID of the member were a new member required 038 */ 039 FieldReference(TypeReference tr, Atom mn, Atom d, int id) { 040 super(tr, mn, d, id); 041 fieldContentsType = TypeReference.findOrCreate(tr.getClassLoader(), d); 042 } 043 044 /** 045 * @return the type of the field's value 046 */ 047 @Uninterruptible 048 public TypeReference getFieldContentsType() { 049 return fieldContentsType; 050 } 051 052 /** 053 * @return number of stack slots that a value of this type takes 054 */ 055 public int getNumberOfStackSlots() { 056 return getFieldContentsType().getStackWords(); 057 } 058 059 /** 060 * @return size of the field's value, in bytes. 061 */ 062 @Uninterruptible 063 public int getSize() { 064 return fieldContentsType.getMemoryBytes(); 065 } 066 067 /** 068 * Do this and that definitely refer to different fields? 069 * 070 * @param that the reference to compare with 071 * @return {@code true} if the fields are definitely different, {@code false} 072 * if it's not known (e.g. because at least one of the field references is 073 * unresolved) 074 */ 075 public boolean definitelyDifferent(FieldReference that) { 076 if (this == that) return false; 077 if (getName() != that.getName() || getDescriptor() != that.getDescriptor()) { 078 return true; 079 } 080 RVMField mine = peekResolvedField(); 081 RVMField theirs = that.peekResolvedField(); 082 if (mine == null || theirs == null) return false; 083 return mine != theirs; 084 } 085 086 /** 087 * Do this and that definitely refer to the same field? 088 * 089 * @param that the reference to compare with 090 * @return {@code true} if the fields are definitely the same, {@code false} 091 * if it's not known (e.g. because at least one of the field references is 092 * unresolved) 093 */ 094 public boolean definitelySame(FieldReference that) { 095 if (this == that) return true; 096 if (getName() != that.getName() || getDescriptor() != that.getDescriptor()) { 097 return false; 098 } 099 RVMField mine = peekResolvedField(); 100 RVMField theirs = that.peekResolvedField(); 101 if (mine == null || theirs == null) return false; 102 return mine == theirs; 103 } 104 105 /** 106 * @return {@code true} if the field reference already been resolved into a target method 107 */ 108 public boolean isResolved() { 109 return resolvedMember != null; 110 } 111 112 void setResolvedMember(RVMField it) { 113 if (VM.VerifyAssertions) VM._assert(resolvedMember == null || resolvedMember == it); 114 resolvedMember = it; 115 } 116 117 /** 118 * Find the RVMField that this field reference refers to using 119 * the search order specified in JVM spec 5.4.3.2. 120 * @return the RVMField that this method ref resolved to or null if it cannot be resolved. 121 */ 122 public RVMField peekResolvedField() { 123 if (resolvedMember != null) return resolvedMember; 124 125 // Hasn't been resolved yet. Try to do it now without triggering class loading. 126 RVMClass declaringClass = (RVMClass) type.peekType(); 127 if (declaringClass == null) return null; 128 return resolveInternal(declaringClass); 129 } 130 131 /** 132 * Find the RVMField that this field reference refers to using 133 * the search order specified in JVM spec 5.4.3.2. 134 * @return the RVMField that this method ref resolved to. 135 */ 136 public synchronized RVMField resolve() { 137 if (resolvedMember != null) return resolvedMember; 138 139 // Hasn't been resolved yet. Do it now triggering class loading if necessary. 140 return resolveInternal((RVMClass) type.resolve()); 141 } 142 143 private RVMField resolveInternal(RVMClass declaringClass) { 144 if (!declaringClass.isResolved()) { 145 declaringClass.resolve(); 146 } 147 for (RVMClass c = declaringClass; c != null; c = c.getSuperClass()) { 148 // Look in this class 149 RVMField it = c.findDeclaredField(name, descriptor); 150 if (it != null) { 151 resolvedMember = it; 152 return resolvedMember; 153 } 154 // Look at all interfaces directly and indirectly implemented by this class. 155 for (RVMClass i : c.getDeclaredInterfaces()) { 156 it = searchInterfaceFields(i); 157 if (it != null) { 158 resolvedMember = it; 159 return resolvedMember; 160 } 161 } 162 } 163 throw new NoSuchFieldError(this.toString()); 164 } 165 166 private RVMField searchInterfaceFields(RVMClass c) { 167 RVMField it = c.findDeclaredField(name, descriptor); 168 if (it != null) return it; 169 for (RVMClass i : c.getDeclaredInterfaces()) { 170 it = searchInterfaceFields(i); 171 if (it != null) return it; 172 } 173 return null; 174 } 175}