1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.vm.ci.hotspot; 24 25 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; 26 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; 27 28 import java.lang.annotation.Annotation; 29 import java.lang.reflect.Field; 30 31 import jdk.vm.ci.common.JVMCIError; 32 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; 33 import jdk.vm.ci.meta.JavaType; 34 import jdk.vm.ci.meta.LocationIdentity; 35 import jdk.vm.ci.meta.MetaAccessProvider; 36 import jdk.vm.ci.meta.ModifiersProvider; 37 import jdk.vm.ci.meta.ResolvedJavaField; 38 import jdk.vm.ci.meta.ResolvedJavaType; 39 40 /** 41 * Represents a field in a HotSpot type. 42 */ 43 class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { 44 45 /** 46 * Mark well-known stable fields as such. 47 */ 48 private static final boolean ImplicitStableValues = HotSpotJVMCIRuntime.getBooleanProperty(Option.ImplicitStableValues, true); 49 50 private final HotSpotResolvedObjectTypeImpl holder; 51 private final String name; 52 private JavaType type; 53 private final int offset; 54 55 /** 56 * This value contains all flags as stored in the VM including internal ones. 57 */ 58 private final int modifiers; 59 private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); 60 61 public static class FieldLocationIdentity extends LocationIdentity { 62 HotSpotResolvedJavaField inner; 63 64 public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { 65 this.inner = inner; 66 } 67 68 @Override 69 public boolean isImmutable() { 70 return false; 71 } 72 73 @Override 74 public boolean equals(Object obj) { 75 if (this == obj) { 76 return true; 77 } 78 if (obj instanceof FieldLocationIdentity) { 79 FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; 80 return inner.equals(fieldLocationIdentity.inner); 81 82 } 83 return false; 84 } 85 86 @Override 87 public int hashCode() { 88 return inner.hashCode(); 89 } 90 91 @Override 92 public String toString() { 93 return inner.getName(); 94 } 95 } 96 97 HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { 98 this.holder = holder; 99 this.name = name; 100 this.type = type; 101 assert offset != -1; 102 assert offset == (int) offset : "offset larger than int"; 103 this.offset = (int) offset; 104 this.modifiers = modifiers; 105 } 106 107 @Override 108 public boolean equals(Object obj) { 109 if (this == obj) { 110 return true; 111 } 112 if (obj instanceof HotSpotResolvedJavaField) { 113 HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; 114 if (that.offset != this.offset || that.isStatic() != this.isStatic()) { 115 return false; 116 } else if (this.holder.equals(that.holder)) { 117 assert this.name.equals(that.name) && this.type.equals(that.type); 118 return true; 119 } 120 } 121 return false; 122 } 123 124 @Override 125 public int hashCode() { 126 return name.hashCode(); 127 } 128 129 @Override 130 public int getModifiers() { 131 return modifiers & ModifiersProvider.jvmFieldModifiers(); 132 } 133 134 @Override 135 public boolean isInternal() { 136 return (modifiers & config().jvmAccFieldInternal) != 0; 137 } 138 139 /** 140 * Determines if a given object contains this field. 141 * 142 * @return true iff this is a non-static field and its declaring class is assignable from 143 * {@code object}'s class 144 */ 145 public boolean isInObject(Object object) { 146 if (isStatic()) { 147 return false; 148 } 149 return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass())); 150 } 151 152 @Override 153 public HotSpotResolvedObjectTypeImpl getDeclaringClass() { 154 return holder; 155 } 156 157 @Override 158 public String getName() { 159 return name; 160 } 161 162 @Override 163 public JavaType getType() { 164 // Pull field into local variable to prevent a race causing 165 // a ClassCastException below 166 JavaType currentType = type; 167 if (currentType instanceof HotSpotUnresolvedJavaType) { 168 // Don't allow unresolved types to hang around forever 169 HotSpotUnresolvedJavaType unresolvedType = (HotSpotUnresolvedJavaType) currentType; 170 ResolvedJavaType resolved = unresolvedType.reresolve(holder); 171 if (resolved != null) { 172 type = resolved; 173 } 174 } 175 return type; 176 } 177 178 public int offset() { 179 return offset; 180 } 181 182 @Override 183 public String toString() { 184 return format("HotSpotField<%H.%n %t:") + offset + ">"; 185 } 186 187 @Override 188 public boolean isSynthetic() { 189 return (config().jvmAccSynthetic & modifiers) != 0; 190 } 191 192 /** 193 * Checks if this field has the {@link Stable} annotation. 194 * 195 * @return true if field has {@link Stable} annotation, false otherwise 196 */ 197 public boolean isStable() { 198 if ((config().jvmAccFieldStable & modifiers) != 0) { 199 return true; 200 } 201 assert getAnnotation(Stable.class) == null; 202 if (ImplicitStableValues && isImplicitStableField()) { 203 return true; 204 } 205 return false; 206 } 207 208 @Override 209 public Annotation[] getAnnotations() { 210 Field javaField = toJava(); 211 if (javaField != null) { 212 return javaField.getAnnotations(); 213 } 214 return new Annotation[0]; 215 } 216 217 @Override 218 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 219 Field javaField = toJava(); 220 if (javaField != null) { 221 return javaField.getAnnotation(annotationClass); 222 } 223 return null; 224 } 225 226 private Field toJavaCache; 227 228 private Field toJava() { 229 if (toJavaCache != null) { 230 return toJavaCache; 231 } 232 233 if (isInternal()) { 234 return null; 235 } 236 try { 237 return toJavaCache = holder.mirror().getDeclaredField(name); 238 } catch (NoSuchFieldException | NoClassDefFoundError e) { 239 return null; 240 } 241 } 242 243 private boolean isArray() { 244 JavaType fieldType = getType(); 245 return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); 246 } 247 248 private boolean isImplicitStableField() { 249 if (isSyntheticEnumSwitchMap()) { 250 return true; 251 } 252 if (isWellKnownImplicitStableField()) { 253 return true; 254 } 255 return false; 256 } 257 258 public boolean isDefaultStable() { 259 assert this.isStable(); 260 if (isSyntheticEnumSwitchMap()) { 261 return true; 262 } 263 return false; 264 } 265 266 private boolean isSyntheticEnumSwitchMap() { 267 if (isSynthetic() && isStatic() && isArray()) { 268 if (isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { 269 // generated int[] field for EnumClass::values() 270 return true; 271 } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { 272 // javac and ecj generate a static field in an inner class for a switch on an enum 273 // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively 274 return true; 275 } 276 } 277 return false; 278 } 279 280 private boolean isWellKnownImplicitStableField() { 281 return WellKnownImplicitStableField.test(this); 282 } 283 284 static class WellKnownImplicitStableField { 285 /** 286 * @return {@code true} if the field is a well-known stable field. 287 */ 288 public static boolean test(HotSpotResolvedJavaField field) { 289 return field.equals(STRING_VALUE_FIELD); 290 } 291 292 private static final ResolvedJavaField STRING_VALUE_FIELD; 293 294 static { 295 try { 296 MetaAccessProvider metaAccess = runtime().getHostJVMCIBackend().getMetaAccess(); 297 STRING_VALUE_FIELD = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); 298 } catch (SecurityException | NoSuchFieldException e) { 299 throw new JVMCIError(e); 300 } 301 } 302 } 303 304 public LocationIdentity getLocationIdentity() { 305 return locationIdentity; 306 } 307 }