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.HotSpotVMConfig.config;
  26 
  27 import java.lang.annotation.Annotation;
  28 import java.lang.reflect.Field;
  29 
  30 import jdk.internal.vm.annotation.Stable;
  31 import jdk.vm.ci.common.JVMCIError;
  32 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
  33 import jdk.vm.ci.meta.JavaType;
  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 {
  43 
  44     private final HotSpotResolvedObjectTypeImpl holder;
  45     private final String name;
  46     private JavaType type;
  47     private final int offset;
  48 
  49     /**
  50      * This value contains all flags as stored in the VM including internal ones.
  51      */
  52     private final int modifiers;
  53 
  54     HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) {
  55         this.holder = holder;
  56         this.name = name;
  57         this.type = type;
  58         assert offset != -1;
  59         assert offset == (int) offset : "offset larger than int";
  60         this.offset = (int) offset;
  61         this.modifiers = modifiers;
  62     }
  63 
  64     @Override
  65     public boolean equals(Object obj) {
  66         if (this == obj) {
  67             return true;
  68         }
  69         if (obj instanceof HotSpotResolvedJavaField) {
  70             HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj;
  71             if (that.offset != this.offset || that.isStatic() != this.isStatic()) {
  72                 return false;
  73             } else if (this.holder.equals(that.holder)) {
  74                 assert this.name.equals(that.name) && this.type.equals(that.type);
  75                 return true;
  76             }
  77         }
  78         return false;
  79     }
  80 
  81     @Override
  82     public int hashCode() {
  83         return name.hashCode();
  84     }
  85 
  86     @Override
  87     public int getModifiers() {
  88         return modifiers & ModifiersProvider.jvmFieldModifiers();
  89     }
  90 
  91     @Override
  92     public boolean isInternal() {
  93         return (modifiers & config().jvmAccFieldInternal) != 0;
  94     }
  95 
  96     /**
  97      * Determines if a given object contains this field.
  98      *
  99      * @return true iff this is a non-static field and its declaring class is assignable from
 100      *         {@code object}'s class
 101      */
 102     public boolean isInObject(Object object) {
 103         if (isStatic()) {
 104             return false;
 105         }
 106         return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass()));
 107     }
 108 
 109     @Override
 110     public HotSpotResolvedObjectTypeImpl getDeclaringClass() {
 111         return holder;
 112     }
 113 
 114     @Override
 115     public String getName() {
 116         return name;
 117     }
 118 
 119     @Override
 120     public JavaType getType() {
 121         // Pull field into local variable to prevent a race causing
 122         // a ClassCastException below
 123         JavaType currentType = type;
 124         if (currentType instanceof HotSpotUnresolvedJavaType) {
 125             // Don't allow unresolved types to hang around forever
 126             HotSpotUnresolvedJavaType unresolvedType = (HotSpotUnresolvedJavaType) currentType;
 127             ResolvedJavaType resolved = unresolvedType.reresolve(holder);
 128             if (resolved != null) {
 129                 type = resolved;
 130             }
 131         }
 132         return type;
 133     }
 134 
 135     public int offset() {
 136         return offset;
 137     }
 138 
 139     @Override
 140     public String toString() {
 141         return format("HotSpotField<%H.%n %t:") + offset + ">";
 142     }
 143 
 144     @Override
 145     public boolean isSynthetic() {
 146         return (config().jvmAccSynthetic & modifiers) != 0;
 147     }
 148 
 149     /**
 150      * Checks if this field has the {@link Stable} annotation.
 151      *
 152      * @return true if field has {@link Stable} annotation, false otherwise
 153      */
 154     public boolean isStable() {
 155         return (config().jvmAccFieldStable & modifiers) != 0;
 156     }
 157 
 158     @Override
 159     public Annotation[] getAnnotations() {
 160         Field javaField = toJava();
 161         if (javaField != null) {
 162             return javaField.getAnnotations();
 163         }
 164         return new Annotation[0];
 165     }
 166 
 167     @Override
 168     public Annotation[] getDeclaredAnnotations() {
 169         Field javaField = toJava();
 170         if (javaField != null) {
 171             return javaField.getDeclaredAnnotations();
 172         }
 173         return new Annotation[0];
 174     }
 175 
 176     @Override
 177     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 178         Field javaField = toJava();
 179         if (javaField != null) {
 180             return javaField.getAnnotation(annotationClass);
 181         }
 182         return null;
 183     }
 184 
 185     private Field toJavaCache;
 186 
 187     private Field toJava() {
 188         if (toJavaCache != null) {
 189             return toJavaCache;
 190         }
 191 
 192         if (isInternal()) {
 193             return null;
 194         }
 195         try {
 196             return toJavaCache = holder.mirror().getDeclaredField(name);
 197         } catch (NoSuchFieldException | NoClassDefFoundError e) {
 198             return null;
 199         }
 200     }
 201 }