// // Copyright (C) 2006 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 cmu.conditional.Conditional; import java.util.function.Function; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import gov.nasa.jpf.JPFException; import gov.nasa.jpf.annotation.MJI; /** * MJI NativePeer class for java.lang.Object library abstraction */ public class JPF_java_lang_Object extends NativePeer { @MJI public Conditional<Integer> getClass____Ljava_lang_Class_2 (final MJIEnv env, Conditional<Integer> objref, FeatureExpr ctx) { return objref.mapr(new Function<Integer, Conditional<Integer>>() { @Override public Conditional<Integer> apply(Integer objref) { ClassInfo oci = env.getClassInfo(objref); return new One<>(oci.getClassObjectRef()); } }).simplify(); } @MJI public int clone____Ljava_lang_Object_2 (MJIEnv env, int objref, FeatureExpr ctx) { Heap heap = env.getHeap(); ElementInfo ei = heap.get(objref); ClassInfo ci = ei.getClassInfo(); ElementInfo eiClone = null; if (!ci.isInstanceOf("java.lang.Cloneable")) { env.throwException(ctx, "java.lang.CloneNotSupportedException", ci.getName() + " does not implement java.lang.Cloneable."); return MJIEnv.NULL; // meaningless } else { // int newref; if (ci.isArray()) { ClassInfo cci = ci.getComponentClassInfo(); String componentType; if (cci.isPrimitive()){ componentType = Types.getTypeSignature(cci.getName(),false); } else { componentType = cci.getType(); } eiClone = heap.newArray(ctx, componentType, ei.arrayLength().getValue(), env.getThreadInfo()); } else { eiClone = heap.newObject(ctx, ci, env.getThreadInfo()); } // Ok, this is nasty but efficient eiClone.fields = ei.getFields().clone(); return eiClone.getObjectRef(); } } @MJI public int hashCode____I (MJIEnv env, int objref, FeatureExpr ctx) { return (objref ^ 0xABCD); } static void wait0(MJIEnv env, int objref, long timeout, FeatureExpr ctx) { // IllegalMonitorStateExceptions are checked in the MJIEnv methods ThreadInfo ti = env.getThreadInfo(); SystemState ss = env.getSystemState(); ElementInfo ei = env.getModifiableElementInfo(objref); if (ti.isFirstStepInsn()) { // we already have a CG switch (ti.getState()) { // we can get here by direct call from ...Unsafe.park__ZJ__V() // which aquires the park lock and waits natively case RUNNING: // note that we can't get here if we are in NOTIFIED or INTERRUPTED state, // since we still have to reacquire the lock case UNBLOCKED: case TIMEDOUT: // nobody else acquired the lock // thread status set by explicit notify() call env.lockNotified(objref); if (ti.isInterrupted(ctx, true)) { env.throwException(ctx, "java.lang.InterruptedException"); } break; default: throw new JPFException("invalid thread state of: " + ti.getName() + " is " + ti.getStateName() + " while waiting on " + ei); } } else { // first time, break the transition (if we don't have a pending interrupt) // no need for a CG if we got interrupted - don't give up locks, throw InterruptedException if (ti.isInterrupted(ctx, true)) { env.throwException(ctx, "java.lang.InterruptedException"); } else { if (!ei.isLockedBy(ti)){ env.throwException(ctx, "java.lang.IllegalMonitorStateException", "un-synchronized wait"); return; } // releases the lock and sets BLOCKED threads to UNBLOCKED ei.wait(ti, timeout); // note we pass in the timeout value, since this might determine the type of CG that is created ChoiceGenerator<?> cg = ss.getSchedulerFactory().createWaitCG(ei, ti, timeout); ss.setMandatoryNextChoiceGenerator(cg, "wait without CG"); env.repeatInvocation(); // so that we can still see the wait on the callstack } } } // we intercept them both so that we don't get the java.lang.Object.wait() location // as the blocking insn @MJI public void wait____V (MJIEnv env, int objref, FeatureExpr ctx){ wait0(env,objref,0, ctx); } @MJI public void wait__J__V (MJIEnv env, int objref, long timeout, FeatureExpr ctx) { wait0(env,objref,timeout, ctx); } @MJI public void wait__JI__V (MJIEnv env, int objref, long timeout, int nanos, FeatureExpr ctx) { wait0(env,objref,timeout, ctx); } @MJI public void notify____V (MJIEnv env, int objref, FeatureExpr ctx) { // IllegalMonitorStateExceptions are checked in the MJIEnv methods ThreadInfo ti = env.getThreadInfo(); SystemState ss = env.getSystemState(); ElementInfo ei = env.getModifiableElementInfo(objref); if (!ti.isFirstStepInsn()) { // first time around ChoiceGenerator<?> cg = ss.getSchedulerFactory().createNotifyCG(ei, ti); if (ss.setNextChoiceGenerator(cg)){ ti.skipInstructionLogging(); env.repeatInvocation(); return; } } // this is a bit cluttered throughout the whole system, with the actual thread // notification (status change) taking place in the ElementInfo env.notify(ctx, ei); } @MJI public void notifyAll____V (MJIEnv env, int objref, FeatureExpr ctx) { // IllegalMonitorStateExceptions are checked in the MJIEnv methods // usually, there is no non-determinism involved here, but // we might have a SchedulerFactory policy that does want to // break, so we have to give it a chance to interfere ThreadInfo ti = env.getThreadInfo(); SystemState ss = env.getSystemState(); if (!ti.isFirstStepInsn()) { // first time around ElementInfo ei = env.getModifiableElementInfo(objref); env.notifyAll(ctx, ei); // do that before we create a CG ChoiceGenerator<?> cg = ss.getSchedulerFactory().createNotifyAllCG(ei, ti); if (ss.setNextChoiceGenerator(cg)){ ti.skipInstructionLogging(); env.repeatInvocation(); return; } } } @MJI public int toString____Ljava_lang_String_2 (MJIEnv env, int objref, FeatureExpr ctx) { ClassInfo ci = env.getClassInfo(objref); int hc = hashCode____I(env,objref, ctx); String s = ci.getName() + '@' + hc; int sref = env.newString(ctx, s); return sref; } }