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