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