// // Copyright (C) 2007 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.lang.reflect.Modifier; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import gov.nasa.jpf.Config; import gov.nasa.jpf.annotation.MJI; import gov.nasa.jpf.util.MethodInfoRegistry; import gov.nasa.jpf.util.RunListener; import gov.nasa.jpf.util.RunRegistry; /** * native peer for rudimentary constructor reflection. * * Unfortunately, this is quite redundant to the Method peer, but Constructor * is not a Method subclass, and hence we can't rely on it's initialization */ public class JPF_java_lang_reflect_Constructor extends NativePeer { static MethodInfoRegistry registry; public static boolean init (Config conf) { // this is an example of how to handle cross-initialization between // native peers - this might also get explicitly called by the java.lang.Class // peer, since it creates Constructor objects. Here we have to make sure // we only reset between JPF runs if (registry == null){ registry = new MethodInfoRegistry(); RunRegistry.getDefaultRegistry().addListener( new RunListener() { public void reset (RunRegistry reg){ registry = null; } }); } return true; } static int createConstructorObject (MJIEnv env, ClassInfo ciCtor, MethodInfo mi, FeatureExpr ctx){ // note - it is the callers responsibility to ensure Constructor is properly initialized int regIdx = registry.registerMethodInfo(mi); int eidx = env.newObject(ctx, ciCtor); ElementInfo ei = env.getModifiableElementInfo(eidx); ei.setIntField(ctx, "regIdx", One.valueOf(regIdx)); return eidx; } static MethodInfo getMethodInfo (FeatureExpr ctx, MJIEnv env, int objRef){ return registry.getMethodInfo(ctx,env, objRef, "regIdx"); } @MJI public int getName____Ljava_lang_String_2 (MJIEnv env, int objRef, FeatureExpr ctx) { MethodInfo mi = getMethodInfo(ctx, env, objRef); int nameRef = env.getReferenceField( ctx, objRef, "name").getValue(); if (nameRef == MJIEnv.NULL) { nameRef = env.newString(ctx, mi.getName()); env.setReferenceField(ctx, objRef, "name", nameRef); } return nameRef; } // <2do> .. and some more delegations to JPF_java_lang_Method @MJI public int newInstance___3Ljava_lang_Object_2__Ljava_lang_Object_2 (MJIEnv env, int mthRef, int argsRef, FeatureExpr ctx) { ThreadInfo ti = env.getThreadInfo(); DirectCallStackFrame frame = ti.getReturnedDirectCall(); MethodInfo miCallee = getMethodInfo(ctx,env, mthRef); if (miCallee.isPrivate() && !env.getBooleanField(mthRef, "isAccessible").getValue()) {// constructor is private if (ti.getTopFrame().getPrevious().mi.ci != miCallee.ci) { env.throwException(ctx, IllegalAccessException.class.getName()); return MJIEnv.NULL; } } if (frame == null) { // first time ClassInfo ci = miCallee.getClassInfo(); if (ci.isAbstract()){ env.throwException(ctx, "java.lang.InstantiationException"); return MJIEnv.NULL; } int objRef = env.newObjectOfUncheckedClass( ctx, ci); frame = miCallee.createDirectCallStackFrame( ctx, ti, 1); frame.setReflection(); frame.setLocalReferenceVariable(ctx, 0, objRef); // (1) store the objRef for retrieval during re-exec int argOffset = frame.setReferenceArgument(ctx, 0, objRef, null); if (!JPF_java_lang_reflect_Method.pushUnboxedArguments( env, miCallee, frame, argOffset, argsRef, ctx)) { // we've got a IllegalArgumentException return MJIEnv.NULL; } ti.pushFrame(frame); ci.pushRequiredClinits(ctx, ti); env.repeatInvocation(); return MJIEnv.NULL; } else { // reflection call returned int objRef = frame.getLocalVariable(ctx, 0).getValue(); // that's the object ref we stored in (1) return objRef; } } @MJI public int getParameterTypes_____3Ljava_lang_Class_2 (MJIEnv env, int objRef, FeatureExpr ctx){ // kind of dangerous, but we don't refer to any fields and the underlying JPF construct // (MethodInfo) is the same, so we just delegate to avoid copying non-trivial code return JPF_java_lang_reflect_Method.getParameterTypes (env, getMethodInfo(ctx,env, objRef), ctx); } @MJI public int getAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef, FeatureExpr ctx){ // <2do> check if ctor annotations are inherited, which is a bit off return JPF_java_lang_reflect_Method.getAnnotations( env, getMethodInfo(ctx,env, objRef), ctx); } @MJI public int getDeclaredAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef, FeatureExpr ctx){ return JPF_java_lang_reflect_Method.getDeclaredAnnotations( env, getMethodInfo(ctx,env, objRef), ctx); } @MJI public int getAnnotation__Ljava_lang_Class_2__Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef, int annotationClsRef, FeatureExpr ctx) { return JPF_java_lang_reflect_Method.getAnnotation( env, getMethodInfo(ctx,env, objRef), annotationClsRef, ctx); } @MJI public int getParameterAnnotations_____3_3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef, FeatureExpr ctx){ return JPF_java_lang_reflect_Method.getParameterAnnotations( env, getMethodInfo(ctx,env, objRef), ctx); } @MJI public int getModifiers____I (MJIEnv env, int objRef, FeatureExpr ctx){ MethodInfo mi = getMethodInfo(ctx, env, objRef); return mi.getModifiers(); } @MJI public int getDeclaringClass____Ljava_lang_Class_2 (MJIEnv env, int objRef, FeatureExpr ctx){ MethodInfo mi = getMethodInfo(ctx, env, objRef); ClassInfo ci = mi.getClassInfo(); // can't get a Constructor object w/o having initialized it's declaring class first return ci.getClassObjectRef(); } @MJI public int toString____Ljava_lang_String_2 (MJIEnv env, int objRef, FeatureExpr ctx){ StringBuilder sb = new StringBuilder(); MethodInfo mi = getMethodInfo(ctx, env, objRef); sb.append(Modifier.toString(mi.getModifiers())); sb.append(' '); sb.append(mi.getClassInfo().getName()); sb.append('('); String[] at = mi.getArgumentTypeNames(); for (int i=0; i<at.length; i++){ if (i>0) sb.append(','); sb.append(at[i]); } sb.append(')'); int sref = env.newString(ctx, sb.toString()); return sref; } @MJI public boolean equals__Ljava_lang_Object_2__Z (MJIEnv env, int objRef, int mthRef, FeatureExpr ctx){ ElementInfo ei = env.getElementInfo(mthRef); ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo(JPF_java_lang_Class.CONSTRUCTOR_CLASSNAME); if (ei.getClassInfo() == ci){ MethodInfo mi1 = getMethodInfo(ctx, env, objRef); MethodInfo mi2 = getMethodInfo(ctx, env, mthRef); if (mi1.getClassInfo() == mi2.getClassInfo()){ if (mi1.getName().equals(mi2.getName())){ if (mi1.getReturnType().equals(mi2.getReturnType())){ byte[] params1 = mi1.getArgumentTypes(); byte[] params2 = mi2.getArgumentTypes(); if (params1.length == params2.length){ for (int i = 0; i < params1.length; i++){ if (params1[i] != params2[i]) return false; } return true; } } } } } return false; } @MJI public int hashCode____I (MJIEnv env, int objRef, FeatureExpr ctx){ MethodInfo ctor = getMethodInfo(ctx, env, objRef); return ctor.getClassName().hashCode(); } }