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.meta.JavaType; 33 import jdk.vm.ci.meta.LocationIdentity; 34 import jdk.vm.ci.meta.MetaAccessProvider; 35 import jdk.vm.ci.meta.ModifiersProvider; 36 import jdk.vm.ci.meta.ResolvedJavaField; 37 import jdk.vm.ci.meta.ResolvedJavaType; 38 39 /** 40 * Represents a field in a HotSpot type. 41 */ 42 class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { 43 44 /** 45 * Mark well-known stable fields as such. 46 */ 47 private static final boolean ImplicitStableValues = HotSpotJVMCIRuntime.getBooleanProperty("ImplicitStableValues", true); 48 49 private final HotSpotResolvedObjectTypeImpl holder; 50 private final String name; 51 private JavaType type; 52 private final int offset; 53 54 /** 55 * This value contains all flags as stored in the VM including internal ones. 56 */ 57 private final int modifiers; 58 private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); 59 60 public static class FieldLocationIdentity extends LocationIdentity { 61 HotSpotResolvedJavaField inner; 62 63 public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { 64 this.inner = inner; 65 } 66 67 @Override 68 public boolean isImmutable() { 69 return false; 70 } 71 72 @Override 73 public boolean equals(Object obj) { 74 if (this == obj) { 75 return true; 76 } 77 if (obj instanceof FieldLocationIdentity) { 78 FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; 79 return inner.equals(fieldLocationIdentity.inner); 80 81 } 82 return false; 83 } 84 85 @Override 86 public int hashCode() { 87 return inner.hashCode(); 88 } 89 90 @Override 91 public String toString() { 92 return inner.getName(); 93 } 94 } 95 96 HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { 97 this.holder = holder; 98 this.name = name; 99 this.type = type; 100 assert offset != -1; 101 assert offset == (int) offset : "offset larger than int"; 102 this.offset = (int) offset; 103 this.modifiers = modifiers; 104 } 105 106 @Override 107 public boolean equals(Object obj) { 108 if (this == obj) { 109 return true; 110 } 111 if (obj instanceof HotSpotResolvedJavaField) { 112 HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; 113 if (that.offset != this.offset || that.isStatic() != this.isStatic()) { 114 return false; 115 } else if (this.holder.equals(that.holder)) { 116 assert this.name.equals(that.name) && this.type.equals(that.type); 117 return true; 118 } 119 } 120 return false; 121 } 122 123 @Override 124 public int hashCode() { 125 return name.hashCode(); 126 } 127 128 @Override 129 public int getModifiers() { 130 return modifiers & ModifiersProvider.jvmFieldModifiers(); 131 } 132 133 @Override 134 public boolean isInternal() { 135 return (modifiers & config().jvmAccFieldInternal) != 0; 136 } 137 138 /** 139 * Determines if a given object contains this field. 140 * 141 * @return true iff this is a non-static field and its declaring class is assignable from 142 * {@code object}'s class 143 */ 144 public boolean isInObject(Object object) { 145 if (isStatic()) { 146 return false; 147 } 148 return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass())); 149 } 150 151 @Override 152 public HotSpotResolvedObjectTypeImpl getDeclaringClass() { 153 return holder; 154 } 155 156 @Override 157 public String getName() { 158 return name; 159 } 160 161 @Override 162 public JavaType getType() { 163 // Pull field into local variable to prevent a race causing 164 // a ClassCastException below 165 JavaType currentType = type; 166 if (currentType instanceof HotSpotUnresolvedJavaType) { 167 // Don't allow unresolved types to hang around forever 168 HotSpotUnresolvedJavaType unresolvedType = (HotSpotUnresolvedJavaType) currentType; 169 ResolvedJavaType resolved = unresolvedType.reresolve(holder); 170 if (resolved != null) { 171 type = resolved; 172 } 173 } 174 return type; 175 } 176 177 public int offset() { 178 return offset; 179 } 180 181 @Override 182 public String toString() { 183 return format("HotSpotField<%H.%n %t:") + offset + ">"; 184 } 185 186 @Override 187 public boolean isSynthetic() { 188 return (config().jvmAccSynthetic & modifiers) != 0; 189 } 190 191 /** 192 * Checks if this field has the {@link Stable} annotation. 193 * 194 * @return true if field has {@link Stable} annotation, false otherwise 195 */ 196 public boolean isStable() { 197 if ((config().jvmAccFieldStable & modifiers) != 0) { 198 return true; 199 } 200 assert getAnnotation(Stable.class) == null; 201 if (ImplicitStableValues && isImplicitStableField()) { 202 return true; 203 } 204 return false; 205 } 206 207 @Override 208 public Annotation[] getAnnotations() { 209 Field javaField = toJava(); 210 if (javaField != null) { 211 return javaField.getAnnotations(); 212 } 213 return new Annotation[0]; 214 } 215 216 @Override 217 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 218 Field javaField = toJava(); 219 if (javaField != null) { 220 return javaField.getAnnotation(annotationClass); 221 } 222 return null; 223 } 224 225 private Field toJavaCache; 226 227 private Field toJava() { 228 if (toJavaCache != null) { 229 return toJavaCache; 230 } 231 232 if (isInternal()) { 233 return null; 234 } 235 try { 236 return toJavaCache = holder.mirror().getDeclaredField(name); 237 } catch (NoSuchFieldException | NoClassDefFoundError e) { 238 return null; 239 } 240 } 241 242 private boolean isArray() { 243 JavaType fieldType = getType(); 244 return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); 245 } 246 247 private boolean isImplicitStableField() { 248 if (isSyntheticEnumSwitchMap()) { 249 return true; 250 } 251 if (isWellKnownImplicitStableField()) { 252 return true; 253 } 254 return false; 255 } 256 257 public boolean isDefaultStable() { 258 assert this.isStable(); 259 if (isSyntheticEnumSwitchMap()) { 260 return true; 261 } 262 return false; 263 } 264 265 private boolean isSyntheticEnumSwitchMap() { 266 if (isSynthetic() && isStatic() && isArray()) { 267 if (isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { 268 // generated int[] field for EnumClass::values() 269 return true; 270 } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { 271 // javac and ecj generate a static field in an inner class for a switch on an enum 272 // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively 273 return true; 274 } 275 } 276 return false; 277 } 278 279 private boolean isWellKnownImplicitStableField() { 280 return WellKnownImplicitStableField.test(this); 281 } 282 283 static class WellKnownImplicitStableField { 284 /** 285 * @return {@code true} if the field is a well-known stable field. 286 */ 287 public static boolean test(HotSpotResolvedJavaField field) { 288 return field.equals(STRING_VALUE_FIELD); 289 } 290 291 private static final ResolvedJavaField STRING_VALUE_FIELD; 292 293 static { 294 try { 295 MetaAccessProvider metaAccess = runtime().getHostJVMCIBackend().getMetaAccess(); 296 STRING_VALUE_FIELD = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); 297 } catch (SecurityException | NoSuchFieldException e) { 298 throw new JVMCIError(e); 299 } 300 } 301 } 302 303 public LocationIdentity getLocationIdentity() { 304 return locationIdentity; 305 } 306 }