1 /*
  2  * Copyright (c) 2024, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.incubator.code.dialect.java.impl;
 27 
 28 import jdk.incubator.code.dialect.java.FieldRef;
 29 import java.lang.invoke.MethodHandles;
 30 import java.lang.invoke.VarHandle;
 31 import java.lang.reflect.Field;
 32 
 33 import jdk.incubator.code.dialect.java.JavaType;
 34 import jdk.incubator.code.TypeElement;
 35 import jdk.incubator.code.extern.ExternalizedTypeElement;
 36 
 37 public final class FieldRefImpl implements FieldRef {
 38 
 39     final TypeElement refType;
 40     final String name;
 41     final TypeElement type;
 42 
 43     public FieldRefImpl(TypeElement refType, String name, TypeElement type) {
 44         this.refType = refType;
 45         this.name = name;
 46         this.type = type;
 47     }
 48 
 49     @Override
 50     public TypeElement refType() {
 51         return refType;
 52     }
 53 
 54     @Override
 55     public String name() {
 56         return name;
 57     }
 58 
 59     @Override
 60     public TypeElement type() {
 61         return type;
 62     }
 63 
 64     @Override
 65     public Field resolveToMember(MethodHandles.Lookup l) throws ReflectiveOperationException {
 66         Class<?> refC = resolve(l, refType);
 67         Class<?> typeC = resolve(l, type);
 68 
 69         Field f = refC.getDeclaredField(name);
 70         if (!f.getType().equals(typeC)) {
 71             throw new NoSuchFieldException();
 72         }
 73 
 74         return f;
 75     }
 76 
 77     @Override
 78     public VarHandle resolveToHandle(MethodHandles.Lookup l) throws ReflectiveOperationException {
 79         Class<?> refC = resolve(l, refType);
 80         Class<?> typeC = resolve(l, type);
 81 
 82         VarHandle vh = null;
 83         ReflectiveOperationException c = null;
 84 
 85         try {
 86             vh = l.findStaticVarHandle(refC, name, typeC);
 87         } catch (NoSuchFieldException | IllegalAccessException e) {
 88             c = e;
 89         }
 90 
 91         if (c != null) {
 92             c = null;
 93             try {
 94                 vh = l.findVarHandle(refC, name, typeC);
 95             } catch (NoSuchFieldException | IllegalAccessException e) {
 96                 c = e;
 97             }
 98         }
 99 
100         if (c != null) {
101             throw c;
102         }
103 
104         assert vh != null;
105         return vh;
106     }
107 
108     static Class<?> resolve(MethodHandles.Lookup l, TypeElement t) throws ReflectiveOperationException {
109         if (t instanceof JavaType jt) {
110             return (Class<?>)jt.erasure().resolve(l);
111         } else {
112             // @@@
113             throw new ReflectiveOperationException();
114         }
115     }
116 
117     @Override
118     public ExternalizedTypeElement externalize() {
119         return JavaTypeUtils.fieldRef(name, refType.externalize(), type.externalize());
120     }
121 
122     @Override
123     public String toString() {
124         return JavaTypeUtils.toExternalRefString(externalize());
125     }
126 
127     @Override
128     public boolean equals(Object o) {
129         if (this == o) return true;
130         if (o == null || getClass() != o.getClass()) return false;
131 
132         FieldRefImpl fieldDesc = (FieldRefImpl) o;
133 
134         if (!refType.equals(fieldDesc.refType)) return false;
135         if (!name.equals(fieldDesc.name)) return false;
136         return type.equals(fieldDesc.type);
137     }
138 
139     @Override
140     public int hashCode() {
141         int result = refType.hashCode();
142         result = 31 * result + name.hashCode();
143         result = 31 * result + type.hashCode();
144         return result;
145     }
146 }