1 /*
   2  * Copyright (c) 2011, 2018, 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.HotSpotModifiers.jvmFieldModifiers;
  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.meta.JavaConstant;
  32 import jdk.vm.ci.meta.JavaType;
  33 import jdk.vm.ci.meta.ResolvedJavaType;
  34 import jdk.vm.ci.meta.UnresolvedJavaType;
  35 
  36 /**
  37  * Represents a field in a HotSpot type.
  38  */
  39 class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField {
  40 
  41     private final HotSpotResolvedObjectTypeImpl holder;
  42     private JavaType type;
  43     private final int offset;
  44     private final short index;
  45 
  46     /**
  47      * This value contains all flags as stored in the VM including internal ones.
  48      */
  49     private final int modifiers;
  50 
  51     HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, JavaType type, long offset, int modifiers, int index) {
  52         this.holder = holder;
  53         this.type = type;
  54         this.index = (short) index;
  55         assert this.index == index;
  56         assert offset != -1;
  57         assert offset == (int) offset : "offset larger than int";
  58         this.offset = (int) offset;
  59         this.modifiers = modifiers;
  60     }
  61 
  62     @Override
  63     public boolean equals(Object obj) {
  64         if (this == obj) {
  65             return true;
  66         }
  67         if (obj instanceof HotSpotResolvedJavaField) {
  68             HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj;
  69             if (that.offset != this.offset || that.isStatic() != this.isStatic()) {
  70                 return false;
  71             } else if (this.holder.equals(that.holder)) {
  72                 return true;
  73             }
  74         }
  75         return false;
  76     }
  77 
  78     @Override
  79     public int hashCode() {
  80         return holder.hashCode() ^ offset;
  81     }
  82 
  83     @Override
  84     public int getModifiers() {
  85         return modifiers & jvmFieldModifiers();
  86     }
  87 
  88     @Override
  89     public boolean isInternal() {
  90         return (modifiers & config().jvmAccFieldInternal) != 0;
  91     }
  92 
  93     /**
  94      * Determines if a given object contains this field.
  95      *
  96      * @return true iff this is a non-static field and its declaring class is assignable from
  97      *         {@code object}'s class
  98      */
  99     @Override
 100     public boolean isInObject(JavaConstant constant) {
 101         if (isStatic()) {
 102             return false;
 103         }
 104         Object object = ((HotSpotObjectConstantImpl) constant).object();
 105         return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass()));
 106     }
 107 
 108     @Override
 109     public HotSpotResolvedObjectTypeImpl getDeclaringClass() {
 110         return holder;
 111     }
 112 
 113     @Override
 114     public String getName() {
 115         return holder.createFieldInfo(index).getName();
 116     }
 117 
 118     @Override
 119     public JavaType getType() {
 120         // Pull field into local variable to prevent a race causing
 121         // a ClassCastException below
 122         JavaType currentType = type;
 123         if (currentType instanceof UnresolvedJavaType) {
 124             // Don't allow unresolved types to hang around forever
 125             UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType;
 126             ResolvedJavaType resolved = holder.lookupType(unresolvedType, false);
 127             if (resolved != null) {
 128                 type = resolved;
 129             }
 130         }
 131         return type;
 132     }
 133 
 134     @Override
 135     public int getOffset() {
 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     @Override
 155     public boolean isStable() {
 156         return (config().jvmAccFieldStable & modifiers) != 0;
 157     }
 158 
 159     @Override
 160     public Annotation[] getAnnotations() {
 161         Field javaField = toJava();
 162         if (javaField != null) {
 163             return javaField.getAnnotations();
 164         }
 165         return new Annotation[0];
 166     }
 167 
 168     @Override
 169     public Annotation[] getDeclaredAnnotations() {
 170         Field javaField = toJava();
 171         if (javaField != null) {
 172             return javaField.getDeclaredAnnotations();
 173         }
 174         return new Annotation[0];
 175     }
 176 
 177     @Override
 178     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 179         Field javaField = toJava();
 180         if (javaField != null) {
 181             return javaField.getAnnotation(annotationClass);
 182         }
 183         return null;
 184     }
 185 
 186     private Field toJava() {
 187         if (isInternal()) {
 188             return null;
 189         }
 190         try {
 191             return holder.mirror().getDeclaredField(getName());
 192         } catch (NoSuchFieldException e) {
 193             return null;
 194         }
 195     }
 196 }