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