2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.vm;
21 import java.util.Arrays;
22 import java.util.Objects;
23 import java.util.function.IntFunction;
25 import gov.nasa.jpf.annotation.MJI;
28 * native peer for Annotation Proxies
29 * (saves us some bytecode interpretation shoe leather)
31 public class JPF_gov_nasa_jpf_AnnotationProxyBase extends NativePeer {
34 public int annotationType____Ljava_lang_Class_2 (MJIEnv env, int objref) {
35 ClassInfo ciProxy = env.getClassInfo(objref); // this would be the proxy
37 // we could also pull it out from the interfaces, but we know the naming scheme
38 String proxyName = ciProxy.getName();
39 String annotation = proxyName.substring(0, proxyName.length() - 6); // "...$Proxy"
40 ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(annotation);
42 return ci.getClassObjectRef();
46 public boolean equals__Ljava_lang_Object_2__Z(MJIEnv env, int objRef, int otherObj) {
47 if(otherObj == MJIEnv.NULL) {
50 ClassInfo thisProxy = env.getClassInfo(objRef);
51 ClassInfo otherProxy = env.getClassInfo(otherObj);
52 if(!thisProxy.equals(otherProxy)) {
53 if(!otherProxy.getAllInterfaceClassInfos().containsAll(thisProxy.getAllInterfaces())) {
56 // oof, someone implemented an annotation in user code. Delegate to their equals and let them deal with it
57 MethodInfo mi = otherProxy.getMethod("equals(Ljava/lang/Object;)Z", true);
59 ThreadInfo ti = env.getThreadInfo();
60 DirectCallStackFrame frame = ti.getReturnedDirectCall();
62 frame = mi.createDirectCallStackFrame(ti, 0);
63 frame.setReferenceArgument(0, otherObj, env.getObjectAttr(otherObj));
64 frame.setReferenceArgument(1, objRef, env.getObjectAttr(objRef));
68 Object attr = frame.getResultAttr();
69 int ret = frame.getResult();
70 env.setReturnAttribute(attr);
74 return annotationsEqual(env, objRef, otherObj);
77 public static boolean annotationsEqual(MJIEnv env, int aObj, int bObj) {
78 if((aObj == MJIEnv.NULL) != (bObj == MJIEnv.NULL)) {
81 ClassInfo thisProxy = env.getClassInfo(aObj);
82 ClassInfo otherProxy = env.getClassInfo(bObj);
83 if(!thisProxy.equals(otherProxy)) {
86 FieldInfo[] fields = thisProxy.getDeclaredInstanceFields();
87 ElementInfo aE = env.getElementInfo(aObj);
88 ElementInfo bE = env.getElementInfo(bObj);
89 for (int i=0; i<fields.length; i++){
90 FieldInfo fi = fields[i];
91 String fn = fi.getName();
92 String ft = fi.getType();
93 if(!fi.isReference()) {
94 if(fi.is1SlotField()) {
95 if(aE.get1SlotField(fi) != bE.get1SlotField(fi)) {
99 if(aE.get2SlotField(fi) != bE.get2SlotField(fi)) {
103 } else if(ft.equals("java.lang.Class")) {
104 if(env.getReferenceField(aObj, fi) != env.getReferenceField(bObj, fi)) {
107 } else if(ft.equals("java.lang.String")) {
108 String aStr = env.getStringField(aObj, fn);
109 String bStr = env.getStringField(bObj, fn);
110 if(!Objects.equals(aStr, bStr)) {
113 } else if(ft.endsWith("[]")) {
114 String elemType = Types.getTypeName(Types.getArrayElementType(fi.getSignature()));
115 int aArrayRef = env.getReferenceField(aObj, fi);
116 int bArrayRef = env.getReferenceField(bObj, fi);
117 if((aArrayRef == MJIEnv.NULL) != (bArrayRef == MJIEnv.NULL)) {
120 ElementInfo aArrayContents = env.getElementInfo(aArrayRef);
121 ElementInfo bArrayContents = env.getElementInfo(bArrayRef);
122 assert aArrayContents.isArray() && bArrayContents.isArray();
123 if(Types.isBasicType(elemType) || elemType.equals("java.lang.Class")) {
124 Object rawArray1 = aArrayContents.getArrayFields().getValues();
125 Object rawArray2 = bArrayContents.getArrayFields().getValues();
126 if(!Objects.deepEquals(rawArray1, rawArray2)) {
130 } else if(elemType.equals("java.lang.String")) {
131 if(!Arrays.equals(env.getStringArrayObject(aArrayRef), env.getStringArrayObject(bArrayRef))) {
134 // either annotation or enum
136 int arrayLength1 = env.getArrayLength(aArrayRef);
137 int arrayLength2 = env.getArrayLength(bArrayRef);
138 if(arrayLength2 != arrayLength1) {
141 for(int j = 0; j < arrayLength1; j++) {
142 int elem1Ref = env.getReferenceArrayElement(aArrayRef, j);
143 int elem2Ref = env.getReferenceArrayElement(bArrayRef, j);
144 assert elem1Ref != MJIEnv.NULL && elem2Ref != MJIEnv.NULL;
145 if(!referenceTypesEqual(env, elem1Ref, elem2Ref)) {
151 if(!referenceTypesEqual(env, env.getReferenceField(aObj, fi), env.getReferenceField(bObj, fi))) {
159 private static boolean referenceTypesEqual(MJIEnv env, int elem1Ref, int elem2Ref) {
160 ClassInfo aci = env.getClassInfo(elem1Ref);
161 ClassInfo bci = env.getClassInfo(elem2Ref);
162 assert aci != null && bci != null;
163 if(!aci.equals(bci)) {
167 return elem1Ref == elem2Ref;
169 return annotationsEqual(env, elem1Ref, elem2Ref);
174 public int toString____Ljava_lang_String_2 (MJIEnv env, int objref){
175 StringBuilder sb = new StringBuilder();
176 annotationReferenceToString(env, objref, sb);
177 return env.newString(sb.toString());
180 private int annotationHashCode(MJIEnv env, int objRef) {
181 ClassInfo thisProxy = env.getClassInfo(objRef);
182 FieldInfo[] fields = thisProxy.getDeclaredInstanceFields();
184 for (int i=0; i<fields.length; i++){
185 FieldInfo fi = fields[i];
186 int fieldHash = computeFieldHash(env, objRef, fi);
187 hashCode += (127 * getStringHash(env, env.newString(fi.getName()))) ^ fieldHash;
192 private int computeFieldHash(MJIEnv env, int objRef, FieldInfo fi) {
193 String fn = fi.getName();
194 String ft = fi.getType();
195 if(!fi.isReference()) {
198 return Byte.valueOf(env.getByteField(objRef, fn)).hashCode();
200 return Boolean.valueOf(env.getBooleanField(objRef, fn)).hashCode();
202 return Character.valueOf(env.getCharField(objRef, fn)).hashCode();
204 return Short.valueOf(env.getShortField(objRef, fn)).hashCode();
206 return Integer.valueOf(env.getIntField(objRef, fn)).hashCode();
208 return Long.valueOf(env.getLongField(objRef, fn)).hashCode();
210 return Float.valueOf(env.getFloatField(objRef, fn)).hashCode();
212 return Double.valueOf(env.getDoubleField(objRef, fn)).hashCode();
214 throw new UnsupportedOperationException();
216 } else if(ft.equals("java.lang.Class")) {
217 return getObjectHash(env.getReferenceField(objRef, fi));
218 } else if(ft.equals("java.lang.String")) {
219 return getStringHash(env, env.getReferenceField(objRef, fi));
220 } else if(ft.endsWith("[]")) {
221 int aArrayRef = env.getReferenceField(objRef, fi);
222 ElementInfo aArrayContents = env.getElementInfo(aArrayRef);
223 String elemType = Types.getTypeName(Types.getArrayElementType(fi.getSignature()));
224 if(Types.isBasicType(elemType)) {
225 Object rawArray1 = aArrayContents.getArrayFields().getValues();
226 if(rawArray1 instanceof boolean[]) {
227 return Arrays.hashCode((boolean[])rawArray1);
228 } else if(rawArray1 instanceof byte[]) {
229 return Arrays.hashCode((byte[])rawArray1);
230 } else if(rawArray1 instanceof char[]) {
231 return Arrays.hashCode((char[])rawArray1);
232 } else if(rawArray1 instanceof short[]) {
233 return Arrays.hashCode((short[])rawArray1);
234 } else if(rawArray1 instanceof int[]) {
235 return Arrays.hashCode((int[])rawArray1);
236 } else if(rawArray1 instanceof long[]) {
237 return Arrays.hashCode((long[])rawArray1);
238 } else if(rawArray1 instanceof float[]) {
239 return Arrays.hashCode((float[])rawArray1);
240 } else if(rawArray1 instanceof double[]) {
241 return Arrays.hashCode((double[])rawArray1);
243 throw new RuntimeException();
245 } else if(elemType.equals("java.lang.Class")) {
246 return computeObjectArrayHash(env, aArrayRef, this::getObjectHash);
248 } else if(elemType.equals("java.lang.String")) {
249 return computeObjectArrayHash(env, aArrayRef, (ref) -> getStringHash(env, ref));
251 return computeObjectArrayHash(env, aArrayRef, (ref) -> hashReferenceValue(env, ref));
254 return hashReferenceValue(env, env.getReferenceField(objRef, fi));
259 * THIS WILL BREAK if the JDK uses a different hashcode from the one here
261 private int computeObjectArrayHash(MJIEnv env, int arrayRef, IntFunction<Integer> refHasher) {
262 int arrayLength1 = env.getArrayLength(arrayRef);
264 for(int j = 0; j < arrayLength1; j++) {
265 int elem1Ref = env.getReferenceArrayElement(arrayRef, j);
266 hash = 31 * hash + refHasher.apply(elem1Ref);
271 private int getStringHash(MJIEnv env, int strObjRef) {
272 return JPF_java_lang_String.computeStringHashCode(env, strObjRef);
275 private int getObjectHash(int ref) {
279 private int hashReferenceValue(MJIEnv env, int elem1Ref) {
280 ClassInfo aci = env.getClassInfo(elem1Ref);
282 return getObjectHash(elem1Ref);
284 return annotationHashCode(env, elem1Ref);
289 public int hashCode____I(MJIEnv env, int objRef) {
290 return annotationHashCode(env, objRef);
293 private void annotationReferenceToString(MJIEnv env, int objref, StringBuilder sb) {
294 ClassInfo ci = env.getClassInfo(objref);
295 String cname = ci.getName();
296 int idx = cname.lastIndexOf('$');
299 sb.append(cname.substring(0,idx));
301 FieldInfo[] fields = ci.getDeclaredInstanceFields();
302 if (fields.length > 0){
304 for (int i=0; i<fields.length; i++){
305 String fn = fields[i].getName();
306 String ft = fields[i].getType();
314 if(ft.equals("int")) {
315 sb.append(env.getIntField(objref,fn));
317 } else if(ft.equals("byte")) {
318 sb.append(env.getByteField(objref,fn));
320 } else if(ft.equals("boolean")) {
321 sb.append(env.getBooleanField(objref,fn));
323 } else if(ft.equals("short")) {
324 sb.append(env.getShortField(objref, fn));
326 } else if(ft.equals("char")) {
327 sb.append(env.getCharField(objref, fn));
329 } else if(ft.equals("float")) {
330 sb.append(env.getFloatField(objref, fn));
332 } else if(ft.equals("long")) {
333 sb.append(env.getLongField(objref, fn));
335 } else if(ft.equals("double")) {
336 sb.append(env.getDoubleField(objref,fn));
338 } else if(ft.equals("java.lang.String")) {
339 sb.append(env.getStringObject(env.getReferenceField(objref, fn)));
341 } else if(ft.equals("java.lang.Class")) {
342 int cref = env.getReferenceField(objref, fn);
343 if (cref != MJIEnv.NULL){
344 int nref = env.getReferenceField(cref, "name");
345 String cn = env.getStringObject(nref);
350 sb.append("class ?");
353 } else if(ft.endsWith("[]")) {
354 int ar = env.getReferenceField(objref, fn);
355 int n = env.getArrayLength((ar));
359 if(ft.equals("int[]")) {
360 for (int j=0; j<n; j++){
361 if (j>0) sb.append(',');
362 sb.append(env.getIntArrayElement(ar,j));
365 } else if(ft.equals("byte[]")) {
366 for (int j=0; j<n; j++){
367 if (j>0) sb.append(',');
368 sb.append(env.getByteArrayElement(ar,j));
371 } else if(ft.equals("boolean[]")) {
372 for (int j=0; j<n; j++){
373 if (j>0) sb.append(',');
374 sb.append(env.getBooleanArrayElement(ar,j));
377 } else if(ft.equals("short[]")) {
378 for (int j=0; j<n; j++){
379 if (j>0) sb.append(',');
380 sb.append(env.getShortArrayElement(ar,j));
383 } else if(ft.equals("char[]")) {
384 for (int j=0; j<n; j++){
385 if (j>0) sb.append(',');
386 sb.append(env.getCharArrayElement(ar,j));
389 } else if(ft.equals("float[]")) {
390 for (int j=0; j<n; j++){
391 if (j>0) sb.append(',');
392 sb.append(env.getFloatArrayElement(ar,j));
395 } else if(ft.equals("long[]")) {
396 for (int j=0; j<n; j++){
397 if (j>0) sb.append(',');
398 sb.append(env.getLongArrayElement(ar,j));
401 } else if(ft.equals("double[]")) {
402 for (int j=0; j<n; j++){
403 if (j>0) sb.append(',');
404 sb.append(env.getDoubleArrayElement(ar,j));
407 } else if(ft.equals("java.lang.String[]")) {
408 for (int j=0; j<n; j++){
409 if (j>0) sb.append(',');
410 sb.append(env.getStringObject(env.getReferenceArrayElement(ar,j)));
413 } else if(ft.equals("java.lang.Class[]")) {
414 for (int j=0; j<n; j++){
415 if (j>0) sb.append(',');
417 int cref = env.getReferenceArrayElement(ar,j);
418 if (cref != MJIEnv.NULL){
419 int nref = env.getReferenceField(cref, "name");
420 String cn = env.getStringObject(nref);
425 sb.append("class ?");
430 for(int j=0; j < n; j++) {
431 if (j>0) sb.append(',');
433 int cref = env.getReferenceArrayElement(ar,j);
434 if (cref != MJIEnv.NULL){
435 referenceToString(env, sb, cref);
444 int eref = env.getReferenceField(objref, fn);
445 if (eref != MJIEnv.NULL){
446 referenceToString(env, sb, eref);
454 private void referenceToString(MJIEnv env, StringBuilder sb, int eref) {
455 ClassInfo eci = env.getClassInfo(eref);
457 int nref = env.getReferenceField(eref, "name");
458 String en = env.getStringObject(nref);
460 sb.append(eci.getName());
464 annotationReferenceToString(env, eref, sb);