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