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 }