001/* 002 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.hotspot; 024 025import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; 026import static jdk.internal.jvmci.hotspot.HotSpotResolvedJavaFieldImpl.Options.*; 027 028import java.lang.annotation.*; 029import java.lang.reflect.*; 030 031import jdk.internal.jvmci.common.*; 032import jdk.internal.jvmci.meta.*; 033import jdk.internal.jvmci.options.*; 034 035/** 036 * Represents a field in a HotSpot type. 037 */ 038public class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { 039 040 static class Options { 041 //@formatter:off 042 @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug) 043 public static final OptionValue<Boolean> ImplicitStableValues = new OptionValue<>(true); 044 //@formatter:on 045 } 046 047 private final HotSpotResolvedObjectTypeImpl holder; 048 private final String name; 049 private JavaType type; 050 private final int offset; 051 052 /** 053 * This value contains all flags as stored in the VM including internal ones. 054 */ 055 private final int modifiers; 056 private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); 057 058 public static class FieldLocationIdentity extends LocationIdentity { 059 HotSpotResolvedJavaField inner; 060 061 public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { 062 this.inner = inner; 063 } 064 065 @Override 066 public boolean isImmutable() { 067 return false; 068 } 069 070 @Override 071 public boolean equals(Object obj) { 072 if (this == obj) { 073 return true; 074 } 075 if (obj instanceof FieldLocationIdentity) { 076 FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; 077 return inner.equals(fieldLocationIdentity.inner); 078 079 } 080 return false; 081 } 082 083 @Override 084 public int hashCode() { 085 return inner.hashCode(); 086 } 087 088 @Override 089 public String toString() { 090 return inner.getName(); 091 } 092 } 093 094 public HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { 095 this.holder = holder; 096 this.name = name; 097 this.type = type; 098 assert offset != -1; 099 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 <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 207 Field javaField = toJava(); 208 if (javaField != null) { 209 return javaField.getAnnotation(annotationClass); 210 } 211 return null; 212 } 213 214 private Field toJavaCache; 215 216 private Field toJava() { 217 if (toJavaCache != null) { 218 return toJavaCache; 219 } 220 221 if (isInternal()) { 222 return null; 223 } 224 try { 225 return toJavaCache = holder.mirror().getDeclaredField(name); 226 } catch (NoSuchFieldException | NoClassDefFoundError e) { 227 return null; 228 } 229 } 230 231 private boolean isArray() { 232 JavaType fieldType = getType(); 233 return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); 234 } 235 236 private boolean isImplicitStableField() { 237 if (isSynthetic()) { 238 if (isSyntheticImplicitStableField()) { 239 return true; 240 } 241 } else if (isWellKnownImplicitStableField()) { 242 return true; 243 } 244 return false; 245 } 246 247 private boolean isSyntheticImplicitStableField() { 248 assert this.isSynthetic(); 249 if (isStatic() && isArray()) { 250 if (isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { 251 // generated int[] field for EnumClass::values() 252 return true; 253 } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { 254 // javac and ecj generate a static field in an inner class for a switch on an enum 255 // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively 256 return true; 257 } 258 } 259 return false; 260 } 261 262 private boolean isWellKnownImplicitStableField() { 263 return WellKnownImplicitStableField.test(this); 264 } 265 266 static class WellKnownImplicitStableField { 267 /** 268 * @return {@code true} if the field is a well-known stable field. 269 */ 270 public static boolean test(HotSpotResolvedJavaField field) { 271 return field.equals(STRING_VALUE_FIELD); 272 } 273 274 private static final ResolvedJavaField STRING_VALUE_FIELD; 275 static { 276 try { 277 MetaAccessProvider metaAccess = runtime().getHostJVMCIBackend().getMetaAccess(); 278 STRING_VALUE_FIELD = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); 279 } catch (SecurityException | NoSuchFieldException e) { 280 throw new JVMCIError(e); 281 } 282 } 283 } 284 285 public LocationIdentity getLocationIdentity() { 286 return locationIdentity; 287 } 288}