Mercurial > hg > Members > kono > jpf-core
comparison src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children | db918c531e6d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
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 | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
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. | |
17 */ | |
18 package gov.nasa.jpf.vm; | |
19 | |
20 import gov.nasa.jpf.Config; | |
21 import gov.nasa.jpf.annotation.MJI; | |
22 import gov.nasa.jpf.util.MethodInfoRegistry; | |
23 import gov.nasa.jpf.util.RunListener; | |
24 import gov.nasa.jpf.util.RunRegistry; | |
25 | |
26 import java.lang.reflect.Modifier; | |
27 import java.util.ArrayList; | |
28 | |
29 public class JPF_java_lang_reflect_Method extends NativePeer { | |
30 | |
31 static MethodInfoRegistry registry; | |
32 | |
33 // class init - this is called automatically from the NativePeer ctor | |
34 public static boolean init (Config conf) { | |
35 // this is an example of how to handle cross-initialization between | |
36 // native peers - this might also get explicitly called by the java.lang.Class | |
37 // peer, since it creates Method objects. Here we have to make sure | |
38 // we only reset between JPF runs | |
39 | |
40 if (registry == null){ | |
41 registry = new MethodInfoRegistry(); | |
42 | |
43 RunRegistry.getDefaultRegistry().addListener( new RunListener() { | |
44 @Override | |
45 public void reset (RunRegistry reg){ | |
46 registry = null; | |
47 } | |
48 }); | |
49 } | |
50 return true; | |
51 } | |
52 | |
53 static int createMethodObject (MJIEnv env, ClassInfo ciMth, MethodInfo mi){ | |
54 // note - it is the callers responsibility to ensure Method is properly initialized | |
55 int regIdx = registry.registerMethodInfo(mi); | |
56 int eidx = env.newObject( ciMth); | |
57 ElementInfo ei = env.getModifiableElementInfo(eidx); | |
58 | |
59 ei.setIntField("regIdx", regIdx); | |
60 ei.setBooleanField("isAccessible", mi.isPublic()); | |
61 | |
62 return eidx; | |
63 } | |
64 | |
65 // this is NOT an MJI method, but it is used outside this package, so | |
66 // we have to add 'final' | |
67 public static final MethodInfo getMethodInfo (MJIEnv env, int objRef){ | |
68 return registry.getMethodInfo(env,objRef, "regIdx"); | |
69 } | |
70 | |
71 @MJI | |
72 public int getName____Ljava_lang_String_2 (MJIEnv env, int objRef) { | |
73 MethodInfo mi = getMethodInfo(env, objRef); | |
74 | |
75 int nameRef = env.getReferenceField( objRef, "name"); | |
76 if (nameRef == MJIEnv.NULL) { | |
77 nameRef = env.newString(mi.getName()); | |
78 env.setReferenceField(objRef, "name", nameRef); | |
79 } | |
80 | |
81 return nameRef; | |
82 } | |
83 | |
84 @MJI | |
85 public int getModifiers____I (MJIEnv env, int objRef){ | |
86 MethodInfo mi = getMethodInfo(env, objRef); | |
87 return mi.getModifiers(); | |
88 } | |
89 | |
90 static int getParameterTypes( MJIEnv env, MethodInfo mi) { | |
91 ThreadInfo ti = env.getThreadInfo(); | |
92 String[] argTypeNames = mi.getArgumentTypeNames(); | |
93 int[] ar = new int[argTypeNames.length]; | |
94 | |
95 for (int i = 0; i < argTypeNames.length; i++) { | |
96 ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(argTypeNames[i]); | |
97 if (!ci.isRegistered()) { | |
98 ci.registerClass(ti); | |
99 } | |
100 | |
101 ar[i] = ci.getClassObjectRef(); | |
102 } | |
103 | |
104 int aRef = env.newObjectArray("Ljava/lang/Class;", argTypeNames.length); | |
105 for (int i = 0; i < argTypeNames.length; i++) { | |
106 env.setReferenceArrayElement(aRef, i, ar[i]); | |
107 } | |
108 | |
109 return aRef; | |
110 } | |
111 | |
112 @MJI | |
113 public int getParameterTypes_____3Ljava_lang_Class_2 (MJIEnv env, int objRef){ | |
114 return getParameterTypes(env, getMethodInfo(env, objRef)); | |
115 } | |
116 | |
117 int getExceptionTypes(MJIEnv env, MethodInfo mi) { | |
118 ThreadInfo ti = env.getThreadInfo(); | |
119 String[] exceptionNames = mi.getThrownExceptionClassNames(); | |
120 | |
121 if (exceptionNames == null) { | |
122 exceptionNames = new String[0]; | |
123 } | |
124 | |
125 int[] ar = new int[exceptionNames.length]; | |
126 | |
127 for (int i = 0; i < exceptionNames.length; i++) { | |
128 ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(exceptionNames[i]); | |
129 if (!ci.isRegistered()) { | |
130 ci.registerClass(ti); | |
131 } | |
132 | |
133 ar[i] = ci.getClassObjectRef(); | |
134 } | |
135 | |
136 int aRef = env.newObjectArray("Ljava/lang/Class;", exceptionNames.length); | |
137 for (int i = 0; i < exceptionNames.length; i++) { | |
138 env.setReferenceArrayElement(aRef, i, ar[i]); | |
139 } | |
140 | |
141 return aRef; | |
142 } | |
143 | |
144 @MJI | |
145 public int getExceptionTypes_____3Ljava_lang_Class_2 (MJIEnv env, int objRef) { | |
146 return getExceptionTypes(env, getMethodInfo(env, objRef)); | |
147 } | |
148 | |
149 @MJI | |
150 public int getReturnType____Ljava_lang_Class_2 (MJIEnv env, int objRef){ | |
151 MethodInfo mi = getMethodInfo(env, objRef); | |
152 ThreadInfo ti = env.getThreadInfo(); | |
153 | |
154 ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(mi.getReturnTypeName()); | |
155 if (!ci.isRegistered()) { | |
156 ci.registerClass(ti); | |
157 } | |
158 | |
159 return ci.getClassObjectRef(); | |
160 } | |
161 | |
162 @MJI | |
163 public int getDeclaringClass____Ljava_lang_Class_2 (MJIEnv env, int objRef){ | |
164 MethodInfo mi = getMethodInfo(env, objRef); | |
165 ClassInfo ci = mi.getClassInfo(); | |
166 // it's got to be registered, otherwise we wouldn't be able to acquire the Method object | |
167 return ci.getClassObjectRef(); | |
168 } | |
169 | |
170 static int createBoxedReturnValueObject (MJIEnv env, MethodInfo mi, DirectCallStackFrame frame) { | |
171 byte rt = mi.getReturnTypeCode(); | |
172 int ret = MJIEnv.NULL; | |
173 ElementInfo rei; | |
174 Object attr = null; | |
175 | |
176 if (rt == Types.T_DOUBLE) { | |
177 attr = frame.getLongResultAttr(); | |
178 double v = frame.getDoubleResult(); | |
179 ret = env.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Double")); | |
180 rei = env.getModifiableElementInfo(ret); | |
181 rei.setDoubleField("value", v); | |
182 } else if (rt == Types.T_FLOAT) { | |
183 attr = frame.getResultAttr(); | |
184 float v = frame.getFloatResult(); | |
185 ret = env.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Float")); | |
186 rei = env.getModifiableElementInfo(ret); | |
187 rei.setFloatField("value", v); | |
188 } else if (rt == Types.T_LONG) { | |
189 attr = frame.getLongResultAttr(); | |
190 long v = frame.getLongResult(); | |
191 ret = env.valueOfLong(v); | |
192 } else if (rt == Types.T_BYTE) { | |
193 attr = frame.getResultAttr(); | |
194 int v = frame.getResult(); | |
195 ret = env.valueOfByte((byte)v); | |
196 } else if (rt == Types.T_CHAR) { | |
197 attr = frame.getResultAttr(); | |
198 int v = frame.getResult(); | |
199 ret = env.valueOfCharacter((char)v); | |
200 } else if (rt == Types.T_SHORT) { | |
201 attr = frame.getResultAttr(); | |
202 int v = frame.getResult(); | |
203 ret = env.valueOfShort((short)v); | |
204 } else if (rt == Types.T_INT) { | |
205 attr = frame.getResultAttr(); | |
206 int v = frame.getResult(); | |
207 ret = env.valueOfInteger(v); | |
208 } else if (rt == Types.T_BOOLEAN) { | |
209 attr = frame.getResultAttr(); | |
210 int v = frame.getResult(); | |
211 ret = env.valueOfBoolean((v == 1)? true: false); | |
212 } else if (mi.isReferenceReturnType()){ | |
213 attr = frame.getResultAttr(); | |
214 ret = frame.getReferenceResult(); | |
215 } | |
216 | |
217 env.setReturnAttribute(attr); | |
218 return ret; | |
219 } | |
220 | |
221 static boolean pushUnboxedArguments (MJIEnv env, MethodInfo mi, DirectCallStackFrame frame, int argIdx, int argsRef) { | |
222 ElementInfo source; | |
223 ClassInfo sourceClass; | |
224 String destTypeNames[]; | |
225 int nArgs, passedCount, sourceRef; | |
226 byte sourceType, destTypes[]; | |
227 | |
228 destTypes = mi.getArgumentTypes(); | |
229 destTypeNames = mi.getArgumentTypeNames(); | |
230 nArgs = destTypeNames.length; | |
231 | |
232 // according to the API docs, passing null instead of an empty array is allowed for no args | |
233 passedCount = (argsRef != MJIEnv.NULL) ? env.getArrayLength(argsRef) : 0; | |
234 | |
235 if (nArgs != passedCount) { | |
236 env.throwException(IllegalArgumentException.class.getName(), "Wrong number of arguments passed. Actual = " + passedCount + ". Expected = " + nArgs); | |
237 return false; | |
238 } | |
239 | |
240 for (int i = 0; i < nArgs; i++) { | |
241 sourceRef = env.getReferenceArrayElement(argsRef, i); | |
242 | |
243 // we have to handle null references explicitly | |
244 if (sourceRef == MJIEnv.NULL) { | |
245 if ((destTypes[i] != Types.T_REFERENCE) && (destTypes[i] != Types.T_ARRAY)) { | |
246 env.throwException(IllegalArgumentException.class.getName(), "Wrong argument type at index " + i + ". Actual = (null). Expected = " + destTypeNames[i]); | |
247 return false; | |
248 } | |
249 | |
250 frame.pushRef(MJIEnv.NULL); | |
251 continue; | |
252 } | |
253 | |
254 source = env.getElementInfo(sourceRef); | |
255 sourceClass = source.getClassInfo(); | |
256 sourceType = getSourceType( sourceClass, destTypes[i], destTypeNames[i]); | |
257 | |
258 Object attr = env.getElementInfo(argsRef).getFields().getFieldAttr(i); | |
259 if ((argIdx = pushArg( argIdx, frame, source, sourceType, destTypes[i], attr)) < 0 ){ | |
260 env.throwException(IllegalArgumentException.class.getName(), "Wrong argument type at index " + i + ". Source Class = " + sourceClass.getName() + ". Dest Class = " + destTypeNames[i]); | |
261 return false; | |
262 } | |
263 } | |
264 | |
265 return true; | |
266 } | |
267 | |
268 // this returns the primitive type in case we have to unbox, and otherwise checks reference type compatibility | |
269 private static byte getSourceType (ClassInfo ciArgVal, byte destType, String destTypeName){ | |
270 switch (destType){ | |
271 // the primitives | |
272 case Types.T_BOOLEAN: | |
273 case Types.T_BYTE: | |
274 case Types.T_CHAR: | |
275 case Types.T_SHORT: | |
276 case Types.T_INT: | |
277 case Types.T_LONG: | |
278 case Types.T_FLOAT: | |
279 case Types.T_DOUBLE: | |
280 return Types.getUnboxedType(ciArgVal.getName()); | |
281 | |
282 case Types.T_ARRAY: | |
283 case Types.T_REFERENCE: // check if the source type is assignment compatible with the destType | |
284 if (ciArgVal.isInstanceOf(destTypeName)){ | |
285 return destType; | |
286 } | |
287 } | |
288 | |
289 return Types.T_NONE; | |
290 } | |
291 | |
292 // do the proper type conversion - Java is pretty forgiving here and does | |
293 // not throw exceptions upon value truncation | |
294 private static int pushArg( int argIdx, DirectCallStackFrame frame, ElementInfo eiArg, byte srcType, byte destType, Object attr){ | |
295 switch (srcType) { | |
296 case Types.T_DOUBLE: | |
297 { | |
298 double v = eiArg.getDoubleField("value"); | |
299 if (destType == Types.T_DOUBLE){ | |
300 return frame.setDoubleArgument( argIdx, v, attr); | |
301 } | |
302 return -1; | |
303 } | |
304 case Types.T_FLOAT: // covers float, double | |
305 { | |
306 float v = eiArg.getFloatField("value"); | |
307 switch (destType){ | |
308 case Types.T_FLOAT: | |
309 return frame.setFloatArgument( argIdx, v, attr); | |
310 case Types.T_DOUBLE: | |
311 return frame.setDoubleArgument( argIdx, v, attr); | |
312 } | |
313 return -1; | |
314 } | |
315 case Types.T_LONG: | |
316 { | |
317 long v = eiArg.getLongField("value"); | |
318 switch (destType){ | |
319 case Types.T_LONG: | |
320 return frame.setLongArgument(argIdx, v, attr); | |
321 case Types.T_FLOAT: | |
322 return frame.setFloatArgument(argIdx, v, attr); | |
323 case Types.T_DOUBLE: | |
324 return frame.setDoubleArgument( argIdx, v, attr); | |
325 } | |
326 return -1; | |
327 } | |
328 case Types.T_INT: | |
329 { | |
330 int v = eiArg.getIntField("value"); | |
331 switch (destType){ | |
332 case Types.T_INT: | |
333 return frame.setArgument( argIdx, v, attr); | |
334 case Types.T_LONG: | |
335 return frame.setLongArgument( argIdx, v, attr); | |
336 case Types.T_FLOAT: | |
337 return frame.setFloatArgument(argIdx, v, attr); | |
338 case Types.T_DOUBLE: | |
339 return frame.setDoubleArgument( argIdx, v, attr); | |
340 } | |
341 return -1; | |
342 } | |
343 case Types.T_SHORT: | |
344 { | |
345 int v = eiArg.getShortField("value"); | |
346 switch (destType){ | |
347 case Types.T_SHORT: | |
348 case Types.T_INT: | |
349 return frame.setArgument( argIdx, v, attr); | |
350 case Types.T_LONG: | |
351 return frame.setLongArgument( argIdx, v, attr); | |
352 case Types.T_FLOAT: | |
353 return frame.setFloatArgument(argIdx, v, attr); | |
354 case Types.T_DOUBLE: | |
355 return frame.setDoubleArgument( argIdx, v, attr); | |
356 } | |
357 return -1; | |
358 } | |
359 case Types.T_BYTE: | |
360 { | |
361 byte v = eiArg.getByteField("value"); | |
362 switch (destType){ | |
363 case Types.T_BYTE: | |
364 case Types.T_SHORT: | |
365 case Types.T_INT: | |
366 return frame.setArgument( argIdx, v, attr); | |
367 case Types.T_LONG: | |
368 return frame.setLongArgument( argIdx, v, attr); | |
369 case Types.T_FLOAT: | |
370 return frame.setFloatArgument(argIdx, v, attr); | |
371 case Types.T_DOUBLE: | |
372 return frame.setDoubleArgument( argIdx, v, attr); | |
373 } | |
374 return -1; | |
375 } | |
376 case Types.T_CHAR: | |
377 { | |
378 char v = eiArg.getCharField("value"); | |
379 switch (destType){ | |
380 case Types.T_CHAR: | |
381 case Types.T_INT: | |
382 return frame.setArgument( argIdx, v, attr); | |
383 case Types.T_LONG: | |
384 return frame.setLongArgument( argIdx, v, attr); | |
385 case Types.T_FLOAT: | |
386 return frame.setFloatArgument(argIdx, v, attr); | |
387 case Types.T_DOUBLE: | |
388 return frame.setDoubleArgument( argIdx, v, attr); | |
389 } | |
390 return -1; | |
391 } | |
392 case Types.T_BOOLEAN: | |
393 { | |
394 boolean v = eiArg.getBooleanField("value"); | |
395 if (destType == Types.T_BOOLEAN){ | |
396 return frame.setArgument( argIdx, v ? 1 : 0, attr); | |
397 } | |
398 return -1; | |
399 } | |
400 case Types.T_ARRAY: | |
401 { | |
402 int ref = eiArg.getObjectRef(); | |
403 if (destType == Types.T_ARRAY){ | |
404 return frame.setReferenceArgument( argIdx, ref, attr); | |
405 } | |
406 return -1; | |
407 } | |
408 case Types.T_REFERENCE: | |
409 { | |
410 int ref = eiArg.getObjectRef(); | |
411 if (destType == Types.T_REFERENCE){ | |
412 return frame.setReferenceArgument( argIdx, ref, attr); | |
413 } | |
414 return -1; | |
415 } | |
416 default: | |
417 // T_VOID, T_NONE | |
418 return -1; | |
419 } | |
420 } | |
421 | |
422 @MJI | |
423 public int invoke__Ljava_lang_Object_2_3Ljava_lang_Object_2__Ljava_lang_Object_2 (MJIEnv env, int mthRef, int objRef, int argsRef) { | |
424 ThreadInfo ti = env.getThreadInfo(); | |
425 MethodInfo miCallee = getMethodInfo(env, mthRef); | |
426 ClassInfo calleeClass = miCallee.getClassInfo(); | |
427 DirectCallStackFrame frame = ti.getReturnedDirectCall(); | |
428 | |
429 if (frame == null){ // first time | |
430 | |
431 //--- check the instance we are calling on | |
432 if (!miCallee.isStatic()) { | |
433 if (objRef == MJIEnv.NULL){ | |
434 env.throwException("java.lang.NullPointerException"); | |
435 return MJIEnv.NULL; | |
436 | |
437 } else { | |
438 ElementInfo eiObj = ti.getElementInfo(objRef); | |
439 ClassInfo objClass = eiObj.getClassInfo(); | |
440 | |
441 if (!objClass.isInstanceOf(calleeClass)) { | |
442 env.throwException(IllegalArgumentException.class.getName(), "Object is not an instance of declaring class. Actual = " + objClass + ". Expected = " + calleeClass); | |
443 return MJIEnv.NULL; | |
444 } | |
445 } | |
446 } | |
447 | |
448 //--- check accessibility | |
449 ElementInfo eiMth = ti.getElementInfo(mthRef); | |
450 if (! (Boolean) eiMth.getFieldValueObject("isAccessible")) { | |
451 StackFrame caller = ti.getTopFrame().getPrevious(); | |
452 ClassInfo callerClass = caller.getClassInfo(); | |
453 | |
454 if (callerClass != calleeClass) { | |
455 env.throwException(IllegalAccessException.class.getName(), "Class " + callerClass.getName() + | |
456 " can not access a member of class " + calleeClass.getName() | |
457 + " with modifiers \"" + Modifier.toString(miCallee.getModifiers())); | |
458 return MJIEnv.NULL; | |
459 } | |
460 } | |
461 | |
462 //--- push the direct call | |
463 frame = miCallee.createDirectCallStackFrame(ti, 0); | |
464 frame.setReflection(); | |
465 | |
466 int argOffset = 0; | |
467 if (!miCallee.isStatic()) { | |
468 frame.setReferenceArgument( argOffset++, objRef, null); | |
469 } | |
470 if (!pushUnboxedArguments( env, miCallee, frame, argOffset, argsRef)) { | |
471 // we've got a IllegalArgumentException | |
472 return MJIEnv.NULL; | |
473 } | |
474 ti.pushFrame(frame); | |
475 | |
476 | |
477 //--- check for and push required clinits | |
478 if (miCallee.isStatic()){ | |
479 calleeClass.pushRequiredClinits(ti); | |
480 } | |
481 | |
482 return MJIEnv.NULL; // reexecute | |
483 | |
484 } else { // we have returned from the direct call | |
485 return createBoxedReturnValueObject( env, miCallee, frame); | |
486 } | |
487 } | |
488 | |
489 | |
490 // this one has to collect annotations upwards in the inheritance chain | |
491 static int getAnnotations (MJIEnv env, MethodInfo mi){ | |
492 String mname = mi.getName(); | |
493 String msig = mi.genericSignature; | |
494 ArrayList<AnnotationInfo> aiList = new ArrayList<AnnotationInfo>(); | |
495 | |
496 // our own annotations | |
497 ClassInfo ci = mi.getClassInfo(); | |
498 for (AnnotationInfo ai : mi.getAnnotations()) { | |
499 aiList.add(ai); | |
500 } | |
501 | |
502 // our superclass annotations | |
503 for (ci = ci.getSuperClass(); ci != null; ci = ci.getSuperClass()){ | |
504 mi = ci.getMethod(mname, msig, false); | |
505 if (mi != null){ | |
506 for (AnnotationInfo ai: mi.getAnnotations()){ | |
507 aiList.add(ai); | |
508 } | |
509 } | |
510 } | |
511 | |
512 try { | |
513 return env.newAnnotationProxies(aiList.toArray(new AnnotationInfo[aiList.size()])); | |
514 } catch (ClinitRequired x){ | |
515 env.handleClinitRequest(x.getRequiredClassInfo()); | |
516 return MJIEnv.NULL; | |
517 } | |
518 } | |
519 | |
520 @MJI | |
521 public int getAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef){ | |
522 return getAnnotations( env, getMethodInfo(env,mthRef)); | |
523 } | |
524 | |
525 // the following ones consist of a package default implementation that is shared with | |
526 // the constructor peer, and a public model method | |
527 static int getAnnotation (MJIEnv env, MethodInfo mi, int annotationClsRef){ | |
528 ClassInfo aci = env.getReferredClassInfo(annotationClsRef); | |
529 | |
530 AnnotationInfo ai = mi.getAnnotation(aci.getName()); | |
531 if (ai != null){ | |
532 ClassInfo aciProxy = aci.getAnnotationProxy(); | |
533 try { | |
534 return env.newAnnotationProxy(aciProxy, ai); | |
535 } catch (ClinitRequired x){ | |
536 env.handleClinitRequest(x.getRequiredClassInfo()); | |
537 return MJIEnv.NULL; | |
538 } | |
539 } | |
540 | |
541 return MJIEnv.NULL; | |
542 } | |
543 | |
544 @MJI | |
545 public int getAnnotation__Ljava_lang_Class_2__Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef, int annotationClsRef) { | |
546 return getAnnotation(env, getMethodInfo(env,mthRef), annotationClsRef); | |
547 } | |
548 | |
549 static int getDeclaredAnnotations (MJIEnv env, MethodInfo mi){ | |
550 AnnotationInfo[] ai = mi.getAnnotations(); | |
551 | |
552 try { | |
553 return env.newAnnotationProxies(ai); | |
554 } catch (ClinitRequired x){ | |
555 env.handleClinitRequest(x.getRequiredClassInfo()); | |
556 return MJIEnv.NULL; | |
557 } | |
558 } | |
559 | |
560 @MJI | |
561 public int getDeclaredAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef){ | |
562 return getDeclaredAnnotations( env, getMethodInfo(env,mthRef)); | |
563 } | |
564 | |
565 static int getParameterAnnotations (MJIEnv env, MethodInfo mi){ | |
566 AnnotationInfo[][] pa = mi.getParameterAnnotations(); | |
567 // this should always return an array object, even if the method has no arguments | |
568 | |
569 try { | |
570 int paRef = env.newObjectArray("[Ljava/lang/annotation/Annotation;", pa.length); | |
571 | |
572 for (int i=0; i<pa.length; i++){ | |
573 int eRef = env.newAnnotationProxies(pa[i]); | |
574 env.setReferenceArrayElement(paRef, i, eRef); | |
575 } | |
576 | |
577 return paRef; | |
578 | |
579 } catch (ClinitRequired x){ // be prepared that we might have to initialize respective annotation classes | |
580 env.handleClinitRequest(x.getRequiredClassInfo()); | |
581 return MJIEnv.NULL; | |
582 } | |
583 } | |
584 | |
585 @MJI | |
586 public int getParameterAnnotations_____3_3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef){ | |
587 return getParameterAnnotations( env, getMethodInfo(env,mthRef)); | |
588 } | |
589 | |
590 @MJI | |
591 public int toString____Ljava_lang_String_2 (MJIEnv env, int objRef){ | |
592 StringBuilder sb = new StringBuilder(); | |
593 | |
594 MethodInfo mi = getMethodInfo(env, objRef); | |
595 | |
596 sb.append(Modifier.toString(mi.getModifiers())); | |
597 sb.append(' '); | |
598 | |
599 sb.append(mi.getReturnTypeName()); | |
600 sb.append(' '); | |
601 | |
602 sb.append(mi.getClassName()); | |
603 sb.append('.'); | |
604 | |
605 sb.append(mi.getName()); | |
606 | |
607 sb.append('('); | |
608 | |
609 String[] at = mi.getArgumentTypeNames(); | |
610 for (int i=0; i<at.length; i++){ | |
611 if (i>0) sb.append(','); | |
612 sb.append(at[i]); | |
613 } | |
614 | |
615 sb.append(')'); | |
616 | |
617 int sref = env.newString(sb.toString()); | |
618 return sref; | |
619 } | |
620 | |
621 @MJI | |
622 public boolean equals__Ljava_lang_Object_2__Z (MJIEnv env, int objRef, int mthRef){ | |
623 ElementInfo ei = env.getElementInfo(mthRef); | |
624 ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo(JPF_java_lang_Class.METHOD_CLASSNAME); | |
625 | |
626 if (ei.getClassInfo() == ci){ | |
627 MethodInfo mi1 = getMethodInfo(env, objRef); | |
628 MethodInfo mi2 = getMethodInfo(env, mthRef); | |
629 if (mi1.getClassInfo() == mi2.getClassInfo()){ | |
630 if (mi1.getName().equals(mi2.getName())){ | |
631 if (mi1.getReturnType().equals(mi2.getReturnType())){ | |
632 byte[] params1 = mi1.getArgumentTypes(); | |
633 byte[] params2 = mi2.getArgumentTypes(); | |
634 if (params1.length == params2.length){ | |
635 for (int i = 0; i < params1.length; i++){ | |
636 if (params1[i] != params2[i]){ | |
637 return false; | |
638 } | |
639 } | |
640 return true; | |
641 } | |
642 } | |
643 } | |
644 } | |
645 } | |
646 return false; | |
647 } | |
648 | |
649 @MJI | |
650 public int hashCode____I (MJIEnv env, int objRef){ | |
651 MethodInfo mi = getMethodInfo(env, objRef); | |
652 return mi.getClassName().hashCode() ^ mi.getName().hashCode(); | |
653 } | |
654 } |