From a9bc9081ebda74eb6ee5451d2b719405db3a955c Mon Sep 17 00:00:00 2001 From: Nastaran Shafiei Date: Tue, 30 May 2017 17:46:11 -0700 Subject: [PATCH] Initial import --- .classpath | 11 + .gitignore | 17 + .idea/.name | 1 + .idea/annotations.iml | 13 + .idea/artifacts/RunJPF.xml | 33 + .idea/artifacts/jpf.xml | 21 + .idea/artifacts/jpf_annotations.xml | 8 + .idea/artifacts/jpf_classes.xml | 25 + .idea/classes.iml | 15 + .idea/codeStyleSettings.xml | 13 + .idea/compiler.xml | 23 + .idea/copyright/profiles_settings.xml | 3 + .idea/encodings.xml | 4 + .idea/examples.iml | 16 + .idea/main.iml | 14 + .idea/misc.xml | 57 + .idea/modules.xml | 13 + .idea/peers.iml | 15 + .idea/runConfigurations/run_example_jpf.xml | 25 + .idea/runConfigurations/run_test.xml | 19 + .idea/scopes/scope_settings.xml | 5 + .idea/tests.iml | 17 + .idea/vcs.xml | 6 + .project | 26 + LICENSE-2.0.txt | 202 + META-INF/RunJPF/MANIFEST.MF | 3 + README | 36 + bin/javajpf | 10 + bin/jpf | 13 + bin/jpf.bat | 13 + bin/print_class | 5 + bin/print_class.bat | 8 + bin/print_events | 5 + bin/test | 13 + bin/test.bat | 13 + build.properties | 22 + build.xml | 456 ++ doc/devel/attributes.md | 18 + doc/devel/bytecode_factory.md | 70 + doc/devel/choicegenerator.md | 212 + doc/devel/coding_conventions.md | 41 + doc/devel/create_project.md | 91 + doc/devel/design.md | 52 + doc/devel/eclipse_plugin_update.md | 36 + doc/devel/embedded.md | 27 + doc/devel/index.md | 23 + doc/devel/jpf_tests.md | 148 + doc/devel/listener.md | 332 ++ doc/devel/logging.md | 31 + doc/devel/mercurial.md | 56 + doc/devel/mji.md | 214 + doc/devel/mji/mangling.md | 200 + doc/devel/modules.md | 21 + doc/devel/partial_order_reduction.md | 67 + doc/devel/report.md | 70 + doc/graphics/DFSListener.svg | 3 + doc/graphics/app-types.svg | 3 + doc/graphics/attributes.svg | 3 + doc/graphics/bc-factory.svg | 3 + doc/graphics/cg-impl.svg | 3 + doc/graphics/cg-motivation.svg | 3 + doc/graphics/cg-ontology.svg | 3 + doc/graphics/cg-sequence.svg | 3 + doc/graphics/choicegen-example.svg | 3 + doc/graphics/genpeer.svg | 3 + doc/graphics/interleavings.svg | 3 + doc/graphics/jpf-abstractions.svg | 3 + doc/graphics/jpf-basic.svg | 3 + doc/graphics/jpf-intro-new.svg | 3 + doc/graphics/jpf-layers.svg | 3 + doc/graphics/jpf-project.svg | 3 + doc/graphics/listener-overview.svg | 3 + doc/graphics/listeners.svg | 3 + doc/graphics/mji-call.svg | 3 + doc/graphics/mji-functions.svg | 3 + doc/graphics/mji-mangling.svg | 3 + doc/graphics/new-testing.svg | 3 + doc/graphics/por-mark.svg | 3 + doc/graphics/por-scheduling-relevance.svg | 3 + doc/graphics/properties.svg | 3 + doc/graphics/report.svg | 3 + doc/graphics/states-mc.svg | 3 + doc/graphics/states-testing.svg | 3 + doc/graphics/sw-model-checking-2.svg | 3 + doc/graphics/sw-model-checking.svg | 3 + doc/index.md | 66 + doc/install/build.md | 112 + doc/install/eclipse-jpf.md | 24 + doc/install/eclipse-plugin.md | 15 + doc/install/eclipse-plugin/update.md | 1 + doc/install/eclipse-plugin/update/features.md | 1 + doc/install/eclipse-plugin/update/plugins.md | 1 + doc/install/index.md | 19 + doc/install/netbeans-jpf.md | 10 + doc/install/netbeans-plugin.md | 11 + doc/install/repo_shell.md | 74 + doc/install/repositories.md | 68 + doc/install/requirements.md | 79 + doc/install/site-properties.md | 32 + doc/install/snapshot.md | 14 + doc/intro/classification.md | 25 + doc/intro/index.md | 17 + doc/intro/race_example.md | 105 + doc/intro/random_example.md | 95 + doc/intro/testing_vs_model_checking.md | 28 + doc/intro/what_is_jpf.md | 44 + doc/jpf-core/AssertionProperty.md | 88 + doc/jpf-core/ErrorTraceGenerator.md | 32 + doc/jpf-core/ExceptionInjector.md | 105 + doc/jpf-core/IdleFilter.md | 99 + doc/jpf-core/index.md | 43 + doc/papers/chicago-author-date.csl | 549 ++ doc/papers/index.md | 133 + doc/papers/references.bib | 636 +++ doc/user/api.md | 125 + doc/user/application_types.md | 36 + doc/user/components.md | 57 + doc/user/config.md | 153 + doc/user/config/random.md | 15 + doc/user/index.md | 19 + doc/user/output.md | 98 + doc/user/run.md | 258 + doc/user/run_eclipse.md | 20 + doc/user/run_eclipse_plugin.md | 12 + doc/user/run_nb.md | 92 + doc/user/run_nb_plugin.md | 12 + eclipse/AntBuilder.launch | 17 + eclipse/run-JPF.launch | 29 + eclipse/test-JPF.launch | 29 + eclipse/update-JPF-siteproperties.launch | 13 + jpf.properties | 427 ++ nbproject/ide-file-targets.xml | 255 + nbproject/project.xml | 325 ++ .../gov/nasa/jpf/annotation/FilterField.java | 45 + .../gov/nasa/jpf/annotation/FilterFrame.java | 53 + .../gov/nasa/jpf/annotation/JPFAttribute.java | 30 + .../gov/nasa/jpf/annotation/JPFConfig.java | 32 + .../gov/nasa/jpf/annotation/JPFOption.java | 26 + .../gov/nasa/jpf/annotation/JPFOptions.java | 24 + .../gov/nasa/jpf/annotation/MJI.java | 31 + .../gov/nasa/jpf/annotation/NeverBreak.java | 30 + .../nasa/jpf/annotation/NoJPFExecution.java | 39 + .../gov/nasa/jpf/annotation/NonShared.java | 30 + .../gov/nasa/jpf/AnnotationProxyBase.java | 80 + src/classes/gov/nasa/jpf/BoxObjectCaches.java | 45 + .../gov/nasa/jpf/CachedROHttpConnection.java | 84 + .../gov/nasa/jpf/ConsoleOutputStream.java | 117 + src/classes/gov/nasa/jpf/EventProducer.java | 37 + src/classes/gov/nasa/jpf/FinalizerThread.java | 71 + .../nasa/jpf/SerializationConstructor.java | 44 + src/classes/java/io/File.java | 189 + src/classes/java/io/FileDescriptor.java | 86 + src/classes/java/io/FileInputStream.java | 93 + src/classes/java/io/FileOutputStream.java | 80 + src/classes/java/io/InputStreamReader.java | 109 + src/classes/java/io/OutputStreamWriter.java | 127 + src/classes/java/io/RandomAccessFile.java | 106 + src/classes/java/lang/Class.java | 362 ++ src/classes/java/lang/ClassLoader.java | 257 + .../java/lang/InheritableThreadLocal.java | 37 + src/classes/java/lang/Object.java | 63 + src/classes/java/lang/StackTraceElement.java | 94 + src/classes/java/lang/String.java | 372 ++ src/classes/java/lang/System.java | 213 + src/classes/java/lang/Thread.java | 411 ++ src/classes/java/lang/ThreadGroup.java | 487 ++ src/classes/java/lang/ThreadLocal.java | 112 + src/classes/java/lang/Throwable.java | 142 + .../java/lang/annotation/Inherited.java | 24 + .../java/lang/annotation/Retention.java | 25 + src/classes/java/lang/ref/Reference.java | 67 + src/classes/java/lang/ref/ReferenceQueue.java | 43 + src/classes/java/lang/ref/WeakReference.java | 31 + .../java/lang/reflect/AccessibleObject.java | 48 + .../java/lang/reflect/Constructor.java | 80 + src/classes/java/lang/reflect/Field.java | 94 + .../reflect/InvocationTargetException.java | 35 + src/classes/java/lang/reflect/Method.java | 85 + src/classes/java/net/URLClassLoader.java | 127 + src/classes/java/nio/Buffer.java | 81 + .../java/nio/BufferUnderflowException.java | 22 + src/classes/java/nio/ByteBuffer.java | 288 + src/classes/java/nio/ByteOrder.java | 36 + .../java/nio/channels/FileChannel.java | 50 + src/classes/java/nio/package-info.java | 24 + .../java/security/AccessController.java | 78 + src/classes/java/security/MessageDigest.java | 68 + .../java/security/SecureClassLoader.java | 34 + src/classes/java/text/DecimalFormat.java | 141 + src/classes/java/text/Format.java | 57 + src/classes/java/text/NumberFormat.java | 87 + src/classes/java/text/SimpleDateFormat.java | 90 + src/classes/java/util/Random.java | 73 + src/classes/java/util/TimeZone.java | 134 + .../concurrent/BrokenBarrierException.java | 29 + .../java/util/concurrent/CyclicBarrier.java | 104 + .../java/util/concurrent/Exchanger.java | 53 + .../concurrent/atomic/AtomicIntegerArray.java | 127 + .../atomic/AtomicIntegerFieldUpdater.java | 51 + .../concurrent/atomic/AtomicLongArray.java | 127 + .../atomic/AtomicLongFieldUpdater.java | 51 + .../atomic/AtomicReferenceArray.java | 98 + .../atomic/AtomicReferenceFieldUpdater.java | 45 + src/classes/java/util/function/Supplier.java | 25 + .../java/util/logging/FileHandler.java | 36 + src/classes/java/util/regex/Matcher.java | 115 + src/classes/java/util/regex/Pattern.java | 65 + src/classes/org/junit/After.java | 34 + src/classes/org/junit/AfterClass.java | 34 + src/classes/org/junit/Before.java | 34 + src/classes/org/junit/BeforeClass.java | 34 + src/classes/org/junit/Ignore.java | 34 + src/classes/org/junit/Test.java | 54 + src/classes/sun/misc/AtomicLong.java | 70 + src/classes/sun/misc/JavaAWTAccess.java | 35 + src/classes/sun/misc/JavaIOAccess.java | 36 + .../sun/misc/JavaIODeleteOnExitAccess.java | 32 + .../sun/misc/JavaIOFileDescriptorAccess.java | 37 + src/classes/sun/misc/JavaLangAccess.java | 51 + src/classes/sun/misc/JavaNetAccess.java | 33 + src/classes/sun/misc/JavaNioAccess.java | 33 + src/classes/sun/misc/SharedSecrets.java | 174 + src/classes/sun/misc/Unsafe.java | 248 + .../sun/net/www/protocol/http/Handler.java | 88 + src/classes/sun/nio/ch/Interruptible.java | 32 + src/classes/sun/reflect/ConstantPool.java | 91 + .../reflect/annotation/AnnotationType.java | 143 + src/examples/BoundedBuffer.java | 143 + src/examples/BoundedBuffer.jpf | 4 + src/examples/Crossing.java | 243 + src/examples/Crossing.jpf | 5 + src/examples/DiningPhil.java | 64 + src/examples/DiningPhil.jpf | 3 + src/examples/HelloWorld.java | 26 + src/examples/HelloWorld.jpf | 1 + src/examples/NumericValueCheck.java | 31 + src/examples/NumericValueCheck.jpf | 10 + src/examples/Racer.java | 43 + src/examples/Racer.jpf | 5 + src/examples/Rand.java | 37 + src/examples/Rand.jpf | 4 + src/examples/RobotManager-replay-nt.jpf | 7 + src/examples/RobotManager-replay-ot.jpf | 10 + src/examples/RobotManager.java | 140 + src/examples/RobotManager.jpf | 5 + src/examples/StopWatch.java | 35 + src/examples/StopWatch.jpf | 3 + src/examples/TestExample-coverage.jpf | 7 + src/examples/TestExample.java | 74 + src/examples/oldclassic-da.jpf | 10 + src/examples/oldclassic.java | 137 + src/examples/oldclassic.jpf | 5 + src/main/gov/nasa/jpf/$coreTag.java | 35 + src/main/gov/nasa/jpf/Config.java | 2468 ++++++++ .../gov/nasa/jpf/ConfigChangeListener.java | 41 + src/main/gov/nasa/jpf/Error.java | 73 + src/main/gov/nasa/jpf/GenericProperty.java | 65 + src/main/gov/nasa/jpf/JPF.java | 731 +++ src/main/gov/nasa/jpf/JPFClassLoader.java | 84 + src/main/gov/nasa/jpf/JPFConfigException.java | 51 + src/main/gov/nasa/jpf/JPFErrorException.java | 28 + src/main/gov/nasa/jpf/JPFException.java | 46 + src/main/gov/nasa/jpf/JPFListener.java | 27 + .../gov/nasa/jpf/JPFListenerException.java | 29 + .../gov/nasa/jpf/JPFNativePeerException.java | 29 + src/main/gov/nasa/jpf/JPFShell.java | 42 + src/main/gov/nasa/jpf/ListenerAdapter.java | 146 + src/main/gov/nasa/jpf/Property.java | 43 + .../gov/nasa/jpf/PropertyListenerAdapter.java | 171 + src/main/gov/nasa/jpf/State.java | 59 + src/main/gov/nasa/jpf/StateExtension.java | 23 + src/main/gov/nasa/jpf/SystemAttribute.java | 28 + src/main/gov/nasa/jpf/jvm/ClassFile.java | 2735 +++++++++ .../gov/nasa/jpf/jvm/ClassFilePrinter.java | 780 +++ .../gov/nasa/jpf/jvm/ClassFileReader.java | 196 + .../nasa/jpf/jvm/ClassFileReaderAdapter.java | 249 + .../nasa/jpf/jvm/DirClassFileContainer.java | 86 + .../gov/nasa/jpf/jvm/JVMAnnotationParser.java | 184 + .../gov/nasa/jpf/jvm/JVMByteCodePrinter.java | 1096 ++++ .../gov/nasa/jpf/jvm/JVMByteCodeReader.java | 247 + .../jpf/jvm/JVMByteCodeReaderAdapter.java | 455 ++ .../nasa/jpf/jvm/JVMClassFileContainer.java | 79 + src/main/gov/nasa/jpf/jvm/JVMClassInfo.java | 950 ++++ src/main/gov/nasa/jpf/jvm/JVMCodeBuilder.java | 1326 +++++ .../nasa/jpf/jvm/JVMDirectCallStackFrame.java | 129 + .../nasa/jpf/jvm/JVMInstructionFactory.java | 485 ++ .../gov/nasa/jpf/jvm/JVMNativeStackFrame.java | 127 + src/main/gov/nasa/jpf/jvm/JVMStackFrame.java | 110 + .../jpf/jvm/JVMSystemClassLoaderInfo.java | 178 + .../nasa/jpf/jvm/JarClassFileContainer.java | 157 + .../gov/nasa/jpf/jvm/bytecode/AALOAD.java | 57 + .../gov/nasa/jpf/jvm/bytecode/AASTORE.java | 146 + .../nasa/jpf/jvm/bytecode/ACONST_NULL.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/ALOAD.java | 81 + .../gov/nasa/jpf/jvm/bytecode/ANEWARRAY.java | 101 + .../gov/nasa/jpf/jvm/bytecode/ARETURN.java | 86 + .../nasa/jpf/jvm/bytecode/ARRAYLENGTH.java | 82 + .../gov/nasa/jpf/jvm/bytecode/ASTORE.java | 77 + .../gov/nasa/jpf/jvm/bytecode/ATHROW.java | 54 + .../jvm/bytecode/ArrayLoadInstruction.java | 121 + .../jvm/bytecode/ArrayStoreInstruction.java | 128 + .../gov/nasa/jpf/jvm/bytecode/BALOAD.java | 59 + .../gov/nasa/jpf/jvm/bytecode/BASTORE.java | 68 + .../gov/nasa/jpf/jvm/bytecode/BIPUSH.java | 65 + .../gov/nasa/jpf/jvm/bytecode/CALOAD.java | 46 + .../gov/nasa/jpf/jvm/bytecode/CASTORE.java | 53 + .../gov/nasa/jpf/jvm/bytecode/CHECKCAST.java | 113 + src/main/gov/nasa/jpf/jvm/bytecode/D2F.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/D2I.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/D2L.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/DADD.java | 54 + .../gov/nasa/jpf/jvm/bytecode/DALOAD.java | 46 + .../gov/nasa/jpf/jvm/bytecode/DASTORE.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/DCMPG.java | 49 + src/main/gov/nasa/jpf/jvm/bytecode/DCMPL.java | 51 + .../gov/nasa/jpf/jvm/bytecode/DCONST.java | 59 + src/main/gov/nasa/jpf/jvm/bytecode/DDIV.java | 54 + .../jpf/jvm/bytecode/DIRECTCALLRETURN.java | 78 + src/main/gov/nasa/jpf/jvm/bytecode/DLOAD.java | 74 + src/main/gov/nasa/jpf/jvm/bytecode/DMUL.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/DNEG.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/DREM.java | 58 + .../gov/nasa/jpf/jvm/bytecode/DRETURN.java | 60 + .../gov/nasa/jpf/jvm/bytecode/DSTORE.java | 70 + src/main/gov/nasa/jpf/jvm/bytecode/DSUB.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/DUP.java | 49 + src/main/gov/nasa/jpf/jvm/bytecode/DUP2.java | 49 + .../gov/nasa/jpf/jvm/bytecode/DUP2_X1.java | 48 + .../gov/nasa/jpf/jvm/bytecode/DUP2_X2.java | 49 + .../gov/nasa/jpf/jvm/bytecode/DUP_X1.java | 49 + .../gov/nasa/jpf/jvm/bytecode/DUP_X2.java | 48 + .../bytecode/DoubleCompareInstruction.java | 45 + .../nasa/jpf/jvm/bytecode/EXECUTENATIVE.java | 99 + src/main/gov/nasa/jpf/jvm/bytecode/F2D.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/F2I.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/F2L.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/FADD.java | 54 + .../gov/nasa/jpf/jvm/bytecode/FALOAD.java | 46 + .../gov/nasa/jpf/jvm/bytecode/FASTORE.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/FCMPG.java | 64 + src/main/gov/nasa/jpf/jvm/bytecode/FCMPL.java | 66 + .../gov/nasa/jpf/jvm/bytecode/FCONST.java | 61 + src/main/gov/nasa/jpf/jvm/bytecode/FDIV.java | 54 + .../nasa/jpf/jvm/bytecode/FINISHCLINIT.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/FLOAD.java | 74 + src/main/gov/nasa/jpf/jvm/bytecode/FMUL.java | 55 + src/main/gov/nasa/jpf/jvm/bytecode/FNEG.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/FREM.java | 58 + .../gov/nasa/jpf/jvm/bytecode/FRETURN.java | 80 + .../gov/nasa/jpf/jvm/bytecode/FSTORE.java | 75 + src/main/gov/nasa/jpf/jvm/bytecode/FSUB.java | 54 + .../gov/nasa/jpf/jvm/bytecode/GETFIELD.java | 138 + .../gov/nasa/jpf/jvm/bytecode/GETSTATIC.java | 129 + src/main/gov/nasa/jpf/jvm/bytecode/GOTO.java | 102 + .../gov/nasa/jpf/jvm/bytecode/GOTO_W.java | 41 + .../gov/nasa/jpf/jvm/bytecode/GetHelper.java | 78 + src/main/gov/nasa/jpf/jvm/bytecode/I2B.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/I2C.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/I2D.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/I2F.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/I2L.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/I2S.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/IADD.java | 52 + .../gov/nasa/jpf/jvm/bytecode/IALOAD.java | 46 + src/main/gov/nasa/jpf/jvm/bytecode/IAND.java | 52 + .../gov/nasa/jpf/jvm/bytecode/IASTORE.java | 53 + .../gov/nasa/jpf/jvm/bytecode/ICONST.java | 80 + src/main/gov/nasa/jpf/jvm/bytecode/IDIV.java | 57 + src/main/gov/nasa/jpf/jvm/bytecode/IFEQ.java | 49 + src/main/gov/nasa/jpf/jvm/bytecode/IFGE.java | 48 + src/main/gov/nasa/jpf/jvm/bytecode/IFGT.java | 48 + src/main/gov/nasa/jpf/jvm/bytecode/IFLE.java | 47 + src/main/gov/nasa/jpf/jvm/bytecode/IFLT.java | 48 + src/main/gov/nasa/jpf/jvm/bytecode/IFNE.java | 48 + .../gov/nasa/jpf/jvm/bytecode/IFNONNULL.java | 49 + .../gov/nasa/jpf/jvm/bytecode/IFNULL.java | 47 + .../gov/nasa/jpf/jvm/bytecode/IF_ACMPEQ.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ACMPNE.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ICMPEQ.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ICMPGE.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ICMPGT.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ICMPLE.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ICMPLT.java | 51 + .../gov/nasa/jpf/jvm/bytecode/IF_ICMPNE.java | 51 + src/main/gov/nasa/jpf/jvm/bytecode/IINC.java | 78 + src/main/gov/nasa/jpf/jvm/bytecode/ILOAD.java | 74 + src/main/gov/nasa/jpf/jvm/bytecode/IMUL.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/INEG.java | 51 + .../gov/nasa/jpf/jvm/bytecode/INSTANCEOF.java | 94 + .../gov/nasa/jpf/jvm/bytecode/INVOKECG.java | 147 + .../nasa/jpf/jvm/bytecode/INVOKECLINIT.java | 88 + .../nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java | 130 + .../jpf/jvm/bytecode/INVOKEINTERFACE.java | 53 + .../nasa/jpf/jvm/bytecode/INVOKESPECIAL.java | 138 + .../nasa/jpf/jvm/bytecode/INVOKESTATIC.java | 203 + .../nasa/jpf/jvm/bytecode/INVOKEVIRTUAL.java | 49 + src/main/gov/nasa/jpf/jvm/bytecode/IOR.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/IREM.java | 56 + .../gov/nasa/jpf/jvm/bytecode/IRETURN.java | 80 + src/main/gov/nasa/jpf/jvm/bytecode/ISHL.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/ISHR.java | 52 + .../gov/nasa/jpf/jvm/bytecode/ISTORE.java | 75 + src/main/gov/nasa/jpf/jvm/bytecode/ISUB.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/IUSHR.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/IXOR.java | 52 + .../nasa/jpf/jvm/bytecode/IfInstruction.java | 156 + .../jpf/jvm/bytecode/InstanceInvocation.java | 86 + .../jpf/jvm/bytecode/InstructionFactory.java | 1120 ++++ src/main/gov/nasa/jpf/jvm/bytecode/JSR.java | 66 + src/main/gov/nasa/jpf/jvm/bytecode/JSR_W.java | 66 + .../bytecode/JVMArrayElementInstruction.java | 116 + .../jpf/jvm/bytecode/JVMFieldInstruction.java | 38 + .../bytecode/JVMInstanceFieldInstruction.java | 36 + .../nasa/jpf/jvm/bytecode/JVMInstruction.java | 31 + .../jvm/bytecode/JVMInstructionVisitor.java | 197 + .../JVMInstructionVisitorAdapter.java | 367 ++ .../jvm/bytecode/JVMInvokeInstruction.java | 281 + .../bytecode/JVMLocalVariableInstruction.java | 104 + .../jvm/bytecode/JVMReturnInstruction.java | 182 + .../bytecode/JVMStaticFieldInstruction.java | 56 + src/main/gov/nasa/jpf/jvm/bytecode/L2D.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/L2F.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/L2I.java | 50 + src/main/gov/nasa/jpf/jvm/bytecode/LADD.java | 54 + .../gov/nasa/jpf/jvm/bytecode/LALOAD.java | 47 + src/main/gov/nasa/jpf/jvm/bytecode/LAND.java | 54 + .../gov/nasa/jpf/jvm/bytecode/LASTORE.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/LCMP.java | 64 + .../gov/nasa/jpf/jvm/bytecode/LCONST.java | 73 + src/main/gov/nasa/jpf/jvm/bytecode/LDC.java | 157 + .../gov/nasa/jpf/jvm/bytecode/LDC2_W.java | 84 + src/main/gov/nasa/jpf/jvm/bytecode/LDC_W.java | 56 + src/main/gov/nasa/jpf/jvm/bytecode/LDIV.java | 58 + src/main/gov/nasa/jpf/jvm/bytecode/LLOAD.java | 74 + src/main/gov/nasa/jpf/jvm/bytecode/LMUL.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/LNEG.java | 50 + .../nasa/jpf/jvm/bytecode/LOOKUPSWITCH.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/LOR.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/LREM.java | 54 + .../gov/nasa/jpf/jvm/bytecode/LRETURN.java | 58 + src/main/gov/nasa/jpf/jvm/bytecode/LSHL.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/LSHR.java | 52 + .../gov/nasa/jpf/jvm/bytecode/LSTORE.java | 74 + src/main/gov/nasa/jpf/jvm/bytecode/LSUB.java | 54 + src/main/gov/nasa/jpf/jvm/bytecode/LUSHR.java | 52 + src/main/gov/nasa/jpf/jvm/bytecode/LXOR.java | 54 + .../jpf/jvm/bytecode/LockInstruction.java | 51 + .../bytecode/LongArrayLoadInstruction.java | 46 + .../bytecode/LongArrayStoreInstruction.java | 73 + .../gov/nasa/jpf/jvm/bytecode/LongReturn.java | 124 + .../nasa/jpf/jvm/bytecode/MONITORENTER.java | 84 + .../nasa/jpf/jvm/bytecode/MONITOREXIT.java | 77 + .../nasa/jpf/jvm/bytecode/MULTIANEWARRAY.java | 130 + .../nasa/jpf/jvm/bytecode/NATIVERETURN.java | 230 + src/main/gov/nasa/jpf/jvm/bytecode/NEW.java | 109 + .../gov/nasa/jpf/jvm/bytecode/NEWARRAY.java | 104 + src/main/gov/nasa/jpf/jvm/bytecode/NOP.java | 48 + .../jpf/jvm/bytecode/NewArrayInstruction.java | 56 + src/main/gov/nasa/jpf/jvm/bytecode/POP.java | 48 + src/main/gov/nasa/jpf/jvm/bytecode/POP2.java | 49 + .../gov/nasa/jpf/jvm/bytecode/PUTFIELD.java | 155 + .../gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java | 132 + .../gov/nasa/jpf/jvm/bytecode/PutHelper.java | 85 + src/main/gov/nasa/jpf/jvm/bytecode/RET.java | 61 + .../gov/nasa/jpf/jvm/bytecode/RETURN.java | 106 + .../gov/nasa/jpf/jvm/bytecode/RUNSTART.java | 64 + .../gov/nasa/jpf/jvm/bytecode/SALOAD.java | 47 + .../gov/nasa/jpf/jvm/bytecode/SASTORE.java | 53 + .../gov/nasa/jpf/jvm/bytecode/SIPUSH.java | 63 + src/main/gov/nasa/jpf/jvm/bytecode/SWAP.java | 49 + .../jvm/bytecode/StaticFieldInstruction.java | 138 + .../jpf/jvm/bytecode/SwitchInstruction.java | 138 + .../nasa/jpf/jvm/bytecode/TABLESWITCH.java | 94 + .../jpf/jvm/bytecode/VirtualInvocation.java | 220 + src/main/gov/nasa/jpf/jvm/bytecode/WIDE.java | 52 + .../nasa/jpf/listener/AssertionProperty.java | 118 + .../gov/nasa/jpf/listener/BudgetChecker.java | 198 + src/main/gov/nasa/jpf/listener/CGMonitor.java | 106 + src/main/gov/nasa/jpf/listener/CGRemover.java | 268 + .../gov/nasa/jpf/listener/CallMonitor.java | 78 + .../gov/nasa/jpf/listener/ChoiceSelector.java | 187 + .../gov/nasa/jpf/listener/ChoiceTracker.java | 211 + .../nasa/jpf/listener/CoverageAnalyzer.java | 1228 ++++ .../nasa/jpf/listener/DeadlockAnalyzer.java | 521 ++ .../jpf/listener/DistributedSimpleDot.java | 159 + .../jpf/listener/EndlessLoopDetector.java | 57 + .../jpf/listener/ErrorTraceGenerator.java | 121 + .../nasa/jpf/listener/ExceptionInjector.java | 386 ++ .../gov/nasa/jpf/listener/ExecTracker.java | 291 + .../gov/nasa/jpf/listener/HeapTracker.java | 478 ++ .../gov/nasa/jpf/listener/IdleFilter.java | 249 + .../gov/nasa/jpf/listener/InsnCounter.java | 109 + .../nasa/jpf/listener/LockedStackDepth.java | 440 ++ .../gov/nasa/jpf/listener/LogConsole.java | 162 + .../gov/nasa/jpf/listener/MethodAnalyzer.java | 380 ++ .../gov/nasa/jpf/listener/MethodTracker.java | 168 + .../gov/nasa/jpf/listener/NoStateCycles.java | 126 + .../nasa/jpf/listener/NonSharedChecker.java | 161 + .../gov/nasa/jpf/listener/NullTracker.java | 340 ++ .../jpf/listener/NumericValueChecker.java | 276 + .../gov/nasa/jpf/listener/OOMEInjector.java | 161 + .../gov/nasa/jpf/listener/ObjectTracker.java | 254 + .../listener/OverlappingMethodAnalyzer.java | 198 + .../nasa/jpf/listener/PathOutputMonitor.java | 460 ++ .../gov/nasa/jpf/listener/Perturbator.java | 457 ++ .../jpf/listener/PreciseRaceDetector.java | 286 + .../nasa/jpf/listener/ReferenceLocator.java | 106 + .../gov/nasa/jpf/listener/SearchStats.java | 215 + src/main/gov/nasa/jpf/listener/SimpleDot.java | 507 ++ .../nasa/jpf/listener/SimpleIdleFilter.java | 120 + .../nasa/jpf/listener/StackDepthChecker.java | 65 + .../gov/nasa/jpf/listener/StackTracker.java | 120 + .../jpf/listener/StateCountEstimator.java | 177 + .../nasa/jpf/listener/StateSpaceAnalyzer.java | 802 +++ .../gov/nasa/jpf/listener/StateSpaceDot.java | 527 ++ .../gov/nasa/jpf/listener/StateTracker.java | 123 + .../nasa/jpf/listener/StopWatchFuzzer.java | 138 + .../gov/nasa/jpf/listener/TraceStorer.java | 164 + .../gov/nasa/jpf/listener/VarRecorder.java | 422 ++ .../gov/nasa/jpf/listener/VarTracker.java | 298 + .../jpf/perturb/GenericDataAbstractor.java | 345 ++ .../gov/nasa/jpf/perturb/IntOverUnder.java | 74 + .../nasa/jpf/perturb/OperandPerturbator.java | 36 + .../gov/nasa/jpf/report/ConsolePublisher.java | 392 ++ src/main/gov/nasa/jpf/report/Publisher.java | 377 ++ .../nasa/jpf/report/PublisherExtension.java | 32 + .../jpf/report/PublisherExtensionAdapter.java | 44 + src/main/gov/nasa/jpf/report/Reporter.java | 476 ++ src/main/gov/nasa/jpf/report/Statistics.java | 188 + .../gov/nasa/jpf/report/XMLPublisher.java | 278 + src/main/gov/nasa/jpf/search/DFSearch.java | 118 + src/main/gov/nasa/jpf/search/PathSearch.java | 92 + .../gov/nasa/jpf/search/RandomSearch.java | 92 + src/main/gov/nasa/jpf/search/Search.java | 642 +++ .../gov/nasa/jpf/search/SearchListener.java | 91 + .../jpf/search/SearchListenerAdapter.java | 60 + src/main/gov/nasa/jpf/search/SearchState.java | 33 + src/main/gov/nasa/jpf/search/Simulation.java | 80 + .../jpf/search/heuristic/BFSHeuristic.java | 42 + .../jpf/search/heuristic/DFSHeuristic.java | 37 + .../search/heuristic/GlobalSwitchThread.java | 69 + .../jpf/search/heuristic/HeuristicSearch.java | 209 + .../jpf/search/heuristic/HeuristicState.java | 46 + .../jpf/search/heuristic/Interleaving.java | 66 + .../search/heuristic/MinimizePreemption.java | 76 + .../jpf/search/heuristic/MostBlocked.java | 46 + .../jpf/search/heuristic/PreferThreads.java | 59 + .../search/heuristic/PrioritizedState.java | 69 + .../jpf/search/heuristic/RandomHeuristic.java | 43 + .../heuristic/SimplePriorityHeuristic.java | 111 + .../search/heuristic/StaticPriorityQueue.java | 91 + .../jpf/search/heuristic/UserHeuristic.java | 40 + src/main/gov/nasa/jpf/tool/GenPeer.java | 399 ++ src/main/gov/nasa/jpf/tool/LogConsole.java | 162 + src/main/gov/nasa/jpf/tool/PrintEvents.java | 126 + src/main/gov/nasa/jpf/tool/Run.java | 93 + src/main/gov/nasa/jpf/tool/RunJPF.java | 291 + src/main/gov/nasa/jpf/tool/RunTest.java | 367 ++ .../gov/nasa/jpf/util/ArrayByteQueue.java | 252 + src/main/gov/nasa/jpf/util/ArrayIntSet.java | 158 + .../gov/nasa/jpf/util/ArrayObjectQueue.java | 225 + src/main/gov/nasa/jpf/util/Attributable.java | 38 + .../util/AvailableBufferedInputStream.java | 145 + src/main/gov/nasa/jpf/util/BailOut.java | 34 + .../gov/nasa/jpf/util/BinaryClassSource.java | 394 ++ src/main/gov/nasa/jpf/util/BitArray.java | 121 + src/main/gov/nasa/jpf/util/BitSet1024.java | 896 +++ src/main/gov/nasa/jpf/util/BitSet256.java | 340 ++ src/main/gov/nasa/jpf/util/BitSet64.java | 194 + src/main/gov/nasa/jpf/util/BitSetN.java | 122 + .../gov/nasa/jpf/util/ClassInfoFilter.java | 73 + .../gov/nasa/jpf/util/CloneableObject.java | 26 + src/main/gov/nasa/jpf/util/Cloner.java | 28 + .../gov/nasa/jpf/util/CommitOutputStream.java | 103 + src/main/gov/nasa/jpf/util/ConsoleStream.java | 71 + src/main/gov/nasa/jpf/util/ConstGrowth.java | 40 + src/main/gov/nasa/jpf/util/CountDown.java | 43 + .../gov/nasa/jpf/util/DevNullPrintStream.java | 105 + .../gov/nasa/jpf/util/DynamicIntArray.java | 208 + .../gov/nasa/jpf/util/DynamicObjectArray.java | 167 + .../gov/nasa/jpf/util/ElementCreator.java | 25 + src/main/gov/nasa/jpf/util/ExpGrowth.java | 46 + src/main/gov/nasa/jpf/util/FeatureSpec.java | 173 + src/main/gov/nasa/jpf/util/FieldSpec.java | 100 + .../gov/nasa/jpf/util/FieldSpecMatcher.java | 55 + src/main/gov/nasa/jpf/util/FileUtils.java | 510 ++ src/main/gov/nasa/jpf/util/FinalBitSet.java | 73 + src/main/gov/nasa/jpf/util/FixedBitSet.java | 175 + src/main/gov/nasa/jpf/util/Growth.java | 24 + src/main/gov/nasa/jpf/util/HashData.java | 62 + src/main/gov/nasa/jpf/util/HashPool.java | 90 + .../nasa/jpf/util/IdentityArrayObjectSet.java | 174 + .../gov/nasa/jpf/util/IdentityObjectSet.java | 26 + src/main/gov/nasa/jpf/util/ImmutableList.java | 83 + src/main/gov/nasa/jpf/util/IndexIterator.java | 30 + .../gov/nasa/jpf/util/InstructionState.java | 32 + src/main/gov/nasa/jpf/util/IntArray.java | 49 + src/main/gov/nasa/jpf/util/IntIterator.java | 29 + src/main/gov/nasa/jpf/util/IntSet.java | 35 + src/main/gov/nasa/jpf/util/IntTable.java | 573 ++ src/main/gov/nasa/jpf/util/IntVector.java | 485 ++ src/main/gov/nasa/jpf/util/Invocation.java | 116 + src/main/gov/nasa/jpf/util/JPFLogger.java | 545 ++ src/main/gov/nasa/jpf/util/JPFSiteUtils.java | 476 ++ src/main/gov/nasa/jpf/util/Left.java | 39 + .../gov/nasa/jpf/util/LimitedInputStream.java | 139 + .../gov/nasa/jpf/util/LinkedObjectQueue.java | 195 + src/main/gov/nasa/jpf/util/LocationSpec.java | 239 + src/main/gov/nasa/jpf/util/LogHandler.java | 239 + src/main/gov/nasa/jpf/util/LogManager.java | 141 + src/main/gov/nasa/jpf/util/Loggable.java | 286 + src/main/gov/nasa/jpf/util/LongVector.java | 114 + .../gov/nasa/jpf/util/MethodInfoRegistry.java | 72 + src/main/gov/nasa/jpf/util/MethodSpec.java | 213 + .../gov/nasa/jpf/util/MethodSpecMatcher.java | 55 + src/main/gov/nasa/jpf/util/Misc.java | 713 +++ .../gov/nasa/jpf/util/MutableInteger.java | 109 + .../nasa/jpf/util/MutableIntegerRestorer.java | 40 + src/main/gov/nasa/jpf/util/OATHash.java | 96 + src/main/gov/nasa/jpf/util/ObjArray.java | 137 + src/main/gov/nasa/jpf/util/ObjVector.java | 631 ++ .../gov/nasa/jpf/util/ObjectConverter.java | 306 + src/main/gov/nasa/jpf/util/ObjectList.java | 647 +++ src/main/gov/nasa/jpf/util/ObjectQueue.java | 43 + src/main/gov/nasa/jpf/util/ObjectSet.java | 34 + src/main/gov/nasa/jpf/util/PSIntMap.java | 1799 ++++++ src/main/gov/nasa/jpf/util/Pair.java | 65 + .../jpf/util/PairPermutationGenerator.java | 87 + .../gov/nasa/jpf/util/PathnameExpander.java | 239 + .../nasa/jpf/util/PermutationGenerator.java | 98 + src/main/gov/nasa/jpf/util/Predicate.java | 24 + .../gov/nasa/jpf/util/PrintStreamable.java | 71 + src/main/gov/nasa/jpf/util/PrintUtils.java | 74 + src/main/gov/nasa/jpf/util/Printable.java | 30 + src/main/gov/nasa/jpf/util/Processor.java | 23 + .../jpf/util/RandomPermutationGenerator.java | 76 + .../gov/nasa/jpf/util/ReadOnlyObjList.java | 24 + src/main/gov/nasa/jpf/util/Reflection.java | 112 + .../gov/nasa/jpf/util/RepositoryEntry.java | 240 + src/main/gov/nasa/jpf/util/Result.java | 54 + src/main/gov/nasa/jpf/util/Right.java | 45 + src/main/gov/nasa/jpf/util/RunListener.java | 27 + src/main/gov/nasa/jpf/util/RunRegistry.java | 64 + src/main/gov/nasa/jpf/util/SimplePool.java | 185 + .../gov/nasa/jpf/util/SingleElementList.java | 248 + .../gov/nasa/jpf/util/SortedArrayIntSet.java | 159 + .../nasa/jpf/util/SortedArrayObjectSet.java | 206 + src/main/gov/nasa/jpf/util/Source.java | 335 ++ src/main/gov/nasa/jpf/util/SourceRef.java | 145 + .../gov/nasa/jpf/util/SparseClusterArray.java | 783 +++ .../gov/nasa/jpf/util/SparseIntVector.java | 408 ++ .../gov/nasa/jpf/util/SparseObjVector.java | 277 + .../gov/nasa/jpf/util/SplitInputStream.java | 439 ++ .../gov/nasa/jpf/util/SplitOutputStream.java | 99 + .../nasa/jpf/util/StateExtensionClient.java | 33 + .../nasa/jpf/util/StateExtensionListener.java | 72 + .../gov/nasa/jpf/util/StringExpander.java | 360 ++ src/main/gov/nasa/jpf/util/StringMatcher.java | 93 + .../gov/nasa/jpf/util/StringSetMatcher.java | 263 + .../gov/nasa/jpf/util/StructuredPrinter.java | 76 + .../jpf/util/TotalPermutationGenerator.java | 93 + src/main/gov/nasa/jpf/util/Trace.java | 203 + src/main/gov/nasa/jpf/util/TraceElement.java | 54 + src/main/gov/nasa/jpf/util/Transformer.java | 27 + .../gov/nasa/jpf/util/TwoTypeComparator.java | 25 + src/main/gov/nasa/jpf/util/TypeRef.java | 68 + src/main/gov/nasa/jpf/util/TypeSpec.java | 73 + .../gov/nasa/jpf/util/TypeSpecMatcher.java | 66 + .../jpf/util/UniqueRandomPermGenerator.java | 57 + .../nasa/jpf/util/UnsortedArrayIntSet.java | 108 + src/main/gov/nasa/jpf/util/VarSpec.java | 77 + src/main/gov/nasa/jpf/util/WeakPool.java | 214 + .../nasa/jpf/util/automaton/Automaton.java | 148 + .../gov/nasa/jpf/util/automaton/State.java | 112 + .../nasa/jpf/util/automaton/Transition.java | 69 + .../gov/nasa/jpf/util/event/CheckEvent.java | 107 + .../gov/nasa/jpf/util/event/ControlEvent.java | 31 + src/main/gov/nasa/jpf/util/event/Event.java | 651 +++ .../jpf/util/event/EventChoiceGenerator.java | 250 + .../nasa/jpf/util/event/EventConstructor.java | 140 + .../gov/nasa/jpf/util/event/EventContext.java | 26 + .../gov/nasa/jpf/util/event/EventForest.java | 70 + .../gov/nasa/jpf/util/event/EventTree.java | 247 + src/main/gov/nasa/jpf/util/event/NoEvent.java | 37 + .../util/event/PropagatingEventContext.java | 27 + .../gov/nasa/jpf/util/event/SystemEvent.java | 40 + .../nasa/jpf/util/event/TestEventTree.java | 84 + .../gov/nasa/jpf/util/json/AbstractValue.java | 62 + .../gov/nasa/jpf/util/json/ArrayValue.java | 65 + .../gov/nasa/jpf/util/json/BooleanValue.java | 37 + src/main/gov/nasa/jpf/util/json/CGCall.java | 108 + .../gov/nasa/jpf/util/json/CGCreator.java | 43 + .../nasa/jpf/util/json/CGCreatorFactory.java | 204 + src/main/gov/nasa/jpf/util/json/Creator.java | 36 + .../nasa/jpf/util/json/CreatorsFactory.java | 173 + .../gov/nasa/jpf/util/json/DoubleValue.java | 37 + .../gov/nasa/jpf/util/json/JSONLexer.java | 357 ++ .../gov/nasa/jpf/util/json/JSONObject.java | 398 ++ .../nasa/jpf/util/json/JSONObjectValue.java | 58 + .../gov/nasa/jpf/util/json/JSONParser.java | 271 + .../gov/nasa/jpf/util/json/NullValue.java | 54 + .../gov/nasa/jpf/util/json/StringValue.java | 38 + src/main/gov/nasa/jpf/util/json/Token.java | 88 + src/main/gov/nasa/jpf/util/json/Value.java | 59 + .../gov/nasa/jpf/util/script/Alternative.java | 42 + .../gov/nasa/jpf/util/script/ESParser.java | 434 ++ .../jpf/util/script/ElementProcessor.java | 26 + src/main/gov/nasa/jpf/util/script/Event.java | 230 + .../nasa/jpf/util/script/EventFactory.java | 29 + .../nasa/jpf/util/script/EventGenerator.java | 31 + .../util/script/EventGeneratorFactory.java | 308 + .../gov/nasa/jpf/util/script/Repetition.java | 86 + src/main/gov/nasa/jpf/util/script/Script.java | 38 + .../nasa/jpf/util/script/ScriptElement.java | 57 + .../util/script/ScriptElementContainer.java | 183 + .../jpf/util/script/ScriptEnvironment.java | 319 ++ .../gov/nasa/jpf/util/script/Section.java | 62 + .../jpf/util/script/SequenceInterpreter.java | 112 + .../jpf/util/script/StringSetGenerator.java | 120 + .../JPF_gov_nasa_jpf_util_test_TestJPF.java | 255 + ...asa_jpf_util_test_TestMultiProcessJPF.java | 77 + src/main/gov/nasa/jpf/util/test/TestJPF.java | 1181 ++++ .../jpf/util/test/TestMultiProcessJPF.java | 145 + .../gov/nasa/jpf/vm/AbstractRestorer.java | 62 + .../gov/nasa/jpf/vm/AbstractSerializer.java | 67 + .../jpf/vm/AbstractTypeAnnotationInfo.java | 73 + .../nasa/jpf/vm/AllRunnablesSyncPolicy.java | 345 ++ src/main/gov/nasa/jpf/vm/Allocation.java | 62 + .../gov/nasa/jpf/vm/AllocationContext.java | 29 + src/main/gov/nasa/jpf/vm/AnnotationInfo.java | 385 ++ .../gov/nasa/jpf/vm/AnnotationParser.java | 27 + .../gov/nasa/jpf/vm/ApplicationContext.java | 117 + src/main/gov/nasa/jpf/vm/ArrayAccess.java | 46 + src/main/gov/nasa/jpf/vm/ArrayFields.java | 210 + ...rayIndexOutOfBoundsExecutiveException.java | 47 + src/main/gov/nasa/jpf/vm/ArrayOffset.java | 44 + src/main/gov/nasa/jpf/vm/AtomicData.java | 103 + src/main/gov/nasa/jpf/vm/Attributor.java | 27 + src/main/gov/nasa/jpf/vm/Backtracker.java | 34 + .../gov/nasa/jpf/vm/BooleanArrayFields.java | 127 + .../nasa/jpf/vm/BooleanChoiceGenerator.java | 168 + .../gov/nasa/jpf/vm/BooleanFieldInfo.java | 67 + .../gov/nasa/jpf/vm/BootstrapMethodInfo.java | 65 + .../nasa/jpf/vm/BoxObjectCacheManager.java | 264 + src/main/gov/nasa/jpf/vm/ByteArrayFields.java | 122 + src/main/gov/nasa/jpf/vm/ByteFieldInfo.java | 73 + .../nasa/jpf/vm/BytecodeAnnotationInfo.java | 37 + .../BytecodeTypeParameterAnnotationInfo.java | 45 + src/main/gov/nasa/jpf/vm/CharArrayFields.java | 165 + src/main/gov/nasa/jpf/vm/CharFieldInfo.java | 70 + .../nasa/jpf/vm/CheckExtendTransition.java | 36 + src/main/gov/nasa/jpf/vm/ChoiceGenerator.java | 207 + .../gov/nasa/jpf/vm/ChoiceGeneratorBase.java | 545 ++ src/main/gov/nasa/jpf/vm/ChoicePoint.java | 257 + .../gov/nasa/jpf/vm/ClassChangeException.java | 28 + .../gov/nasa/jpf/vm/ClassFileContainer.java | 49 + src/main/gov/nasa/jpf/vm/ClassFileMatch.java | 44 + src/main/gov/nasa/jpf/vm/ClassInfo.java | 2594 +++++++++ .../gov/nasa/jpf/vm/ClassInfoException.java | 89 + src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java | 862 +++ src/main/gov/nasa/jpf/vm/ClassLoaderList.java | 165 + .../gov/nasa/jpf/vm/ClassParseException.java | 33 + src/main/gov/nasa/jpf/vm/ClassPath.java | 115 + src/main/gov/nasa/jpf/vm/ClinitRequired.java | 41 + src/main/gov/nasa/jpf/vm/ClosedMemento.java | 33 + src/main/gov/nasa/jpf/vm/CollapsePools.java | 133 + .../gov/nasa/jpf/vm/ConstInsnPathTime.java | 107 + .../gov/nasa/jpf/vm/DebugJenkinsStateSet.java | 120 + .../gov/nasa/jpf/vm/DebugStateSerializer.java | 28 + .../gov/nasa/jpf/vm/DefaultBacktracker.java | 126 + .../gov/nasa/jpf/vm/DefaultFieldsFactory.java | 56 + .../nasa/jpf/vm/DefaultMementoRestorer.java | 65 + .../gov/nasa/jpf/vm/DelegatingScheduler.java | 251 + .../gov/nasa/jpf/vm/DirectCallStackFrame.java | 104 + .../gov/nasa/jpf/vm/DoubleArrayFields.java | 122 + .../nasa/jpf/vm/DoubleChoiceGenerator.java | 26 + src/main/gov/nasa/jpf/vm/DoubleFieldInfo.java | 87 + .../gov/nasa/jpf/vm/DoubleSlotFieldInfo.java | 35 + .../gov/nasa/jpf/vm/DynamicElementInfo.java | 187 + src/main/gov/nasa/jpf/vm/ElementInfo.java | 2257 ++++++++ .../gov/nasa/jpf/vm/ExceptionHandler.java | 87 + src/main/gov/nasa/jpf/vm/ExceptionInfo.java | 91 + .../vm/ExceptionParameterAnnotationInfo.java | 37 + src/main/gov/nasa/jpf/vm/FieldInfo.java | 341 ++ src/main/gov/nasa/jpf/vm/FieldLockInfo.java | 162 + .../gov/nasa/jpf/vm/FieldLockInfoFactory.java | 27 + src/main/gov/nasa/jpf/vm/Fields.java | 352 ++ src/main/gov/nasa/jpf/vm/FieldsFactory.java | 30 + .../gov/nasa/jpf/vm/FinalizerThreadInfo.java | 254 + .../gov/nasa/jpf/vm/FloatArrayFields.java | 122 + .../gov/nasa/jpf/vm/FloatChoiceGenerator.java | 27 + src/main/gov/nasa/jpf/vm/FloatFieldInfo.java | 81 + .../jpf/vm/FormalParameterAnnotationInfo.java | 37 + src/main/gov/nasa/jpf/vm/FullStateSet.java | 38 + .../nasa/jpf/vm/FunctionObjectFactory.java | 69 + src/main/gov/nasa/jpf/vm/GenericHeap.java | 758 +++ .../gov/nasa/jpf/vm/GenericSGOIDHeap.java | 117 + .../nasa/jpf/vm/GenericSharednessPolicy.java | 614 ++ .../nasa/jpf/vm/GenericSignatureHolder.java | 29 + .../nasa/jpf/vm/GlobalSchedulingPoint.java | 41 + .../nasa/jpf/vm/GlobalSharednessPolicy.java | 116 + src/main/gov/nasa/jpf/vm/HandlerContext.java | 78 + .../nasa/jpf/vm/HashedAllocationContext.java | 234 + src/main/gov/nasa/jpf/vm/Heap.java | 99 + .../nasa/jpf/vm/IncrementalChangeTracker.java | 29 + src/main/gov/nasa/jpf/vm/InfoObject.java | 274 + src/main/gov/nasa/jpf/vm/Instruction.java | 450 ++ src/main/gov/nasa/jpf/vm/IntArrayFields.java | 123 + .../gov/nasa/jpf/vm/IntChoiceGenerator.java | 26 + .../gov/nasa/jpf/vm/IntegerFieldInfo.java | 78 + .../gov/nasa/jpf/vm/IsEndStateProperty.java | 37 + src/main/gov/nasa/jpf/vm/JPFOutputStream.java | 206 + .../jpf/vm/JPF_gov_nasa_jpf_vm_Verify.java | 1283 +++++ src/main/gov/nasa/jpf/vm/JenkinsStateSet.java | 221 + src/main/gov/nasa/jpf/vm/KernelState.java | 178 + .../gov/nasa/jpf/vm/LoadOnJPFRequired.java | 35 + src/main/gov/nasa/jpf/vm/LocalVarInfo.java | 122 + .../gov/nasa/jpf/vm/LockSetThresholdFli.java | 171 + src/main/gov/nasa/jpf/vm/LongArrayFields.java | 123 + .../gov/nasa/jpf/vm/LongChoiceGenerator.java | 29 + src/main/gov/nasa/jpf/vm/LongFieldInfo.java | 82 + src/main/gov/nasa/jpf/vm/MJIEnv.java | 1785 ++++++ src/main/gov/nasa/jpf/vm/Memento.java | 44 + src/main/gov/nasa/jpf/vm/MementoFactory.java | 45 + src/main/gov/nasa/jpf/vm/MementoRestorer.java | 39 + src/main/gov/nasa/jpf/vm/MethodInfo.java | 1378 +++++ src/main/gov/nasa/jpf/vm/MethodLocator.java | 26 + src/main/gov/nasa/jpf/vm/Monitor.java | 454 ++ src/main/gov/nasa/jpf/vm/MultiProcessVM.java | 466 ++ src/main/gov/nasa/jpf/vm/NamedFields.java | 274 + .../gov/nasa/jpf/vm/NativeMethodInfo.java | 289 + src/main/gov/nasa/jpf/vm/NativePeer.java | 434 ++ .../gov/nasa/jpf/vm/NativeStackFrame.java | 286 + .../gov/nasa/jpf/vm/NativeStateHolder.java | 30 + src/main/gov/nasa/jpf/vm/NoJPFExec.java | 32 + .../jpf/vm/NoOutOfMemoryErrorProperty.java | 44 + .../jpf/vm/NoUncaughtExceptionsProperty.java | 76 + .../nasa/jpf/vm/NotDeadlockedProperty.java | 79 + src/main/gov/nasa/jpf/vm/OVHeap.java | 155 + src/main/gov/nasa/jpf/vm/OVStatics.java | 186 + src/main/gov/nasa/jpf/vm/ObjRef.java | 59 + src/main/gov/nasa/jpf/vm/PSIMHeap.java | 189 + src/main/gov/nasa/jpf/vm/Path.java | 134 + .../gov/nasa/jpf/vm/PathSharednessPolicy.java | 94 + .../jpf/vm/PersistentLockSetThresholdFli.java | 40 + .../vm/PersistentSingleLockThresholdFli.java | 34 + .../gov/nasa/jpf/vm/PersistentTidSet.java | 63 + .../nasa/jpf/vm/PreciseAllocationContext.java | 167 + src/main/gov/nasa/jpf/vm/PredicateMap.java | 31 + .../jpf/vm/PriorityRunnablesSyncPolicy.java | 77 + .../gov/nasa/jpf/vm/ReferenceArrayFields.java | 136 + .../nasa/jpf/vm/ReferenceChoiceGenerator.java | 25 + .../gov/nasa/jpf/vm/ReferenceFieldInfo.java | 103 + .../gov/nasa/jpf/vm/ReferenceProcessor.java | 26 + src/main/gov/nasa/jpf/vm/ReleaseAction.java | 34 + src/main/gov/nasa/jpf/vm/Restorable.java | 27 + .../gov/nasa/jpf/vm/RestorableVMState.java | 65 + src/main/gov/nasa/jpf/vm/Scheduler.java | 31 + .../gov/nasa/jpf/vm/SerializingStateSet.java | 35 + .../gov/nasa/jpf/vm/SharednessPolicy.java | 130 + .../gov/nasa/jpf/vm/ShortArrayFields.java | 121 + src/main/gov/nasa/jpf/vm/ShortFieldInfo.java | 74 + .../nasa/jpf/vm/SingleLockThresholdFli.java | 86 + src/main/gov/nasa/jpf/vm/SingleProcessVM.java | 330 ++ .../gov/nasa/jpf/vm/SingleSlotFieldInfo.java | 34 + src/main/gov/nasa/jpf/vm/StackFrame.java | 2281 ++++++++ src/main/gov/nasa/jpf/vm/StateRestorer.java | 34 + src/main/gov/nasa/jpf/vm/StateSerializer.java | 32 + src/main/gov/nasa/jpf/vm/StateSet.java | 43 + .../gov/nasa/jpf/vm/StaticElementInfo.java | 219 + src/main/gov/nasa/jpf/vm/Statics.java | 78 + .../jpf/vm/StatisticFieldLockInfoFactory.java | 377 ++ src/main/gov/nasa/jpf/vm/Step.java | 100 + src/main/gov/nasa/jpf/vm/Storable.java | 28 + .../nasa/jpf/vm/SuperTypeAnnotationInfo.java | 41 + src/main/gov/nasa/jpf/vm/SyncPolicy.java | 124 + .../nasa/jpf/vm/SystemClassLoaderInfo.java | 268 + src/main/gov/nasa/jpf/vm/SystemState.java | 935 +++ src/main/gov/nasa/jpf/vm/SystemTime.java | 42 + .../nasa/jpf/vm/ThreadChoiceGenerator.java | 27 + src/main/gov/nasa/jpf/vm/ThreadData.java | 131 + src/main/gov/nasa/jpf/vm/ThreadInfo.java | 3452 +++++++++++ src/main/gov/nasa/jpf/vm/ThreadInfoSet.java | 50 + src/main/gov/nasa/jpf/vm/ThreadList.java | 617 ++ .../nasa/jpf/vm/ThresholdFieldLockInfo.java | 61 + .../gov/nasa/jpf/vm/ThrowsAnnotationInfo.java | 37 + src/main/gov/nasa/jpf/vm/TidSet.java | 141 + src/main/gov/nasa/jpf/vm/TimeModel.java | 39 + src/main/gov/nasa/jpf/vm/Transition.java | 178 + .../gov/nasa/jpf/vm/TypeAnnotationInfo.java | 33 + .../jpf/vm/TypeParameterAnnotationInfo.java | 38 + .../vm/TypeParameterBoundAnnotationInfo.java | 47 + src/main/gov/nasa/jpf/vm/Types.java | 1156 ++++ .../gov/nasa/jpf/vm/UncaughtException.java | 82 + src/main/gov/nasa/jpf/vm/VM.java | 2053 +++++++ src/main/gov/nasa/jpf/vm/VMListener.java | 224 + .../nasa/jpf/vm/VariableAnnotationInfo.java | 84 + src/main/gov/nasa/jpf/vm/Verify.java | 624 ++ .../vm/bytecode/ArrayElementInstruction.java | 33 + .../jpf/vm/bytecode/FieldInstruction.java | 132 + .../vm/bytecode/InstanceFieldInstruction.java | 102 + .../bytecode/InstanceInvokeInstruction.java | 33 + .../jpf/vm/bytecode/InstructionInterface.java | 62 + .../jpf/vm/bytecode/InvokeInstruction.java | 69 + .../vm/bytecode/LocalVariableInstruction.java | 32 + .../vm/bytecode/LookupSwitchInstruction.java | 26 + .../nasa/jpf/vm/bytecode/NewInstruction.java | 27 + .../nasa/jpf/vm/bytecode/ReadInstruction.java | 27 + .../vm/bytecode/ReadOrWriteInstruction.java | 37 + .../jpf/vm/bytecode/ReturnInstruction.java | 31 + .../vm/bytecode/ReturnValueInstruction.java | 33 + .../vm/bytecode/StaticFieldInstruction.java | 118 + .../jpf/vm/bytecode/StoreInstruction.java | 27 + .../vm/bytecode/TableSwitchInstruction.java | 26 + .../jpf/vm/bytecode/WriteInstruction.java | 39 + .../nasa/jpf/vm/choice/BreakGenerator.java | 116 + .../vm/choice/CompoundChoiceGenerator.java | 134 + .../jpf/vm/choice/DoubleChoiceFromList.java | 89 + .../jpf/vm/choice/DoubleChoiceFromSet.java | 68 + .../gov/nasa/jpf/vm/choice/DoubleSpec.java | 94 + .../vm/choice/DoubleThresholdGenerator.java | 123 + .../choice/ExceptionThreadChoiceFromSet.java | 102 + .../gov/nasa/jpf/vm/choice/ExposureCG.java | 36 + .../jpf/vm/choice/FloatChoiceFromList.java | 84 + .../nasa/jpf/vm/choice/IntChoiceFromList.java | 91 + .../nasa/jpf/vm/choice/IntChoiceFromSet.java | 78 + .../jpf/vm/choice/IntIntervalGenerator.java | 226 + .../gov/nasa/jpf/vm/choice/InvocationCG.java | 120 + .../jpf/vm/choice/LongChoiceFromList.java | 84 + .../jpf/vm/choice/NumberChoiceFromList.java | 238 + .../gov/nasa/jpf/vm/choice/PermutationCG.java | 78 + .../vm/choice/RandomIntIntervalGenerator.java | 160 + .../nasa/jpf/vm/choice/RandomOrderIntCG.java | 94 + .../nasa/jpf/vm/choice/RandomOrderLongCG.java | 95 + .../jpf/vm/choice/ThreadChoiceFromSet.java | 196 + .../nasa/jpf/vm/choice/TypedObjectChoice.java | 160 + .../nasa/jpf/vm/serialize/Abstraction.java | 32 + .../jpf/vm/serialize/AbstractionAdapter.java | 58 + .../jpf/vm/serialize/AdaptiveSerializer.java | 76 + .../AmmendableFilterConfiguration.java | 189 + .../nasa/jpf/vm/serialize/CFSerializer.java | 145 + .../jpf/vm/serialize/DebugCFSerializer.java | 130 + .../serialize/DebugFilteringSerializer.java | 39 + .../serialize/DefaultFilterConfiguration.java | 46 + .../DynamicAbstractionSerializer.java | 374 ++ .../vm/serialize/FieldAmmendmentByName.java | 59 + .../jpf/vm/serialize/FilterConfiguration.java | 33 + .../nasa/jpf/vm/serialize/FilterFrame.java | 50 + .../jpf/vm/serialize/FilteringSerializer.java | 484 ++ .../nasa/jpf/vm/serialize/FramePolicy.java | 69 + .../jpf/vm/serialize/IgnoreConstants.java | 73 + .../vm/serialize/IgnoreReflectiveNames.java | 40 + .../vm/serialize/IgnoreThreadNastiness.java | 44 + .../jpf/vm/serialize/IgnoreUtilSilliness.java | 41 + .../gov/nasa/jpf/vm/serialize/Ignored.java | 27 + .../vm/serialize/IgnoresFromAnnotations.java | 70 + .../vm/serialize/IncludesFromAnnotations.java | 42 + .../jpf/vm/serialize/TopFrameSerializer.java | 71 + .../nasa/jpf/vm/serialize/UnfilterField.java | 42 + .../jpf/vm/serialize/UnknownJPFClass.java | 42 + .../gov/nasa/jpf/vm/AtomicFieldUpdater.java | 48 + .../JPF_gov_nasa_jpf_AnnotationProxyBase.java | 168 + ...F_gov_nasa_jpf_CachedROHttpConnection.java | 165 + .../JPF_gov_nasa_jpf_ConsoleOutputStream.java | 141 + .../JPF_gov_nasa_jpf_DelegatingTimeZone.java | 72 + .../vm/JPF_gov_nasa_jpf_EventProducer.java | 192 + .../vm/JPF_gov_nasa_jpf_FinalizerThread.java | 107 + ...gov_nasa_jpf_SerializationConstructor.java | 63 + .../vm/JPF_gov_nasa_jpf_test_MemoryGoal.java | 112 + .../JPF_gov_nasa_jpf_tools_MethodTester.java | 42 + .../gov/nasa/jpf/vm/JPF_java_io_File.java | 196 + .../jpf/vm/JPF_java_io_FileDescriptor.java | 435 ++ .../jpf/vm/JPF_java_io_InputStreamReader.java | 109 + .../jpf/vm/JPF_java_io_ObjectInputStream.java | 97 + .../vm/JPF_java_io_ObjectOutputStream.java | 44 + .../jpf/vm/JPF_java_io_ObjectStreamClass.java | 55 + .../vm/JPF_java_io_OutputStreamWriter.java | 100 + .../jpf/vm/JPF_java_io_RandomAccessFile.java | 220 + .../nasa/jpf/vm/JPF_java_lang_Boolean.java | 32 + .../gov/nasa/jpf/vm/JPF_java_lang_Byte.java | 32 + .../nasa/jpf/vm/JPF_java_lang_Character.java | 216 + .../gov/nasa/jpf/vm/JPF_java_lang_Class.java | 946 +++ .../jpf/vm/JPF_java_lang_ClassLoader.java | 295 + .../gov/nasa/jpf/vm/JPF_java_lang_Double.java | 62 + .../gov/nasa/jpf/vm/JPF_java_lang_Float.java | 57 + .../nasa/jpf/vm/JPF_java_lang_Integer.java | 83 + .../gov/nasa/jpf/vm/JPF_java_lang_Long.java | 83 + .../gov/nasa/jpf/vm/JPF_java_lang_Math.java | 186 + .../gov/nasa/jpf/vm/JPF_java_lang_Object.java | 205 + .../nasa/jpf/vm/JPF_java_lang_Runtime.java | 81 + .../gov/nasa/jpf/vm/JPF_java_lang_Short.java | 70 + .../gov/nasa/jpf/vm/JPF_java_lang_String.java | 619 ++ .../jpf/vm/JPF_java_lang_StringBuffer.java | 174 + .../jpf/vm/JPF_java_lang_StringBuilder.java | 166 + .../jpf/vm/JPF_java_lang_StringCoding.java | 58 + .../gov/nasa/jpf/vm/JPF_java_lang_System.java | 279 + .../gov/nasa/jpf/vm/JPF_java_lang_Thread.java | 417 ++ .../jpf/vm/JPF_java_lang_ThreadLocal.java | 98 + .../nasa/jpf/vm/JPF_java_lang_Throwable.java | 88 + .../jpf/vm/JPF_java_lang_reflect_Array.java | 295 + .../vm/JPF_java_lang_reflect_Constructor.java | 223 + .../jpf/vm/JPF_java_lang_reflect_Field.java | 847 +++ .../jpf/vm/JPF_java_lang_reflect_Method.java | 654 +++ .../jpf/vm/JPF_java_lang_reflect_Proxy.java | 43 + .../jpf/vm/JPF_java_net_URLClassLoader.java | 106 + .../nasa/jpf/vm/JPF_java_net_URLDecoder.java | 49 + .../nasa/jpf/vm/JPF_java_net_URLEncoder.java | 49 + .../vm/JPF_java_security_MessageDigest.java | 100 + .../gov/nasa/jpf/vm/JPF_java_text_Bidi.java | 45 + .../nasa/jpf/vm/JPF_java_text_DateFormat.java | 95 + .../vm/JPF_java_text_DateFormatSymbols.java | 61 + .../jpf/vm/JPF_java_text_DecimalFormat.java | 208 + .../JPF_java_text_DecimalFormatSymbols.java | 52 + .../gov/nasa/jpf/vm/JPF_java_text_Format.java | 55 + .../vm/JPF_java_text_SimpleDateFormat.java | 89 + .../nasa/jpf/vm/JPF_java_util_Calendar.java | 42 + .../gov/nasa/jpf/vm/JPF_java_util_Date.java | 46 + .../gov/nasa/jpf/vm/JPF_java_util_Locale.java | 135 + .../gov/nasa/jpf/vm/JPF_java_util_Random.java | 305 + .../jpf/vm/JPF_java_util_ResourceBundle.java | 53 + .../nasa/jpf/vm/JPF_java_util_TimeZone.java | 191 + .../JPF_java_util_concurrent_Exchanger.java | 169 + ..._util_concurrent_atomic_AtomicInteger.java | 114 + ..._concurrent_atomic_AtomicIntegerArray.java | 47 + ...rent_atomic_AtomicIntegerFieldUpdater.java | 168 + ...ava_util_concurrent_atomic_AtomicLong.java | 89 + ...til_concurrent_atomic_AtomicLongArray.java | 47 + ...current_atomic_AtomicLongFieldUpdater.java | 170 + ...oncurrent_atomic_AtomicReferenceArray.java | 47 + ...nt_atomic_AtomicReferenceFieldUpdater.java | 149 + .../jpf/vm/JPF_java_util_logging_Level.java | 60 + .../jpf/vm/JPF_java_util_regex_Matcher.java | 224 + .../jpf/vm/JPF_java_util_regex_Pattern.java | 42 + .../gov/nasa/jpf/vm/JPF_sun_misc_Unsafe.java | 923 +++ .../gov/nasa/jpf/vm/JPF_sun_misc_VM.java | 33 + ...JPF_sun_net_www_protocol_http_Handler.java | 112 + .../jpf/vm/JPF_sun_reflect_Reflection.java | 58 + .../vm/JPF_sun_reflect_ReflectionFactory.java | 47 + src/peers/gov/nasa/jpf/vm/LoggablePeer.java | 134 + src/tests/TypeNameTest.java | 75 + .../classloader_specific_tests/Class1.java | 32 + .../classloader_specific_tests/Class2.java | 25 + .../classloader_specific_tests/Class3.java | 25 + .../Interface1.java | 23 + .../Interface2.java | 22 + src/tests/gov/nasa/jpf/ConfigTest.java | 179 + src/tests/gov/nasa/jpf/configTestApp.jpf | 9 + src/tests/gov/nasa/jpf/configTestCommon.jpf | 4 + src/tests/gov/nasa/jpf/configTestIncludes.jpf | 4 + src/tests/gov/nasa/jpf/configTestRequires.jpf | 7 + .../gov/nasa/jpf/configTestRequiresFail.jpf | 6 + .../gov/nasa/jpf/configTestSite.properties | 13 + src/tests/gov/nasa/jpf/jvm/ClassInfoTest.java | 146 + .../gov/nasa/jpf/jvm/JVMStackFrameTest.java | 173 + .../gov/nasa/jpf/jvm/MethodInfoTest.java | 154 + .../nasa/jpf/jvm/NonResolvedClassInfo.java | 52 + .../gov/nasa/jpf/test/basic/HarnessTest.java | 91 + .../test/basic/InstructionFactoryTest.java | 79 + .../JPF_gov_nasa_jpf_test_basic_MJITest.java | 240 + .../gov/nasa/jpf/test/basic/ListenerTest.java | 64 + .../gov/nasa/jpf/test/basic/MJITest.java | 233 + .../nasa/jpf/test/basic/TestJPFMainTest.java | 45 + .../jpf/test/basic/TestJPFNoMainTest.java | 41 + .../AtomicIntegerFieldUpdaterTest.java | 72 + .../AtomicLongFieldUpdaterTest.java | 75 + .../AtomicReferenceFieldUpdaterTest.java | 92 + .../java/concurrent/CountDownLatchTest.java | 78 + .../test/java/concurrent/ExchangerTest.java | 88 + .../java/concurrent/ExecutorServiceTest.java | 52 + .../test/java/concurrent/SemaphoreTest.java | 135 + .../test/java/io/BufferedInputStreamTest.java | 93 + .../jpf/test/java/io/FileIOStreamTest.java | 68 + .../gov/nasa/jpf/test/java/io/FileIOTest.java | 128 + .../gov/nasa/jpf/test/java/io/FileTest.java | 106 + .../jpf/test/java/io/ObjectStreamTest.java | 107 + .../test/java/lang/BoxObjectCacheTest.java | 208 + .../jpf/test/java/lang/ClassLoaderTest.java | 185 + .../nasa/jpf/test/java/lang/ClassTest.java | 585 ++ .../nasa/jpf/test/java/lang/CloneTest.java | 40 + .../nasa/jpf/test/java/lang/RuntimeTest.java | 49 + .../nasa/jpf/test/java/lang/StringTest.java | 304 + .../nasa/jpf/test/java/lang/SystemTest.java | 152 + .../test/java/lang/ref/WeakReferenceTest.java | 82 + .../java/lang/reflect/ConstructorTest.java | 65 + .../jpf/test/java/lang/reflect/FieldTest.java | 109 + .../test/java/lang/reflect/MethodTest.java | 184 + .../jpf/test/java/math/BigIntegerTest.java | 48 + .../nasa/jpf/test/java/net/LoadUtility.java | 77 + .../jpf/test/java/net/URLClassLoaderTest.java | 521 ++ .../jpf/test/java/net/URLEncoderTest.java | 74 + .../jpf/test/java/text/DateFormatTest.java | 97 + .../jpf/test/java/text/DecimalFormatTest.java | 141 + .../test/java/text/SimpleDateFormatTest.java | 48 + .../gov/nasa/jpf/test/mc/basic/AttrsTest.java | 544 ++ .../gov/nasa/jpf/test/mc/basic/BreakTest.java | 230 + .../jpf/test/mc/basic/CGNotificationTest.java | 163 + .../nasa/jpf/test/mc/basic/CGRemoverTest.java | 107 + .../nasa/jpf/test/mc/basic/CGReorderTest.java | 118 + .../jpf/test/mc/basic/CascadedCGTest.java | 216 + .../test/mc/basic/ExceptionInjectorTest.java | 94 + .../test/mc/basic/ExtendTransitionTest.java | 82 + .../jpf/test/mc/basic/FinalBreakTest.java | 199 + .../test/mc/basic/FinalFieldChoiceTest.java | 106 + .../nasa/jpf/test/mc/basic/IdleLoopTest.java | 84 + .../jpf/test/mc/basic/InvokeListenerTest.java | 138 + ..._gov_nasa_jpf_test_mc_basic_AttrsTest.java | 41 + ..._jpf_test_mc_basic_InvokeListenerTest.java | 34 + ..._nasa_jpf_test_mc_basic_NoJPFExecTest.java | 34 + ...nasa_jpf_test_mc_basic_RestorerTest$X.java | 77 + .../jpf/test/mc/basic/LocalVarInfoTest.java | 130 + .../jpf/test/mc/basic/MethodListenerTest.java | 194 + .../nasa/jpf/test/mc/basic/NoJPFExecTest.java | 55 + .../jpf/test/mc/basic/NullTrackerTest.java | 153 + .../jpf/test/mc/basic/OOMEInjectorTest.java | 80 + .../nasa/jpf/test/mc/basic/OVHeapTest.java | 112 + .../jpf/test/mc/basic/RecursiveLockTest.java | 67 + .../nasa/jpf/test/mc/basic/RestorerTest.java | 82 + .../jpf/test/mc/basic/SearchMultipleTest.java | 104 + .../test/mc/basic/SharedPropagationTest.java | 220 + .../nasa/jpf/test/mc/basic/SharedRefTest.java | 140 + .../test/mc/basic/SkipInstructionTest.java | 147 + .../test/mc/basic/StackDepthCheckerTest.java | 55 + .../nasa/jpf/test/mc/basic/StatelessTest.java | 50 + .../gov/nasa/jpf/test/mc/basic/TraceTest.java | 152 + .../test/mc/basic/TransitionLengthTest.java | 63 + .../test/mc/basic/UnlockNonSharedTest.java | 78 + .../nasa/jpf/test/mc/basic/VerifyTest.java | 161 + .../test/mc/data/CGCreatorFactoryTest.java | 79 + .../nasa/jpf/test/mc/data/CrossingTest.java | 282 + .../nasa/jpf/test/mc/data/DataChoiceTest.java | 140 + .../test/mc/data/DynamicAbstractionTest.java | 183 + .../jpf/test/mc/data/EventGeneratorTest.java | 188 + .../gov/nasa/jpf/test/mc/data/JSONTest.java | 588 ++ .../test/mc/data/NativeStateHolderTest.java | 95 + .../test/mc/data/NumericValueCheckerTest.java | 68 + .../jpf/test/mc/data/ObjectStreamTest.java | 208 + .../jpf/test/mc/data/PerturbatorTest.java | 257 + .../gov/nasa/jpf/test/mc/data/RandomTest.java | 95 + .../jpf/test/mc/data/StopWatchFuzzerTest.java | 57 + .../nasa/jpf/test/mc/data/TimeModelTest.java | 89 + .../test/mc/data/TypedObjectChoiceTest.java | 105 + .../nasa/jpf/test/mc/threads/AtomicTest.java | 114 + .../nasa/jpf/test/mc/threads/ClinitTest.java | 87 + .../nasa/jpf/test/mc/threads/DaemonTest.java | 67 + .../jpf/test/mc/threads/DeadlockTest.java | 395 ++ .../threads/ExceptionalThreadChoiceTest.java | 64 + .../test/mc/threads/FinalizerThreadTest.java | 86 + .../nasa/jpf/test/mc/threads/HORaceTest.java | 103 + ...c_threads_ExceptionalThreadChoiceTest.java | 63 + .../mc/threads/MinimizePreemptionTest.java | 157 + .../jpf/test/mc/threads/MissedPathTest.java | 132 + .../jpf/test/mc/threads/NestedInitTest.java | 138 + .../jpf/test/mc/threads/OldClassicTest.java | 128 + .../nasa/jpf/test/mc/threads/RaceTest.java | 518 ++ .../jpf/test/mc/threads/SchedulesTest-output | 17 + .../jpf/test/mc/threads/SchedulesTest.java | 58 + .../jpf/test/vm/basic/AnnotationTest.java | 556 ++ .../gov/nasa/jpf/test/vm/basic/ArrayTest.java | 226 + .../nasa/jpf/test/vm/basic/AssertTest.java | 191 + .../gov/nasa/jpf/test/vm/basic/CastTest.java | 94 + .../nasa/jpf/test/vm/basic/ClassInitTest.java | 59 + .../jpf/test/vm/basic/EndStateListener.java | 50 + .../nasa/jpf/test/vm/basic/EndStateTest.java | 55 + .../gov/nasa/jpf/test/vm/basic/EnumTest.java | 88 + .../test/vm/basic/ExceptionHandlingTest.java | 159 + .../gov/nasa/jpf/test/vm/basic/FieldTest.java | 211 + ...InitializeInterfaceClassObjectRefTest.java | 55 + .../test/vm/basic/JPFAttrAnnotationTest.java | 91 + .../nasa/jpf/test/vm/basic/LargeCodeTest.java | 5053 +++++++++++++++++ .../nasa/jpf/test/vm/basic/MethodTest.java | 258 + .../test/vm/basic/OutOfMemoryErrorTest.java | 48 + .../test/vm/basic/RecursiveClinitTest.java | 117 + .../jpf/test/vm/reflection/ArrayTest.java | 67 + .../test/vm/reflection/ConstructorTest.java | 137 + .../jpf/test/vm/reflection/FieldTest.java | 201 + .../jpf/test/vm/reflection/MethodTest.java | 686 +++ .../jpf/test/vm/reflection/ProxyTest.java | 97 + .../test/vm/reflection/ReflectionTest.java | 65 + .../jpf/test/vm/threads/InterruptTest.java | 218 + .../nasa/jpf/test/vm/threads/JoinTest.java | 716 +++ .../test/vm/threads/LockedStackDepthTest.java | 94 + .../test/vm/threads/SuspendResumeTest.java | 283 + .../threads/ThreadExceptionHandlerTest.java | 254 + .../jpf/test/vm/threads/ThreadStopTest.java | 527 ++ .../nasa/jpf/test/vm/threads/ThreadTest.java | 454 ++ .../nasa/jpf/test/vm/threads/WaitTest.java | 318 ++ .../nasa/jpf/test/xerces/SAXParserTest.java | 63 + ....puppycrawl.com^dtds^configuration_1_3.dtd | 56 + .../gov/nasa/jpf/test/xerces/sun_checks.xml | 189 + .../nasa/jpf/util/ArrayIntSetTestBase.java | 183 + .../nasa/jpf/util/ArrayObjectQueueTest.java | 227 + .../AvailableBufferedInputStreamTest.java | 280 + .../gov/nasa/jpf/util/BitSet1024Test.java | 245 + .../gov/nasa/jpf/util/BitSet256Test.java | 215 + src/tests/gov/nasa/jpf/util/BitSet64Test.java | 224 + .../nasa/jpf/util/CommitOutputStreamTest.java | 250 + .../jpf/util/IdentityArrayObjectSetTest.java | 66 + src/tests/gov/nasa/jpf/util/IntTableTest.java | 123 + .../gov/nasa/jpf/util/IntVectorTest.java | 168 + .../nasa/jpf/util/LimitedInputStreamTest.java | 234 + .../gov/nasa/jpf/util/LocationSpecTest.java | 109 + .../gov/nasa/jpf/util/MethodSpecTest.java | 86 + src/tests/gov/nasa/jpf/util/OATHashTest.java | 94 + .../gov/nasa/jpf/util/ObjVectorTest.java | 152 + .../gov/nasa/jpf/util/ObjectListTest.java | 395 ++ src/tests/gov/nasa/jpf/util/PSIntMapTest.java | 443 ++ .../jpf/util/PermutationGeneratorTest.java | 118 + .../nasa/jpf/util/SortedArrayIntSetTest.java | 32 + .../jpf/util/SortedArrayObjectSetTest.java | 102 + .../nasa/jpf/util/SparseClusterArrayTest.java | 404 ++ .../nasa/jpf/util/SparseIntVectorTest.java | 148 + .../nasa/jpf/util/SplitInputStreamTest.java | 660 +++ .../nasa/jpf/util/SplitOutputStreamTest.java | 156 + .../nasa/jpf/util/StringSetMatcherTest.java | 66 + .../jpf/util/UnsortedArrayIntSetTest.java | 32 + .../nasa/jpf/util/event/EventTreeTest.java | 421 ++ .../gov/nasa/jpf/util/json/JSONLexerTest.java | 167 + .../nasa/jpf/util/json/JSONParserTest.java | 114 + .../gov/nasa/jpf/vm/AnnotationInfoTest.java | 96 + .../gov/nasa/jpf/vm/ClassLoaderInfoTest.java | 92 + .../gov/nasa/jpf/vm/ElementInfoTest.java | 134 + .../gov/nasa/jpf/vm/SystemStateTest.java | 132 + src/tests/gov/nasa/jpf/vm/TypesTest.java | 54 + .../jpf/vm/choice/IntChoiceFromListTest.java | 84 + .../jpf/vm/choice/IntChoiceFromSetTest.java | 69 + .../vm/multiProcess/FinalizerThreadTest.java | 36 + ...v_nasa_jpf_vm_multiProcess_MethodTest.java | 54 + ...sa_jpf_vm_multiProcess_NativePeerTest.java | 46 + ...v_nasa_jpf_vm_multiProcess_ThreadTest.java | 73 + ...pf_vm_multiProcess_TypeSeparationTest.java | 70 + .../nasa/jpf/vm/multiProcess/MethodTest.java | 68 + .../jpf/vm/multiProcess/NativePeerTest.java | 54 + .../nasa/jpf/vm/multiProcess/StringTest.java | 52 + .../nasa/jpf/vm/multiProcess/ThreadTest.java | 120 + .../vm/multiProcess/TypeSeparationTest.java | 120 + src/tests/java8/DefaultMethodTest.java | 146 + .../java8/JPF_java8_DefaultMethodTest$G1.java | 16 + src/tests/java8/LambdaTest.java | 297 + src/tests/java8/TypeAnnotationTest.java | 130 + 1239 files changed, 185970 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .idea/.name create mode 100644 .idea/annotations.iml create mode 100644 .idea/artifacts/RunJPF.xml create mode 100644 .idea/artifacts/jpf.xml create mode 100644 .idea/artifacts/jpf_annotations.xml create mode 100644 .idea/artifacts/jpf_classes.xml create mode 100644 .idea/classes.iml create mode 100644 .idea/codeStyleSettings.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/examples.iml create mode 100644 .idea/main.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/peers.iml create mode 100644 .idea/runConfigurations/run_example_jpf.xml create mode 100644 .idea/runConfigurations/run_test.xml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/tests.iml create mode 100644 .idea/vcs.xml create mode 100644 .project create mode 100644 LICENSE-2.0.txt create mode 100644 META-INF/RunJPF/MANIFEST.MF create mode 100644 README create mode 100755 bin/javajpf create mode 100755 bin/jpf create mode 100755 bin/jpf.bat create mode 100755 bin/print_class create mode 100755 bin/print_class.bat create mode 100755 bin/print_events create mode 100755 bin/test create mode 100755 bin/test.bat create mode 100644 build.properties create mode 100644 build.xml create mode 100644 doc/devel/attributes.md create mode 100644 doc/devel/bytecode_factory.md create mode 100644 doc/devel/choicegenerator.md create mode 100644 doc/devel/coding_conventions.md create mode 100644 doc/devel/create_project.md create mode 100644 doc/devel/design.md create mode 100644 doc/devel/eclipse_plugin_update.md create mode 100644 doc/devel/embedded.md create mode 100644 doc/devel/index.md create mode 100644 doc/devel/jpf_tests.md create mode 100644 doc/devel/listener.md create mode 100644 doc/devel/logging.md create mode 100644 doc/devel/mercurial.md create mode 100644 doc/devel/mji.md create mode 100644 doc/devel/mji/mangling.md create mode 100644 doc/devel/modules.md create mode 100644 doc/devel/partial_order_reduction.md create mode 100644 doc/devel/report.md create mode 100644 doc/graphics/DFSListener.svg create mode 100644 doc/graphics/app-types.svg create mode 100644 doc/graphics/attributes.svg create mode 100644 doc/graphics/bc-factory.svg create mode 100644 doc/graphics/cg-impl.svg create mode 100644 doc/graphics/cg-motivation.svg create mode 100644 doc/graphics/cg-ontology.svg create mode 100644 doc/graphics/cg-sequence.svg create mode 100644 doc/graphics/choicegen-example.svg create mode 100644 doc/graphics/genpeer.svg create mode 100644 doc/graphics/interleavings.svg create mode 100644 doc/graphics/jpf-abstractions.svg create mode 100644 doc/graphics/jpf-basic.svg create mode 100644 doc/graphics/jpf-intro-new.svg create mode 100644 doc/graphics/jpf-layers.svg create mode 100644 doc/graphics/jpf-project.svg create mode 100644 doc/graphics/listener-overview.svg create mode 100644 doc/graphics/listeners.svg create mode 100644 doc/graphics/mji-call.svg create mode 100644 doc/graphics/mji-functions.svg create mode 100644 doc/graphics/mji-mangling.svg create mode 100644 doc/graphics/new-testing.svg create mode 100644 doc/graphics/por-mark.svg create mode 100644 doc/graphics/por-scheduling-relevance.svg create mode 100644 doc/graphics/properties.svg create mode 100644 doc/graphics/report.svg create mode 100644 doc/graphics/states-mc.svg create mode 100644 doc/graphics/states-testing.svg create mode 100644 doc/graphics/sw-model-checking-2.svg create mode 100644 doc/graphics/sw-model-checking.svg create mode 100644 doc/index.md create mode 100644 doc/install/build.md create mode 100644 doc/install/eclipse-jpf.md create mode 100644 doc/install/eclipse-plugin.md create mode 100644 doc/install/eclipse-plugin/update.md create mode 100644 doc/install/eclipse-plugin/update/features.md create mode 100644 doc/install/eclipse-plugin/update/plugins.md create mode 100644 doc/install/index.md create mode 100644 doc/install/netbeans-jpf.md create mode 100644 doc/install/netbeans-plugin.md create mode 100644 doc/install/repo_shell.md create mode 100644 doc/install/repositories.md create mode 100644 doc/install/requirements.md create mode 100644 doc/install/site-properties.md create mode 100644 doc/install/snapshot.md create mode 100644 doc/intro/classification.md create mode 100644 doc/intro/index.md create mode 100644 doc/intro/race_example.md create mode 100644 doc/intro/random_example.md create mode 100644 doc/intro/testing_vs_model_checking.md create mode 100644 doc/intro/what_is_jpf.md create mode 100644 doc/jpf-core/AssertionProperty.md create mode 100644 doc/jpf-core/ErrorTraceGenerator.md create mode 100644 doc/jpf-core/ExceptionInjector.md create mode 100644 doc/jpf-core/IdleFilter.md create mode 100644 doc/jpf-core/index.md create mode 100644 doc/papers/chicago-author-date.csl create mode 100644 doc/papers/index.md create mode 100644 doc/papers/references.bib create mode 100644 doc/user/api.md create mode 100644 doc/user/application_types.md create mode 100644 doc/user/components.md create mode 100644 doc/user/config.md create mode 100644 doc/user/config/random.md create mode 100644 doc/user/index.md create mode 100644 doc/user/output.md create mode 100644 doc/user/run.md create mode 100644 doc/user/run_eclipse.md create mode 100644 doc/user/run_eclipse_plugin.md create mode 100644 doc/user/run_nb.md create mode 100644 doc/user/run_nb_plugin.md create mode 100644 eclipse/AntBuilder.launch create mode 100644 eclipse/run-JPF.launch create mode 100644 eclipse/test-JPF.launch create mode 100644 eclipse/update-JPF-siteproperties.launch create mode 100644 jpf.properties create mode 100644 nbproject/ide-file-targets.xml create mode 100644 nbproject/project.xml create mode 100644 src/annotations/gov/nasa/jpf/annotation/FilterField.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/FilterFrame.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/JPFAttribute.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/JPFConfig.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/JPFOption.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/JPFOptions.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/MJI.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/NeverBreak.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/NoJPFExecution.java create mode 100644 src/annotations/gov/nasa/jpf/annotation/NonShared.java create mode 100644 src/classes/gov/nasa/jpf/AnnotationProxyBase.java create mode 100644 src/classes/gov/nasa/jpf/BoxObjectCaches.java create mode 100644 src/classes/gov/nasa/jpf/CachedROHttpConnection.java create mode 100644 src/classes/gov/nasa/jpf/ConsoleOutputStream.java create mode 100644 src/classes/gov/nasa/jpf/EventProducer.java create mode 100644 src/classes/gov/nasa/jpf/FinalizerThread.java create mode 100644 src/classes/gov/nasa/jpf/SerializationConstructor.java create mode 100644 src/classes/java/io/File.java create mode 100644 src/classes/java/io/FileDescriptor.java create mode 100644 src/classes/java/io/FileInputStream.java create mode 100644 src/classes/java/io/FileOutputStream.java create mode 100644 src/classes/java/io/InputStreamReader.java create mode 100644 src/classes/java/io/OutputStreamWriter.java create mode 100644 src/classes/java/io/RandomAccessFile.java create mode 100644 src/classes/java/lang/Class.java create mode 100644 src/classes/java/lang/ClassLoader.java create mode 100644 src/classes/java/lang/InheritableThreadLocal.java create mode 100644 src/classes/java/lang/Object.java create mode 100644 src/classes/java/lang/StackTraceElement.java create mode 100644 src/classes/java/lang/String.java create mode 100644 src/classes/java/lang/System.java create mode 100644 src/classes/java/lang/Thread.java create mode 100644 src/classes/java/lang/ThreadGroup.java create mode 100644 src/classes/java/lang/ThreadLocal.java create mode 100644 src/classes/java/lang/Throwable.java create mode 100644 src/classes/java/lang/annotation/Inherited.java create mode 100644 src/classes/java/lang/annotation/Retention.java create mode 100644 src/classes/java/lang/ref/Reference.java create mode 100644 src/classes/java/lang/ref/ReferenceQueue.java create mode 100644 src/classes/java/lang/ref/WeakReference.java create mode 100644 src/classes/java/lang/reflect/AccessibleObject.java create mode 100644 src/classes/java/lang/reflect/Constructor.java create mode 100644 src/classes/java/lang/reflect/Field.java create mode 100644 src/classes/java/lang/reflect/InvocationTargetException.java create mode 100644 src/classes/java/lang/reflect/Method.java create mode 100644 src/classes/java/net/URLClassLoader.java create mode 100644 src/classes/java/nio/Buffer.java create mode 100644 src/classes/java/nio/BufferUnderflowException.java create mode 100644 src/classes/java/nio/ByteBuffer.java create mode 100644 src/classes/java/nio/ByteOrder.java create mode 100644 src/classes/java/nio/channels/FileChannel.java create mode 100644 src/classes/java/nio/package-info.java create mode 100644 src/classes/java/security/AccessController.java create mode 100644 src/classes/java/security/MessageDigest.java create mode 100644 src/classes/java/security/SecureClassLoader.java create mode 100644 src/classes/java/text/DecimalFormat.java create mode 100644 src/classes/java/text/Format.java create mode 100644 src/classes/java/text/NumberFormat.java create mode 100644 src/classes/java/text/SimpleDateFormat.java create mode 100644 src/classes/java/util/Random.java create mode 100644 src/classes/java/util/TimeZone.java create mode 100644 src/classes/java/util/concurrent/BrokenBarrierException.java create mode 100644 src/classes/java/util/concurrent/CyclicBarrier.java create mode 100644 src/classes/java/util/concurrent/Exchanger.java create mode 100644 src/classes/java/util/concurrent/atomic/AtomicIntegerArray.java create mode 100644 src/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java create mode 100644 src/classes/java/util/concurrent/atomic/AtomicLongArray.java create mode 100644 src/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java create mode 100644 src/classes/java/util/concurrent/atomic/AtomicReferenceArray.java create mode 100644 src/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java create mode 100644 src/classes/java/util/function/Supplier.java create mode 100644 src/classes/java/util/logging/FileHandler.java create mode 100644 src/classes/java/util/regex/Matcher.java create mode 100644 src/classes/java/util/regex/Pattern.java create mode 100644 src/classes/org/junit/After.java create mode 100644 src/classes/org/junit/AfterClass.java create mode 100644 src/classes/org/junit/Before.java create mode 100644 src/classes/org/junit/BeforeClass.java create mode 100644 src/classes/org/junit/Ignore.java create mode 100644 src/classes/org/junit/Test.java create mode 100644 src/classes/sun/misc/AtomicLong.java create mode 100644 src/classes/sun/misc/JavaAWTAccess.java create mode 100644 src/classes/sun/misc/JavaIOAccess.java create mode 100644 src/classes/sun/misc/JavaIODeleteOnExitAccess.java create mode 100644 src/classes/sun/misc/JavaIOFileDescriptorAccess.java create mode 100644 src/classes/sun/misc/JavaLangAccess.java create mode 100644 src/classes/sun/misc/JavaNetAccess.java create mode 100644 src/classes/sun/misc/JavaNioAccess.java create mode 100644 src/classes/sun/misc/SharedSecrets.java create mode 100644 src/classes/sun/misc/Unsafe.java create mode 100644 src/classes/sun/net/www/protocol/http/Handler.java create mode 100644 src/classes/sun/nio/ch/Interruptible.java create mode 100644 src/classes/sun/reflect/ConstantPool.java create mode 100644 src/classes/sun/reflect/annotation/AnnotationType.java create mode 100644 src/examples/BoundedBuffer.java create mode 100644 src/examples/BoundedBuffer.jpf create mode 100644 src/examples/Crossing.java create mode 100644 src/examples/Crossing.jpf create mode 100644 src/examples/DiningPhil.java create mode 100644 src/examples/DiningPhil.jpf create mode 100644 src/examples/HelloWorld.java create mode 100644 src/examples/HelloWorld.jpf create mode 100644 src/examples/NumericValueCheck.java create mode 100644 src/examples/NumericValueCheck.jpf create mode 100644 src/examples/Racer.java create mode 100644 src/examples/Racer.jpf create mode 100644 src/examples/Rand.java create mode 100644 src/examples/Rand.jpf create mode 100644 src/examples/RobotManager-replay-nt.jpf create mode 100644 src/examples/RobotManager-replay-ot.jpf create mode 100644 src/examples/RobotManager.java create mode 100644 src/examples/RobotManager.jpf create mode 100644 src/examples/StopWatch.java create mode 100644 src/examples/StopWatch.jpf create mode 100644 src/examples/TestExample-coverage.jpf create mode 100644 src/examples/TestExample.java create mode 100644 src/examples/oldclassic-da.jpf create mode 100644 src/examples/oldclassic.java create mode 100644 src/examples/oldclassic.jpf create mode 100644 src/main/gov/nasa/jpf/$coreTag.java create mode 100644 src/main/gov/nasa/jpf/Config.java create mode 100644 src/main/gov/nasa/jpf/ConfigChangeListener.java create mode 100644 src/main/gov/nasa/jpf/Error.java create mode 100644 src/main/gov/nasa/jpf/GenericProperty.java create mode 100644 src/main/gov/nasa/jpf/JPF.java create mode 100644 src/main/gov/nasa/jpf/JPFClassLoader.java create mode 100644 src/main/gov/nasa/jpf/JPFConfigException.java create mode 100644 src/main/gov/nasa/jpf/JPFErrorException.java create mode 100644 src/main/gov/nasa/jpf/JPFException.java create mode 100644 src/main/gov/nasa/jpf/JPFListener.java create mode 100644 src/main/gov/nasa/jpf/JPFListenerException.java create mode 100644 src/main/gov/nasa/jpf/JPFNativePeerException.java create mode 100644 src/main/gov/nasa/jpf/JPFShell.java create mode 100644 src/main/gov/nasa/jpf/ListenerAdapter.java create mode 100644 src/main/gov/nasa/jpf/Property.java create mode 100644 src/main/gov/nasa/jpf/PropertyListenerAdapter.java create mode 100644 src/main/gov/nasa/jpf/State.java create mode 100644 src/main/gov/nasa/jpf/StateExtension.java create mode 100644 src/main/gov/nasa/jpf/SystemAttribute.java create mode 100644 src/main/gov/nasa/jpf/jvm/ClassFile.java create mode 100644 src/main/gov/nasa/jpf/jvm/ClassFilePrinter.java create mode 100644 src/main/gov/nasa/jpf/jvm/ClassFileReader.java create mode 100644 src/main/gov/nasa/jpf/jvm/ClassFileReaderAdapter.java create mode 100644 src/main/gov/nasa/jpf/jvm/DirClassFileContainer.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMAnnotationParser.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMByteCodePrinter.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMByteCodeReader.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMByteCodeReaderAdapter.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMClassFileContainer.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMClassInfo.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMCodeBuilder.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMDirectCallStackFrame.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMInstructionFactory.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMNativeStackFrame.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMStackFrame.java create mode 100644 src/main/gov/nasa/jpf/jvm/JVMSystemClassLoaderInfo.java create mode 100644 src/main/gov/nasa/jpf/jvm/JarClassFileContainer.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/AALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/AASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ACONST_NULL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ANEWARRAY.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ARETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ARRAYLENGTH.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ATHROW.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ArrayLoadInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ArrayStoreInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/BALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/BASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/BIPUSH.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/CALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/CASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/CHECKCAST.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/D2F.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/D2I.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/D2L.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DADD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DCMPG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DCMPL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DCONST.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DDIV.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DIRECTCALLRETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DLOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DMUL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DNEG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DREM.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DRETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DSTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DSUB.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DUP.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DUP2.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X1.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X2.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DUP_X1.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DUP_X2.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/DoubleCompareInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/EXECUTENATIVE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/F2D.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/F2I.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/F2L.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FADD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FCMPG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FCMPL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FCONST.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FDIV.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FINISHCLINIT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FLOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FMUL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FNEG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FREM.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FRETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FSTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/FSUB.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/GETFIELD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/GOTO.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/GOTO_W.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/GetHelper.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/I2B.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/I2C.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/I2D.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/I2F.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/I2L.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/I2S.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IADD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IAND.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ICONST.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IDIV.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFEQ.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFGE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFGT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFLE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFLT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFNE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFNONNULL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IFNULL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPEQ.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPNE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPEQ.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPNE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IINC.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ILOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IMUL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INEG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INSTANCEOF.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKECG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKECLINIT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKEINTERFACE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKESPECIAL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/INVOKEVIRTUAL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IOR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IREM.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IRETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ISHL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ISHR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ISTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/ISUB.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IUSHR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IXOR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/IfInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/InstanceInvocation.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/InstructionFactory.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JSR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JSR_W.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMArrayElementInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMFieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMInstanceFieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitor.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitorAdapter.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMInvokeInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMLocalVariableInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMReturnInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/JVMStaticFieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/L2D.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/L2F.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/L2I.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LADD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LAND.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LCMP.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LCONST.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LDC.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LDC2_W.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LDC_W.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LDIV.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LLOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LMUL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LNEG.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LOOKUPSWITCH.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LOR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LREM.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LRETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LSHL.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LSHR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LSTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LSUB.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LUSHR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LXOR.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LockInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LongArrayLoadInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LongArrayStoreInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/LongReturn.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/MONITORENTER.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/MONITOREXIT.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/MULTIANEWARRAY.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/NATIVERETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/NEW.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/NEWARRAY.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/NOP.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/NewArrayInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/POP.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/POP2.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/PUTFIELD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/PutHelper.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/RET.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/RETURN.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/RUNSTART.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/SALOAD.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/SASTORE.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/SIPUSH.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/SWAP.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/StaticFieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/SwitchInstruction.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/TABLESWITCH.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/VirtualInvocation.java create mode 100644 src/main/gov/nasa/jpf/jvm/bytecode/WIDE.java create mode 100644 src/main/gov/nasa/jpf/listener/AssertionProperty.java create mode 100644 src/main/gov/nasa/jpf/listener/BudgetChecker.java create mode 100644 src/main/gov/nasa/jpf/listener/CGMonitor.java create mode 100644 src/main/gov/nasa/jpf/listener/CGRemover.java create mode 100644 src/main/gov/nasa/jpf/listener/CallMonitor.java create mode 100644 src/main/gov/nasa/jpf/listener/ChoiceSelector.java create mode 100644 src/main/gov/nasa/jpf/listener/ChoiceTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/CoverageAnalyzer.java create mode 100644 src/main/gov/nasa/jpf/listener/DeadlockAnalyzer.java create mode 100644 src/main/gov/nasa/jpf/listener/DistributedSimpleDot.java create mode 100644 src/main/gov/nasa/jpf/listener/EndlessLoopDetector.java create mode 100644 src/main/gov/nasa/jpf/listener/ErrorTraceGenerator.java create mode 100644 src/main/gov/nasa/jpf/listener/ExceptionInjector.java create mode 100644 src/main/gov/nasa/jpf/listener/ExecTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/HeapTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/IdleFilter.java create mode 100644 src/main/gov/nasa/jpf/listener/InsnCounter.java create mode 100644 src/main/gov/nasa/jpf/listener/LockedStackDepth.java create mode 100644 src/main/gov/nasa/jpf/listener/LogConsole.java create mode 100644 src/main/gov/nasa/jpf/listener/MethodAnalyzer.java create mode 100644 src/main/gov/nasa/jpf/listener/MethodTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/NoStateCycles.java create mode 100644 src/main/gov/nasa/jpf/listener/NonSharedChecker.java create mode 100644 src/main/gov/nasa/jpf/listener/NullTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/NumericValueChecker.java create mode 100644 src/main/gov/nasa/jpf/listener/OOMEInjector.java create mode 100644 src/main/gov/nasa/jpf/listener/ObjectTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/OverlappingMethodAnalyzer.java create mode 100644 src/main/gov/nasa/jpf/listener/PathOutputMonitor.java create mode 100644 src/main/gov/nasa/jpf/listener/Perturbator.java create mode 100644 src/main/gov/nasa/jpf/listener/PreciseRaceDetector.java create mode 100644 src/main/gov/nasa/jpf/listener/ReferenceLocator.java create mode 100644 src/main/gov/nasa/jpf/listener/SearchStats.java create mode 100644 src/main/gov/nasa/jpf/listener/SimpleDot.java create mode 100644 src/main/gov/nasa/jpf/listener/SimpleIdleFilter.java create mode 100644 src/main/gov/nasa/jpf/listener/StackDepthChecker.java create mode 100644 src/main/gov/nasa/jpf/listener/StackTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/StateCountEstimator.java create mode 100644 src/main/gov/nasa/jpf/listener/StateSpaceAnalyzer.java create mode 100644 src/main/gov/nasa/jpf/listener/StateSpaceDot.java create mode 100644 src/main/gov/nasa/jpf/listener/StateTracker.java create mode 100644 src/main/gov/nasa/jpf/listener/StopWatchFuzzer.java create mode 100644 src/main/gov/nasa/jpf/listener/TraceStorer.java create mode 100644 src/main/gov/nasa/jpf/listener/VarRecorder.java create mode 100644 src/main/gov/nasa/jpf/listener/VarTracker.java create mode 100644 src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.java create mode 100644 src/main/gov/nasa/jpf/perturb/IntOverUnder.java create mode 100644 src/main/gov/nasa/jpf/perturb/OperandPerturbator.java create mode 100644 src/main/gov/nasa/jpf/report/ConsolePublisher.java create mode 100644 src/main/gov/nasa/jpf/report/Publisher.java create mode 100644 src/main/gov/nasa/jpf/report/PublisherExtension.java create mode 100644 src/main/gov/nasa/jpf/report/PublisherExtensionAdapter.java create mode 100644 src/main/gov/nasa/jpf/report/Reporter.java create mode 100644 src/main/gov/nasa/jpf/report/Statistics.java create mode 100644 src/main/gov/nasa/jpf/report/XMLPublisher.java create mode 100644 src/main/gov/nasa/jpf/search/DFSearch.java create mode 100644 src/main/gov/nasa/jpf/search/PathSearch.java create mode 100644 src/main/gov/nasa/jpf/search/RandomSearch.java create mode 100644 src/main/gov/nasa/jpf/search/Search.java create mode 100644 src/main/gov/nasa/jpf/search/SearchListener.java create mode 100644 src/main/gov/nasa/jpf/search/SearchListenerAdapter.java create mode 100644 src/main/gov/nasa/jpf/search/SearchState.java create mode 100644 src/main/gov/nasa/jpf/search/Simulation.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/BFSHeuristic.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/DFSHeuristic.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/GlobalSwitchThread.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/HeuristicSearch.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/HeuristicState.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/Interleaving.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/MinimizePreemption.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/MostBlocked.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/PreferThreads.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/PrioritizedState.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/RandomHeuristic.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/SimplePriorityHeuristic.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/StaticPriorityQueue.java create mode 100644 src/main/gov/nasa/jpf/search/heuristic/UserHeuristic.java create mode 100644 src/main/gov/nasa/jpf/tool/GenPeer.java create mode 100644 src/main/gov/nasa/jpf/tool/LogConsole.java create mode 100644 src/main/gov/nasa/jpf/tool/PrintEvents.java create mode 100644 src/main/gov/nasa/jpf/tool/Run.java create mode 100644 src/main/gov/nasa/jpf/tool/RunJPF.java create mode 100644 src/main/gov/nasa/jpf/tool/RunTest.java create mode 100644 src/main/gov/nasa/jpf/util/ArrayByteQueue.java create mode 100644 src/main/gov/nasa/jpf/util/ArrayIntSet.java create mode 100644 src/main/gov/nasa/jpf/util/ArrayObjectQueue.java create mode 100644 src/main/gov/nasa/jpf/util/Attributable.java create mode 100644 src/main/gov/nasa/jpf/util/AvailableBufferedInputStream.java create mode 100644 src/main/gov/nasa/jpf/util/BailOut.java create mode 100644 src/main/gov/nasa/jpf/util/BinaryClassSource.java create mode 100644 src/main/gov/nasa/jpf/util/BitArray.java create mode 100644 src/main/gov/nasa/jpf/util/BitSet1024.java create mode 100644 src/main/gov/nasa/jpf/util/BitSet256.java create mode 100644 src/main/gov/nasa/jpf/util/BitSet64.java create mode 100644 src/main/gov/nasa/jpf/util/BitSetN.java create mode 100644 src/main/gov/nasa/jpf/util/ClassInfoFilter.java create mode 100644 src/main/gov/nasa/jpf/util/CloneableObject.java create mode 100644 src/main/gov/nasa/jpf/util/Cloner.java create mode 100644 src/main/gov/nasa/jpf/util/CommitOutputStream.java create mode 100644 src/main/gov/nasa/jpf/util/ConsoleStream.java create mode 100644 src/main/gov/nasa/jpf/util/ConstGrowth.java create mode 100644 src/main/gov/nasa/jpf/util/CountDown.java create mode 100644 src/main/gov/nasa/jpf/util/DevNullPrintStream.java create mode 100644 src/main/gov/nasa/jpf/util/DynamicIntArray.java create mode 100644 src/main/gov/nasa/jpf/util/DynamicObjectArray.java create mode 100644 src/main/gov/nasa/jpf/util/ElementCreator.java create mode 100644 src/main/gov/nasa/jpf/util/ExpGrowth.java create mode 100644 src/main/gov/nasa/jpf/util/FeatureSpec.java create mode 100644 src/main/gov/nasa/jpf/util/FieldSpec.java create mode 100644 src/main/gov/nasa/jpf/util/FieldSpecMatcher.java create mode 100644 src/main/gov/nasa/jpf/util/FileUtils.java create mode 100644 src/main/gov/nasa/jpf/util/FinalBitSet.java create mode 100644 src/main/gov/nasa/jpf/util/FixedBitSet.java create mode 100644 src/main/gov/nasa/jpf/util/Growth.java create mode 100644 src/main/gov/nasa/jpf/util/HashData.java create mode 100644 src/main/gov/nasa/jpf/util/HashPool.java create mode 100644 src/main/gov/nasa/jpf/util/IdentityArrayObjectSet.java create mode 100644 src/main/gov/nasa/jpf/util/IdentityObjectSet.java create mode 100644 src/main/gov/nasa/jpf/util/ImmutableList.java create mode 100644 src/main/gov/nasa/jpf/util/IndexIterator.java create mode 100644 src/main/gov/nasa/jpf/util/InstructionState.java create mode 100644 src/main/gov/nasa/jpf/util/IntArray.java create mode 100644 src/main/gov/nasa/jpf/util/IntIterator.java create mode 100644 src/main/gov/nasa/jpf/util/IntSet.java create mode 100644 src/main/gov/nasa/jpf/util/IntTable.java create mode 100644 src/main/gov/nasa/jpf/util/IntVector.java create mode 100644 src/main/gov/nasa/jpf/util/Invocation.java create mode 100644 src/main/gov/nasa/jpf/util/JPFLogger.java create mode 100644 src/main/gov/nasa/jpf/util/JPFSiteUtils.java create mode 100644 src/main/gov/nasa/jpf/util/Left.java create mode 100644 src/main/gov/nasa/jpf/util/LimitedInputStream.java create mode 100644 src/main/gov/nasa/jpf/util/LinkedObjectQueue.java create mode 100644 src/main/gov/nasa/jpf/util/LocationSpec.java create mode 100644 src/main/gov/nasa/jpf/util/LogHandler.java create mode 100644 src/main/gov/nasa/jpf/util/LogManager.java create mode 100644 src/main/gov/nasa/jpf/util/Loggable.java create mode 100644 src/main/gov/nasa/jpf/util/LongVector.java create mode 100644 src/main/gov/nasa/jpf/util/MethodInfoRegistry.java create mode 100644 src/main/gov/nasa/jpf/util/MethodSpec.java create mode 100644 src/main/gov/nasa/jpf/util/MethodSpecMatcher.java create mode 100644 src/main/gov/nasa/jpf/util/Misc.java create mode 100644 src/main/gov/nasa/jpf/util/MutableInteger.java create mode 100644 src/main/gov/nasa/jpf/util/MutableIntegerRestorer.java create mode 100644 src/main/gov/nasa/jpf/util/OATHash.java create mode 100644 src/main/gov/nasa/jpf/util/ObjArray.java create mode 100644 src/main/gov/nasa/jpf/util/ObjVector.java create mode 100644 src/main/gov/nasa/jpf/util/ObjectConverter.java create mode 100644 src/main/gov/nasa/jpf/util/ObjectList.java create mode 100644 src/main/gov/nasa/jpf/util/ObjectQueue.java create mode 100644 src/main/gov/nasa/jpf/util/ObjectSet.java create mode 100644 src/main/gov/nasa/jpf/util/PSIntMap.java create mode 100644 src/main/gov/nasa/jpf/util/Pair.java create mode 100644 src/main/gov/nasa/jpf/util/PairPermutationGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/PathnameExpander.java create mode 100644 src/main/gov/nasa/jpf/util/PermutationGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/Predicate.java create mode 100644 src/main/gov/nasa/jpf/util/PrintStreamable.java create mode 100644 src/main/gov/nasa/jpf/util/PrintUtils.java create mode 100644 src/main/gov/nasa/jpf/util/Printable.java create mode 100644 src/main/gov/nasa/jpf/util/Processor.java create mode 100644 src/main/gov/nasa/jpf/util/RandomPermutationGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/ReadOnlyObjList.java create mode 100644 src/main/gov/nasa/jpf/util/Reflection.java create mode 100644 src/main/gov/nasa/jpf/util/RepositoryEntry.java create mode 100644 src/main/gov/nasa/jpf/util/Result.java create mode 100644 src/main/gov/nasa/jpf/util/Right.java create mode 100644 src/main/gov/nasa/jpf/util/RunListener.java create mode 100644 src/main/gov/nasa/jpf/util/RunRegistry.java create mode 100644 src/main/gov/nasa/jpf/util/SimplePool.java create mode 100644 src/main/gov/nasa/jpf/util/SingleElementList.java create mode 100644 src/main/gov/nasa/jpf/util/SortedArrayIntSet.java create mode 100644 src/main/gov/nasa/jpf/util/SortedArrayObjectSet.java create mode 100644 src/main/gov/nasa/jpf/util/Source.java create mode 100644 src/main/gov/nasa/jpf/util/SourceRef.java create mode 100644 src/main/gov/nasa/jpf/util/SparseClusterArray.java create mode 100644 src/main/gov/nasa/jpf/util/SparseIntVector.java create mode 100644 src/main/gov/nasa/jpf/util/SparseObjVector.java create mode 100644 src/main/gov/nasa/jpf/util/SplitInputStream.java create mode 100644 src/main/gov/nasa/jpf/util/SplitOutputStream.java create mode 100644 src/main/gov/nasa/jpf/util/StateExtensionClient.java create mode 100644 src/main/gov/nasa/jpf/util/StateExtensionListener.java create mode 100644 src/main/gov/nasa/jpf/util/StringExpander.java create mode 100644 src/main/gov/nasa/jpf/util/StringMatcher.java create mode 100644 src/main/gov/nasa/jpf/util/StringSetMatcher.java create mode 100644 src/main/gov/nasa/jpf/util/StructuredPrinter.java create mode 100644 src/main/gov/nasa/jpf/util/TotalPermutationGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/Trace.java create mode 100644 src/main/gov/nasa/jpf/util/TraceElement.java create mode 100644 src/main/gov/nasa/jpf/util/Transformer.java create mode 100644 src/main/gov/nasa/jpf/util/TwoTypeComparator.java create mode 100644 src/main/gov/nasa/jpf/util/TypeRef.java create mode 100644 src/main/gov/nasa/jpf/util/TypeSpec.java create mode 100644 src/main/gov/nasa/jpf/util/TypeSpecMatcher.java create mode 100644 src/main/gov/nasa/jpf/util/UniqueRandomPermGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/UnsortedArrayIntSet.java create mode 100644 src/main/gov/nasa/jpf/util/VarSpec.java create mode 100644 src/main/gov/nasa/jpf/util/WeakPool.java create mode 100644 src/main/gov/nasa/jpf/util/automaton/Automaton.java create mode 100644 src/main/gov/nasa/jpf/util/automaton/State.java create mode 100644 src/main/gov/nasa/jpf/util/automaton/Transition.java create mode 100644 src/main/gov/nasa/jpf/util/event/CheckEvent.java create mode 100644 src/main/gov/nasa/jpf/util/event/ControlEvent.java create mode 100644 src/main/gov/nasa/jpf/util/event/Event.java create mode 100644 src/main/gov/nasa/jpf/util/event/EventChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/event/EventConstructor.java create mode 100644 src/main/gov/nasa/jpf/util/event/EventContext.java create mode 100644 src/main/gov/nasa/jpf/util/event/EventForest.java create mode 100644 src/main/gov/nasa/jpf/util/event/EventTree.java create mode 100644 src/main/gov/nasa/jpf/util/event/NoEvent.java create mode 100644 src/main/gov/nasa/jpf/util/event/PropagatingEventContext.java create mode 100644 src/main/gov/nasa/jpf/util/event/SystemEvent.java create mode 100644 src/main/gov/nasa/jpf/util/event/TestEventTree.java create mode 100644 src/main/gov/nasa/jpf/util/json/AbstractValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/ArrayValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/BooleanValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/CGCall.java create mode 100644 src/main/gov/nasa/jpf/util/json/CGCreator.java create mode 100644 src/main/gov/nasa/jpf/util/json/CGCreatorFactory.java create mode 100644 src/main/gov/nasa/jpf/util/json/Creator.java create mode 100644 src/main/gov/nasa/jpf/util/json/CreatorsFactory.java create mode 100644 src/main/gov/nasa/jpf/util/json/DoubleValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/JSONLexer.java create mode 100644 src/main/gov/nasa/jpf/util/json/JSONObject.java create mode 100644 src/main/gov/nasa/jpf/util/json/JSONObjectValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/JSONParser.java create mode 100644 src/main/gov/nasa/jpf/util/json/NullValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/StringValue.java create mode 100644 src/main/gov/nasa/jpf/util/json/Token.java create mode 100644 src/main/gov/nasa/jpf/util/json/Value.java create mode 100644 src/main/gov/nasa/jpf/util/script/Alternative.java create mode 100644 src/main/gov/nasa/jpf/util/script/ESParser.java create mode 100644 src/main/gov/nasa/jpf/util/script/ElementProcessor.java create mode 100644 src/main/gov/nasa/jpf/util/script/Event.java create mode 100644 src/main/gov/nasa/jpf/util/script/EventFactory.java create mode 100644 src/main/gov/nasa/jpf/util/script/EventGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/script/EventGeneratorFactory.java create mode 100644 src/main/gov/nasa/jpf/util/script/Repetition.java create mode 100644 src/main/gov/nasa/jpf/util/script/Script.java create mode 100644 src/main/gov/nasa/jpf/util/script/ScriptElement.java create mode 100644 src/main/gov/nasa/jpf/util/script/ScriptElementContainer.java create mode 100644 src/main/gov/nasa/jpf/util/script/ScriptEnvironment.java create mode 100644 src/main/gov/nasa/jpf/util/script/Section.java create mode 100644 src/main/gov/nasa/jpf/util/script/SequenceInterpreter.java create mode 100644 src/main/gov/nasa/jpf/util/script/StringSetGenerator.java create mode 100644 src/main/gov/nasa/jpf/util/test/JPF_gov_nasa_jpf_util_test_TestJPF.java create mode 100644 src/main/gov/nasa/jpf/util/test/JPF_gov_nasa_jpf_util_test_TestMultiProcessJPF.java create mode 100644 src/main/gov/nasa/jpf/util/test/TestJPF.java create mode 100644 src/main/gov/nasa/jpf/util/test/TestMultiProcessJPF.java create mode 100644 src/main/gov/nasa/jpf/vm/AbstractRestorer.java create mode 100644 src/main/gov/nasa/jpf/vm/AbstractSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/AbstractTypeAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/AllRunnablesSyncPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/Allocation.java create mode 100644 src/main/gov/nasa/jpf/vm/AllocationContext.java create mode 100644 src/main/gov/nasa/jpf/vm/AnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/AnnotationParser.java create mode 100644 src/main/gov/nasa/jpf/vm/ApplicationContext.java create mode 100644 src/main/gov/nasa/jpf/vm/ArrayAccess.java create mode 100644 src/main/gov/nasa/jpf/vm/ArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/ArrayIndexOutOfBoundsExecutiveException.java create mode 100644 src/main/gov/nasa/jpf/vm/ArrayOffset.java create mode 100644 src/main/gov/nasa/jpf/vm/AtomicData.java create mode 100644 src/main/gov/nasa/jpf/vm/Attributor.java create mode 100644 src/main/gov/nasa/jpf/vm/Backtracker.java create mode 100644 src/main/gov/nasa/jpf/vm/BooleanArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/BooleanChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/BooleanFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/BootstrapMethodInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/BoxObjectCacheManager.java create mode 100644 src/main/gov/nasa/jpf/vm/ByteArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/ByteFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/BytecodeAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/BytecodeTypeParameterAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/CharArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/CharFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/CheckExtendTransition.java create mode 100644 src/main/gov/nasa/jpf/vm/ChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/ChoiceGeneratorBase.java create mode 100644 src/main/gov/nasa/jpf/vm/ChoicePoint.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassChangeException.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassFileContainer.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassFileMatch.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassInfoException.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassLoaderList.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassParseException.java create mode 100644 src/main/gov/nasa/jpf/vm/ClassPath.java create mode 100644 src/main/gov/nasa/jpf/vm/ClinitRequired.java create mode 100644 src/main/gov/nasa/jpf/vm/ClosedMemento.java create mode 100644 src/main/gov/nasa/jpf/vm/CollapsePools.java create mode 100644 src/main/gov/nasa/jpf/vm/ConstInsnPathTime.java create mode 100644 src/main/gov/nasa/jpf/vm/DebugJenkinsStateSet.java create mode 100644 src/main/gov/nasa/jpf/vm/DebugStateSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/DefaultBacktracker.java create mode 100644 src/main/gov/nasa/jpf/vm/DefaultFieldsFactory.java create mode 100644 src/main/gov/nasa/jpf/vm/DefaultMementoRestorer.java create mode 100644 src/main/gov/nasa/jpf/vm/DelegatingScheduler.java create mode 100644 src/main/gov/nasa/jpf/vm/DirectCallStackFrame.java create mode 100644 src/main/gov/nasa/jpf/vm/DoubleArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/DoubleChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/DoubleFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/DoubleSlotFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/DynamicElementInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ElementInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ExceptionHandler.java create mode 100644 src/main/gov/nasa/jpf/vm/ExceptionInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ExceptionParameterAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/FieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/FieldLockInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/FieldLockInfoFactory.java create mode 100644 src/main/gov/nasa/jpf/vm/Fields.java create mode 100644 src/main/gov/nasa/jpf/vm/FieldsFactory.java create mode 100644 src/main/gov/nasa/jpf/vm/FinalizerThreadInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/FloatArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/FloatChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/FloatFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/FormalParameterAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/FullStateSet.java create mode 100644 src/main/gov/nasa/jpf/vm/FunctionObjectFactory.java create mode 100644 src/main/gov/nasa/jpf/vm/GenericHeap.java create mode 100644 src/main/gov/nasa/jpf/vm/GenericSGOIDHeap.java create mode 100644 src/main/gov/nasa/jpf/vm/GenericSharednessPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/GenericSignatureHolder.java create mode 100644 src/main/gov/nasa/jpf/vm/GlobalSchedulingPoint.java create mode 100644 src/main/gov/nasa/jpf/vm/GlobalSharednessPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/HandlerContext.java create mode 100644 src/main/gov/nasa/jpf/vm/HashedAllocationContext.java create mode 100644 src/main/gov/nasa/jpf/vm/Heap.java create mode 100644 src/main/gov/nasa/jpf/vm/IncrementalChangeTracker.java create mode 100644 src/main/gov/nasa/jpf/vm/InfoObject.java create mode 100644 src/main/gov/nasa/jpf/vm/Instruction.java create mode 100644 src/main/gov/nasa/jpf/vm/IntArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/IntChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/IntegerFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/IsEndStateProperty.java create mode 100644 src/main/gov/nasa/jpf/vm/JPFOutputStream.java create mode 100644 src/main/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_vm_Verify.java create mode 100644 src/main/gov/nasa/jpf/vm/JenkinsStateSet.java create mode 100644 src/main/gov/nasa/jpf/vm/KernelState.java create mode 100644 src/main/gov/nasa/jpf/vm/LoadOnJPFRequired.java create mode 100644 src/main/gov/nasa/jpf/vm/LocalVarInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/LockSetThresholdFli.java create mode 100644 src/main/gov/nasa/jpf/vm/LongArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/LongChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/LongFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/MJIEnv.java create mode 100644 src/main/gov/nasa/jpf/vm/Memento.java create mode 100644 src/main/gov/nasa/jpf/vm/MementoFactory.java create mode 100644 src/main/gov/nasa/jpf/vm/MementoRestorer.java create mode 100644 src/main/gov/nasa/jpf/vm/MethodInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/MethodLocator.java create mode 100644 src/main/gov/nasa/jpf/vm/Monitor.java create mode 100644 src/main/gov/nasa/jpf/vm/MultiProcessVM.java create mode 100644 src/main/gov/nasa/jpf/vm/NamedFields.java create mode 100644 src/main/gov/nasa/jpf/vm/NativeMethodInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/NativePeer.java create mode 100644 src/main/gov/nasa/jpf/vm/NativeStackFrame.java create mode 100644 src/main/gov/nasa/jpf/vm/NativeStateHolder.java create mode 100644 src/main/gov/nasa/jpf/vm/NoJPFExec.java create mode 100644 src/main/gov/nasa/jpf/vm/NoOutOfMemoryErrorProperty.java create mode 100644 src/main/gov/nasa/jpf/vm/NoUncaughtExceptionsProperty.java create mode 100644 src/main/gov/nasa/jpf/vm/NotDeadlockedProperty.java create mode 100644 src/main/gov/nasa/jpf/vm/OVHeap.java create mode 100644 src/main/gov/nasa/jpf/vm/OVStatics.java create mode 100644 src/main/gov/nasa/jpf/vm/ObjRef.java create mode 100644 src/main/gov/nasa/jpf/vm/PSIMHeap.java create mode 100644 src/main/gov/nasa/jpf/vm/Path.java create mode 100644 src/main/gov/nasa/jpf/vm/PathSharednessPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/PersistentLockSetThresholdFli.java create mode 100644 src/main/gov/nasa/jpf/vm/PersistentSingleLockThresholdFli.java create mode 100644 src/main/gov/nasa/jpf/vm/PersistentTidSet.java create mode 100644 src/main/gov/nasa/jpf/vm/PreciseAllocationContext.java create mode 100644 src/main/gov/nasa/jpf/vm/PredicateMap.java create mode 100644 src/main/gov/nasa/jpf/vm/PriorityRunnablesSyncPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/ReferenceArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/ReferenceChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/ReferenceFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ReferenceProcessor.java create mode 100644 src/main/gov/nasa/jpf/vm/ReleaseAction.java create mode 100644 src/main/gov/nasa/jpf/vm/Restorable.java create mode 100644 src/main/gov/nasa/jpf/vm/RestorableVMState.java create mode 100644 src/main/gov/nasa/jpf/vm/Scheduler.java create mode 100644 src/main/gov/nasa/jpf/vm/SerializingStateSet.java create mode 100644 src/main/gov/nasa/jpf/vm/SharednessPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/ShortArrayFields.java create mode 100644 src/main/gov/nasa/jpf/vm/ShortFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/SingleLockThresholdFli.java create mode 100644 src/main/gov/nasa/jpf/vm/SingleProcessVM.java create mode 100644 src/main/gov/nasa/jpf/vm/SingleSlotFieldInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/StackFrame.java create mode 100644 src/main/gov/nasa/jpf/vm/StateRestorer.java create mode 100644 src/main/gov/nasa/jpf/vm/StateSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/StateSet.java create mode 100644 src/main/gov/nasa/jpf/vm/StaticElementInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/Statics.java create mode 100644 src/main/gov/nasa/jpf/vm/StatisticFieldLockInfoFactory.java create mode 100644 src/main/gov/nasa/jpf/vm/Step.java create mode 100644 src/main/gov/nasa/jpf/vm/Storable.java create mode 100644 src/main/gov/nasa/jpf/vm/SuperTypeAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/SyncPolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/SystemClassLoaderInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/SystemState.java create mode 100644 src/main/gov/nasa/jpf/vm/SystemTime.java create mode 100644 src/main/gov/nasa/jpf/vm/ThreadChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/ThreadData.java create mode 100644 src/main/gov/nasa/jpf/vm/ThreadInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ThreadInfoSet.java create mode 100644 src/main/gov/nasa/jpf/vm/ThreadList.java create mode 100644 src/main/gov/nasa/jpf/vm/ThresholdFieldLockInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/ThrowsAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/TidSet.java create mode 100644 src/main/gov/nasa/jpf/vm/TimeModel.java create mode 100644 src/main/gov/nasa/jpf/vm/Transition.java create mode 100644 src/main/gov/nasa/jpf/vm/TypeAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/TypeParameterAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/TypeParameterBoundAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/Types.java create mode 100644 src/main/gov/nasa/jpf/vm/UncaughtException.java create mode 100644 src/main/gov/nasa/jpf/vm/VM.java create mode 100644 src/main/gov/nasa/jpf/vm/VMListener.java create mode 100644 src/main/gov/nasa/jpf/vm/VariableAnnotationInfo.java create mode 100644 src/main/gov/nasa/jpf/vm/Verify.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/ArrayElementInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/FieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/InstanceFieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/InstanceInvokeInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/InstructionInterface.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/InvokeInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/LocalVariableInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/LookupSwitchInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/NewInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/ReadInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/ReadOrWriteInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/ReturnInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/ReturnValueInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/StaticFieldInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/StoreInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/TableSwitchInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/bytecode/WriteInstruction.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/BreakGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/CompoundChoiceGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/DoubleChoiceFromList.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/DoubleChoiceFromSet.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/DoubleSpec.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/DoubleThresholdGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/ExceptionThreadChoiceFromSet.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/ExposureCG.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/FloatChoiceFromList.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/IntChoiceFromList.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/IntChoiceFromSet.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/IntIntervalGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/InvocationCG.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/LongChoiceFromList.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/NumberChoiceFromList.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/PermutationCG.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/RandomIntIntervalGenerator.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/RandomOrderIntCG.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/RandomOrderLongCG.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/ThreadChoiceFromSet.java create mode 100644 src/main/gov/nasa/jpf/vm/choice/TypedObjectChoice.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/Abstraction.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/AbstractionAdapter.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/AdaptiveSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/AmmendableFilterConfiguration.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/CFSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/DebugCFSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/DebugFilteringSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/DefaultFilterConfiguration.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/DynamicAbstractionSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/FieldAmmendmentByName.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/FilterConfiguration.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/FilterFrame.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/FilteringSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/FramePolicy.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/IgnoreConstants.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/IgnoreReflectiveNames.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/IgnoreThreadNastiness.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/IgnoreUtilSilliness.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/Ignored.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/IgnoresFromAnnotations.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/IncludesFromAnnotations.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/TopFrameSerializer.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/UnfilterField.java create mode 100644 src/main/gov/nasa/jpf/vm/serialize/UnknownJPFClass.java create mode 100644 src/peers/gov/nasa/jpf/vm/AtomicFieldUpdater.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_AnnotationProxyBase.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_CachedROHttpConnection.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_ConsoleOutputStream.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_DelegatingTimeZone.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_EventProducer.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_FinalizerThread.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_SerializationConstructor.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_test_MemoryGoal.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_tools_MethodTester.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_File.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_FileDescriptor.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_InputStreamReader.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_ObjectInputStream.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_ObjectOutputStream.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_ObjectStreamClass.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_OutputStreamWriter.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_io_RandomAccessFile.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Boolean.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Byte.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Character.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Class.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_ClassLoader.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Double.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Float.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Integer.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Long.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Math.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Object.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Runtime.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Short.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_String.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_StringBuffer.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_StringBuilder.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_StringCoding.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_System.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Thread.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_ThreadLocal.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_Throwable.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Array.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Constructor.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Field.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Proxy.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_net_URLClassLoader.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_net_URLDecoder.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_net_URLEncoder.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_security_MessageDigest.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_Bidi.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_DateFormat.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_DateFormatSymbols.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_DecimalFormat.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_DecimalFormatSymbols.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_Format.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_text_SimpleDateFormat.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_Calendar.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_Date.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_Locale.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_Random.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_ResourceBundle.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_TimeZone.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_Exchanger.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicInteger.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicIntegerArray.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicIntegerFieldUpdater.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicLong.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicLongArray.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicLongFieldUpdater.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicReferenceArray.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_concurrent_atomic_AtomicReferenceFieldUpdater.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_logging_Level.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_regex_Matcher.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_java_util_regex_Pattern.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_sun_misc_Unsafe.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_sun_misc_VM.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_sun_net_www_protocol_http_Handler.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_sun_reflect_Reflection.java create mode 100644 src/peers/gov/nasa/jpf/vm/JPF_sun_reflect_ReflectionFactory.java create mode 100644 src/peers/gov/nasa/jpf/vm/LoggablePeer.java create mode 100644 src/tests/TypeNameTest.java create mode 100644 src/tests/classloader_specific_tests/Class1.java create mode 100644 src/tests/classloader_specific_tests/Class2.java create mode 100644 src/tests/classloader_specific_tests/Class3.java create mode 100644 src/tests/classloader_specific_tests/Interface1.java create mode 100644 src/tests/classloader_specific_tests/Interface2.java create mode 100644 src/tests/gov/nasa/jpf/ConfigTest.java create mode 100644 src/tests/gov/nasa/jpf/configTestApp.jpf create mode 100644 src/tests/gov/nasa/jpf/configTestCommon.jpf create mode 100644 src/tests/gov/nasa/jpf/configTestIncludes.jpf create mode 100644 src/tests/gov/nasa/jpf/configTestRequires.jpf create mode 100644 src/tests/gov/nasa/jpf/configTestRequiresFail.jpf create mode 100644 src/tests/gov/nasa/jpf/configTestSite.properties create mode 100644 src/tests/gov/nasa/jpf/jvm/ClassInfoTest.java create mode 100644 src/tests/gov/nasa/jpf/jvm/JVMStackFrameTest.java create mode 100644 src/tests/gov/nasa/jpf/jvm/MethodInfoTest.java create mode 100644 src/tests/gov/nasa/jpf/jvm/NonResolvedClassInfo.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/HarnessTest.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/InstructionFactoryTest.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/JPF_gov_nasa_jpf_test_basic_MJITest.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/ListenerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/MJITest.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/TestJPFMainTest.java create mode 100644 src/tests/gov/nasa/jpf/test/basic/TestJPFNoMainTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/AtomicIntegerFieldUpdaterTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/AtomicLongFieldUpdaterTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/AtomicReferenceFieldUpdaterTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/CountDownLatchTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/ExchangerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/ExecutorServiceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/concurrent/SemaphoreTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/io/BufferedInputStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/io/FileIOStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/io/FileIOTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/io/FileTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/io/ObjectStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/BoxObjectCacheTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/ClassLoaderTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/ClassTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/CloneTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/RuntimeTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/StringTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/SystemTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/ref/WeakReferenceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/reflect/ConstructorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/reflect/FieldTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/lang/reflect/MethodTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/math/BigIntegerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/net/LoadUtility.java create mode 100644 src/tests/gov/nasa/jpf/test/java/net/URLClassLoaderTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/net/URLEncoderTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/text/DateFormatTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/text/DecimalFormatTest.java create mode 100644 src/tests/gov/nasa/jpf/test/java/text/SimpleDateFormatTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/AttrsTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/BreakTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/CGNotificationTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/CGRemoverTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/CGReorderTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/CascadedCGTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/ExceptionInjectorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/ExtendTransitionTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/FinalBreakTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/FinalFieldChoiceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/IdleLoopTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/InvokeListenerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/JPF_gov_nasa_jpf_test_mc_basic_AttrsTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/JPF_gov_nasa_jpf_test_mc_basic_InvokeListenerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/JPF_gov_nasa_jpf_test_mc_basic_NoJPFExecTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/JPF_gov_nasa_jpf_test_mc_basic_RestorerTest$X.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/LocalVarInfoTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/MethodListenerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/NoJPFExecTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/NullTrackerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/OOMEInjectorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/OVHeapTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/RecursiveLockTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/RestorerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/SearchMultipleTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/SharedPropagationTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/SharedRefTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/SkipInstructionTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/StackDepthCheckerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/StatelessTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/TraceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/TransitionLengthTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/UnlockNonSharedTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/basic/VerifyTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/CGCreatorFactoryTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/CrossingTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/DataChoiceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/DynamicAbstractionTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/EventGeneratorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/JSONTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/NativeStateHolderTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/NumericValueCheckerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/ObjectStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/PerturbatorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/RandomTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/StopWatchFuzzerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/TimeModelTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/data/TypedObjectChoiceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/AtomicTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/ClinitTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/DaemonTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/DeadlockTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/ExceptionalThreadChoiceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/FinalizerThreadTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/HORaceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/JPF_gov_nasa_jpf_test_mc_threads_ExceptionalThreadChoiceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/MinimizePreemptionTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/MissedPathTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/NestedInitTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/OldClassicTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/RaceTest.java create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/SchedulesTest-output create mode 100644 src/tests/gov/nasa/jpf/test/mc/threads/SchedulesTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/AnnotationTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/ArrayTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/AssertTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/CastTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/ClassInitTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/EndStateListener.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/EndStateTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/EnumTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/ExceptionHandlingTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/FieldTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/InitializeInterfaceClassObjectRefTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/JPFAttrAnnotationTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/LargeCodeTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/MethodTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/OutOfMemoryErrorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/basic/RecursiveClinitTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/reflection/ArrayTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/reflection/ConstructorTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/reflection/FieldTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/reflection/MethodTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/reflection/ProxyTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/reflection/ReflectionTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/InterruptTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/JoinTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/LockedStackDepthTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/SuspendResumeTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/ThreadExceptionHandlerTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/ThreadStopTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/ThreadTest.java create mode 100644 src/tests/gov/nasa/jpf/test/vm/threads/WaitTest.java create mode 100644 src/tests/gov/nasa/jpf/test/xerces/SAXParserTest.java create mode 100644 src/tests/gov/nasa/jpf/test/xerces/http%^^www.puppycrawl.com^dtds^configuration_1_3.dtd create mode 100644 src/tests/gov/nasa/jpf/test/xerces/sun_checks.xml create mode 100644 src/tests/gov/nasa/jpf/util/ArrayIntSetTestBase.java create mode 100644 src/tests/gov/nasa/jpf/util/ArrayObjectQueueTest.java create mode 100644 src/tests/gov/nasa/jpf/util/AvailableBufferedInputStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/util/BitSet1024Test.java create mode 100644 src/tests/gov/nasa/jpf/util/BitSet256Test.java create mode 100644 src/tests/gov/nasa/jpf/util/BitSet64Test.java create mode 100644 src/tests/gov/nasa/jpf/util/CommitOutputStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/util/IdentityArrayObjectSetTest.java create mode 100644 src/tests/gov/nasa/jpf/util/IntTableTest.java create mode 100644 src/tests/gov/nasa/jpf/util/IntVectorTest.java create mode 100644 src/tests/gov/nasa/jpf/util/LimitedInputStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/util/LocationSpecTest.java create mode 100644 src/tests/gov/nasa/jpf/util/MethodSpecTest.java create mode 100644 src/tests/gov/nasa/jpf/util/OATHashTest.java create mode 100644 src/tests/gov/nasa/jpf/util/ObjVectorTest.java create mode 100644 src/tests/gov/nasa/jpf/util/ObjectListTest.java create mode 100644 src/tests/gov/nasa/jpf/util/PSIntMapTest.java create mode 100644 src/tests/gov/nasa/jpf/util/PermutationGeneratorTest.java create mode 100644 src/tests/gov/nasa/jpf/util/SortedArrayIntSetTest.java create mode 100644 src/tests/gov/nasa/jpf/util/SortedArrayObjectSetTest.java create mode 100644 src/tests/gov/nasa/jpf/util/SparseClusterArrayTest.java create mode 100644 src/tests/gov/nasa/jpf/util/SparseIntVectorTest.java create mode 100644 src/tests/gov/nasa/jpf/util/SplitInputStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/util/SplitOutputStreamTest.java create mode 100644 src/tests/gov/nasa/jpf/util/StringSetMatcherTest.java create mode 100644 src/tests/gov/nasa/jpf/util/UnsortedArrayIntSetTest.java create mode 100644 src/tests/gov/nasa/jpf/util/event/EventTreeTest.java create mode 100644 src/tests/gov/nasa/jpf/util/json/JSONLexerTest.java create mode 100644 src/tests/gov/nasa/jpf/util/json/JSONParserTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/AnnotationInfoTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/ClassLoaderInfoTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/ElementInfoTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/SystemStateTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/TypesTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/choice/IntChoiceFromListTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/choice/IntChoiceFromSetTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/FinalizerThreadTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/JPF_gov_nasa_jpf_vm_multiProcess_MethodTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/JPF_gov_nasa_jpf_vm_multiProcess_NativePeerTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/JPF_gov_nasa_jpf_vm_multiProcess_ThreadTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/JPF_gov_nasa_jpf_vm_multiProcess_TypeSeparationTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/MethodTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/NativePeerTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/StringTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/ThreadTest.java create mode 100644 src/tests/gov/nasa/jpf/vm/multiProcess/TypeSeparationTest.java create mode 100644 src/tests/java8/DefaultMethodTest.java create mode 100644 src/tests/java8/JPF_java8_DefaultMethodTest$G1.java create mode 100644 src/tests/java8/LambdaTest.java create mode 100644 src/tests/java8/TypeAnnotationTest.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..2721217 --- /dev/null +++ b/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..345194d --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.hg +.hgignore +local.properties +.version +.idea/workspace.xml +.idea/fileColors.xml +.idea/uiDesigner.xml +nbproject/private/* +build/* +dist/* +tmp/* +trace +activity*.png +*.class +*.orig +*~ +*.DS_Store diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..3836a03 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +jpf-core \ No newline at end of file diff --git a/.idea/annotations.iml b/.idea/annotations.iml new file mode 100644 index 0000000..f8666fe --- /dev/null +++ b/.idea/annotations.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/.idea/artifacts/RunJPF.xml b/.idea/artifacts/RunJPF.xml new file mode 100644 index 0000000..71c8dfa --- /dev/null +++ b/.idea/artifacts/RunJPF.xml @@ -0,0 +1,33 @@ + + + $PROJECT_DIR$/build + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/artifacts/jpf.xml b/.idea/artifacts/jpf.xml new file mode 100644 index 0000000..d43581a --- /dev/null +++ b/.idea/artifacts/jpf.xml @@ -0,0 +1,21 @@ + + + $PROJECT_DIR$/build + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/artifacts/jpf_annotations.xml b/.idea/artifacts/jpf_annotations.xml new file mode 100644 index 0000000..0e485a2 --- /dev/null +++ b/.idea/artifacts/jpf_annotations.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/build + + + + + \ No newline at end of file diff --git a/.idea/artifacts/jpf_classes.xml b/.idea/artifacts/jpf_classes.xml new file mode 100644 index 0000000..42eabbb --- /dev/null +++ b/.idea/artifacts/jpf_classes.xml @@ -0,0 +1,25 @@ + + + $PROJECT_DIR$/build + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/classes.iml b/.idea/classes.iml new file mode 100644 index 0000000..d41594e --- /dev/null +++ b/.idea/classes.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 0000000..7fb8ed0 --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..8e650cc --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..d821048 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/examples.iml b/.idea/examples.iml new file mode 100644 index 0000000..1d41ef7 --- /dev/null +++ b/.idea/examples.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/.idea/main.iml b/.idea/main.iml new file mode 100644 index 0000000..c393d6a --- /dev/null +++ b/.idea/main.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4bda5bf --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..769a3f3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/peers.iml b/.idea/peers.iml new file mode 100644 index 0000000..23675dd --- /dev/null +++ b/.idea/peers.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.idea/runConfigurations/run_example_jpf.xml b/.idea/runConfigurations/run_example_jpf.xml new file mode 100644 index 0000000..78a37b9 --- /dev/null +++ b/.idea/runConfigurations/run_example_jpf.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/run_test.xml b/.idea/runConfigurations/run_test.xml new file mode 100644 index 0000000..fa0eace --- /dev/null +++ b/.idea/runConfigurations/run_test.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/tests.iml b/.idea/tests.iml new file mode 100644 index 0000000..ac9f595 --- /dev/null +++ b/.idea/tests.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..e161617 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..d43fdf8 --- /dev/null +++ b/.project @@ -0,0 +1,26 @@ + + + jpf-core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + + + LaunchConfigHandle + <project>/eclipse/AntBuilder.launch + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/LICENSE-2.0.txt b/LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/META-INF/RunJPF/MANIFEST.MF b/META-INF/RunJPF/MANIFEST.MF new file mode 100644 index 0000000..a270c0c --- /dev/null +++ b/META-INF/RunJPF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: gov.nasa.jpf.tool.RunJPF + diff --git a/README b/README new file mode 100644 index 0000000..8fbfa95 --- /dev/null +++ b/README @@ -0,0 +1,36 @@ + Java PathFinder README + ====================== + +========General Information about JPF =================== + +All the latest developments, changes, documentation can +be found at: + +http://babelfish.arc.nasa.gov/trac/jpf/wiki + + +========Building and Installing ========================= + +If you are having problems installing and running JPF +please look at the documentation on the wiki at: + +http://babelfish.arc.nasa.gov/trac/jpf/wiki/install/start + +A lot of the commonly problems during the install and build +process have been documented on the wiki. Please make sure +that the the issue you are running into is not addressed +there; if is not then feel free to contact us at +java-pathfinder@googlegroups.com + + +======Documentation====================================== + +There is a constant effort to update and add JPF +documentation on the wiki. If you would like to contribute +in that, please contact us at +java-pathfinder@googlegroups.com + + + +Happy Verification +-- the Java PathFinder team diff --git a/bin/javajpf b/bin/javajpf new file mode 100755 index 0000000..cc3fe37 --- /dev/null +++ b/bin/javajpf @@ -0,0 +1,10 @@ +# shell script to start arbitrary classes through a JPFClassLoader + +JPF_HOME=`dirname "$0"`/.. + +if test -z "$JVM_FLAGS"; then + JVM_FLAGS="-Xmx1024m -ea" +fi + + +java -ea -cp "$JPF_HOME/build/main:$JPF_HOME/build/peers:$JPF_HOME/build/annotations:$JPF_HOME/build/tests:$JPF_HOME/lib/bcel.jar:$JPF_HOME/lib/junit-4.10.jar" gov.nasa.jpf.Main -a "$@" diff --git a/bin/jpf b/bin/jpf new file mode 100755 index 0000000..6db4727 --- /dev/null +++ b/bin/jpf @@ -0,0 +1,13 @@ +#!/bin/bash +# +# unix shell script to run jpf +# + +JPF_HOME=`dirname "$0"`/.. + +if test -z "$JVM_FLAGS"; then + JVM_FLAGS="-Xmx1024m -ea" +fi + +java $JVM_FLAGS -jar "$JPF_HOME/build/RunJPF.jar" "$@" + diff --git a/bin/jpf.bat b/bin/jpf.bat new file mode 100755 index 0000000..a891c21 --- /dev/null +++ b/bin/jpf.bat @@ -0,0 +1,13 @@ +REM +REM overly simplified batch file to start JPF from a command prompt +REM + +@echo off + +REM Set the JPF_HOME directory +set JPF_HOME=%~dp0.. + +set JVM_FLAGS=-Xmx1024m -ea + +java %JVM_FLAGS% -jar "%JPF_HOME%\build\RunJPF.jar" %* + diff --git a/bin/print_class b/bin/print_class new file mode 100755 index 0000000..31534ef --- /dev/null +++ b/bin/print_class @@ -0,0 +1,5 @@ +#!/bin/sh + +JPF_HOME=`dirname "$0"`/.. + +java -classpath "$JPF_HOME/build/jpf.jar" gov.nasa.jpf.jvm.ClassFilePrinter "$@" diff --git a/bin/print_class.bat b/bin/print_class.bat new file mode 100755 index 0000000..643790a --- /dev/null +++ b/bin/print_class.bat @@ -0,0 +1,8 @@ + +@echo off + +REM Set the JPF_HOME directory +set JPF_HOME=%~dp0.. + +java -classpath "%JPF_HOME%\build\jpf.jar" gov.nasa.jpf.classfile.ClassFilePrinter %* + diff --git a/bin/print_events b/bin/print_events new file mode 100755 index 0000000..3c95eb7 --- /dev/null +++ b/bin/print_events @@ -0,0 +1,5 @@ +#!/bin/sh + +JPF_HOME=`dirname "$0"`/.. + +java -classpath "$JPF_HOME/build/jpf.jar" gov.nasa.jpf.tool.PrintEvents "$@" diff --git a/bin/test b/bin/test new file mode 100755 index 0000000..c2d1c5d --- /dev/null +++ b/bin/test @@ -0,0 +1,13 @@ +#!/bin/bash +# +# unix shell script to run jpf +# + +JPF_HOME=`dirname "$0"`/.. + +if test -z "$JVM_FLAGS"; then + JVM_FLAGS="-Xmx1024m -ea" +fi + +java $JVM_FLAGS -jar "$JPF_HOME/build/RunTest.jar" "$@" + diff --git a/bin/test.bat b/bin/test.bat new file mode 100755 index 0000000..c4351c3 --- /dev/null +++ b/bin/test.bat @@ -0,0 +1,13 @@ +REM +REM overly simplified batch file to start JPF tests from a command prompt +REM + +@echo off + +REM Set the JPF_HOME directory +set JPF_HOME=%~dp0.. + +set JVM_FLAGS=-Xmx1024m -ea + +java %JVM_FLAGS% -jar "%JPF_HOME%\build\RunTest.jar" %* + diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..6602f96 --- /dev/null +++ b/build.properties @@ -0,0 +1,22 @@ +#JPF core build info +#Fri Jan 13 13:32:58 PST 2012 + +revision=647\:b8b86ac8f503 + +date.tip=2012-01-13 13\:30 -0800 + +author=Peter Mehlitz + +repository=file\://flyer/Users/pmehlitz/projects/eclipse/jpf-core + +upstream=http\://babelfish.arc.nasa.gov/hg/jpf/jpf-core + +java.version=1.6.0_26 + +os.arch=x86_64 + +os.name=Mac OS X + +os.version=10.5.8 + +user.country=US diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..ca73885 --- /dev/null +++ b/build.xml @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no javac was found __or__ check http://babelfish.arc.nasa.gov/trac/jpf/wiki/install/build for possible solutions + + + + + + + + + + + + + no src/main + no src/annotations + no src/peers + no src/classes + no src/tests + no src/examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/devel/attributes.md b/doc/devel/attributes.md new file mode 100644 index 0000000..69c7f83 --- /dev/null +++ b/doc/devel/attributes.md @@ -0,0 +1,18 @@ +# The Attribute System # + +While JPF stores values for operands, local variables and fields very similar to a normal VM, it also features a storage extension mechanism that lets you associate arbitrary objects with stack slots (operands and locals), fields, and whole objects (ElementInfos). The attribute objects can be set/used in [native peers](mji) or [listeners](listener) to add state stored/restored information that automatically follows the data flow. + +Note that JPF does not restore attribute object values upon backtracking per default, only attribute references. If you need to make sure attribute values are restored, you have to use copy-on-write and then store back when accessing and modifying such attributes. + +![Figure: JPF Attribute System](../graphics/attributes.svg){align=center width=650} + +JPF provides an API to set/access these attributes, which is located in `gov.nasa.jpf.vm.Fields` (for field attributes) and `gov.nasa.jpf.vm.StackFrame` (for local variables and operands). Once set, the VM copies the attributes each time it reads/writes the associated field or stackframe slot. + +## Usage ## + +For example, such attributes can be used to represent symbolic values or numeric error bounds. It should be noted though that attributes impose additional runtime costs, which is also why we don't treat normal, concrete values just as a special kind of attribute (normal values are still stored separately as builtin types like `int`). The upside of this is that your attributes coexist with normal, concrete values, which for instance allows things like mixed symbolic and concrete execution. + +> **Note:** JPF now can associate attributes not only with fields of an object, but with the object as a whole. See the `gov.nasa.jpf.vm.ElementInfo` API for details. + +> **Note:** while there is an API to set/retrieve attributes based on type, there is no implementation +yet that allows multiple attributes to be stored. \ No newline at end of file diff --git a/doc/devel/bytecode_factory.md b/doc/devel/bytecode_factory.md new file mode 100644 index 0000000..6fb8c2c --- /dev/null +++ b/doc/devel/bytecode_factory.md @@ -0,0 +1,70 @@ +# Bytecode Factories # +Normally, a VM defines the semantics of it's programming language. In case of Java, the corresponding instruction set represents a multi-threaded stack machine, where values are kept on the heap, or inside of local and/or operand slots within stack frames. The effect of Java bytecode instructions with respect to heap, locals and operands are described in [Sun's Java virtual machine specifications](http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html/). +JPF is different. The VM of JPF and its associated constructs like `ThreadInfo`, `ClassInfo`, `ElementInfo` etc. provide all the necessary means to implement a normal Java interpreter. However, JPF delegates the use of these means to the instructions. Every bytecode that gets executed by JPF is represented by a corresponding `Instruction` object, which normally gets instantiated during class load time. The `Instruction` classes of the standard execution mode can be found in package `gov.nasa.jpf.jvm.bytecode`. + +When it comes to executing a bytecode, the VM simply calls the `execute()` method of this `Instruction` instance. The implementation of this method defines the execution semantics. + +The trick is now that JPF uses a configurable [abstract factory](http://en.wikipedia.org/wiki/Abstract_factory_pattern) to choose and instantiate the `Instruction` classes. By providing your own concrete `InstructionFactory`, together with a set of related `Instruction` classes, you can change the execution semantics of Java. + +![Figure: Bytecode Factories](../graphics/bc-factory.svg){align=center width=850} + +## Usages ## + +Why would it be useful to change the standard semantics? One reason is to extend normal semantics with additional checks. For example, this is performed by the JPF extension jpf-numeric which overrides numeric bytecode classes with versions that check for over-/underflow and silent NaN propagation (among other things). A much more involved example is the JPF extension jpf-symbc, which implements a symbolic execution mode for Java, e.g. to automatically generate test cases based on the program structure of an application. It does so by overriding branch instructions, turning them into state space branches represented by their own [ChoiceGenerators](choicegenerator), collecting the path conditions on the way, and feeding them to an external SAT solver. + +## Implementation ## + +Since there is a large number of Java bytecode instructions, it would be tedious having to implement all 250+ Instruction classes in order to override just a couple of them. You can reduce the effort in three ways: + + +### GenericInstructionFactory ### + + +Using the `GenericInstructionFactory` as a base class for your `InstructionFactory`. This only requires you to specify an alternative package where your bytecode classes reside, together with the set of bytecodes that should be overridden. The resulting code can be quite short, as can be seen in the *numeric* extension example: + +~~~~~~~~ {.java} +public class NumericInstructionFactory extends GenericInstructionFactory { + + // which bytecodes do we replace + static final String[] BC_NAMES = { + "DCMPG", "DCMPL", "DADD", "DSUB", "DMUL", "DDIV", + "FCMPG", "FCMPL", "FADD", "FSUB", "FMUL", "FDIV", + "IADD", "ISUB", "IMUL", "IDIV", "IINC", + "LADD", "LSUB", "LMUL", "LDIV" + }; + + // where do they reside + protected static final String BC_PREFIX = "gov.nasa.jpf.numeric.bytecode."; + + // what classes should use them + protected static final String[] DEFAULT_EXCLUDES = { "java.*", "javax.*" }; + + public NumericInstructionFactory (Config conf){ + super(conf, BC_PREFIX, BC_NAMES, null, DEFAULT_EXCLUDES); + + NumericUtils.init(conf); + } +} +~~~~~~~~ + + +### Super Delegation ### + +You can derive your overriding bytecode classes from the ones in `gov.nasa.jpf.jvm.bytecode`. If you just want to add some checks before or after performing the "normal" operation, you can use the standard `Instruction` classes as base classes, and call `super.execute(..)` from within your derived classes. + + +### Attributes ### + +As your execution semantics get more complex, you probably need to store and restore additional information that is associated with variables. JPF provides an automatically managed [attribute system](attributes) for this purpose. You can attach objects to locals, operands and fields, and JPF takes care of propagating these attribute objects whenever it manipulates stackframes or heap objects. + + +## Configuration ## + + +Configuring your bytecode factory just requires one JPF property, e.g. + +~~~~~~~~ {.bash} +vm.insn_factory.class = gov.nasa.jpf.numeric.NumericInstructionFactory +~~~~~~~~ + +which can be either done from the command line or from within a *.jpf property file diff --git a/doc/devel/choicegenerator.md b/doc/devel/choicegenerator.md new file mode 100644 index 0000000..e8272eb --- /dev/null +++ b/doc/devel/choicegenerator.md @@ -0,0 +1,212 @@ +# ChoiceGenerators # + +The goal of every model checker is to check if certain properties hold in states of the system under test. The way that choices are computed is a fundamental part of model checking, since they determine which states are checked. We refer to the mechanism used by JPF to capture choices as ChoiceGenerators. + +ChoiceGenerators can be approached from an application perspective, or from the JPF implementation perspective. In this section, we cover both perspectives. + +## Motivation ## + +Whenever the model checker reaches non-determinism in code, it needs to compute choices. Non-determinism can be due to thread scheduling or non-deterministic data acquisitions. Here, we present an example including data non-determinism to justify our implementation approach. JPF provides support for "random" data acquisition, using the interface `gov.nasa.jpf.jvm.Verify`. + +~~~~~~~~ {.java} +... +boolean b = Verify.getBoolean(); // evaluated by JPF for both `true` and `false` +... +~~~~~~~~ + +This worked nicely for small sets of choice values (such as `{true,false}` for boolean), but the mechanism for enumerating all choices from a type specific interval becomes already questionable for large intervals (e.g. `Verify.getInt(0,10000)`), and fails completely if the data type does not allow finite choice sets at all (such as floating point types): + +![Figure 1: Motivation behind ChoiceGenerator](../graphics/cg-motivation.svg){align=center width=750} + +To handle this case, we have to leave the ideal world of model checking (that considers all possible choices), and make use of what we know about the real world - we have to use heuristics to make the set of choices finite and manageable. However, heuristics are application and domain specific, and it would be a bad idea to hardcode them into the test drivers we give JPF to analyze. This leads to a number of requirements for the JPF choice mechanism: + + * choice mechanisms have to be decoupled (i.e. thread choices should be independent of data choices, double choices from int choices etc.) + * choice sets and enumeration should be encapsulated in dedicated, type specific objects. The VM should only know about the most basic types, and otherwise use a generic interface to obtain choices + * selection of classes representing (domain specific) heuristics, and parametrization of ChoiceGenerator instances should be possible at runtime, i.e. via JPF's configuration mechanism (properties) + +The diagram shown above depicts this with an example that uses a "randomly" chosen velocity value of type double. As an example heuristic we use a threshold model, i.e. we want to know how the system reacts below, at, and above a certain application specific value (threshold). We reduce an infinite set of choices to only three "interesting" ones. Of course, "interesting" is quite subjective, and we probably want to play with the values (delta, threshold, or even used heuristic) efficiently, without having to rebuild the application each time we run JPF. + +The code example does not mention the used `ChoiceGenerator` class (`DoubleThresholdGenerator`) at all, it just specifies a symbolic name `"velocity"`, which JPF uses to look up an associated class name from its configuration data (initialized via property files or the command line - see Configuring JPF Runtime Options). But it doesn't stop there. Most heuristics need further parameterization (e.g. threshold, delta), and we provide that by passing the JPF configuration data into the `ChoiceGenerator` constructors (e.g. the `velocity.threshold` property). Each `ChoiceGenerator` instance knows its symbolic name (e.g. `"velocity"`), and can use this name to look up whatever parameters it needs. + +## The JPF Perspective ## + +Having such a mechanism is nice to avoid test driver modification. But it would be much nicer to consistently use the same mechanism not just for data acquisition choices, but also scheduling choices (i.e. functionality that is not controlled by the test application). JPF's ChoiceGenerator mechanism does just this, but in order to understand it from an implementation perspective we have to take one step back and look at some JPF terminology: + +![Figure 2: States, Transitions and Choices](../graphics/cg-ontology.svg){align=center width=650} + + +*State* is a snapshot of the current execution status of the application (mostly thread and heap states), plus the execution history (path) that lead to this state. Every state has a unique id number. State is encapsulated in the `SystemState` instance (almost, there is some execution history which is just kept by the JVM object). This includes three components: + + * KernelState - the application snapshot (threads, heap) + * trail - the last Transition (execution history) + * current and next ChoiceGenerator - the objects encapsulating the choice enumeration that produces different transitions (but not necessarily new states) + +*Transition* is the sequence of instructions that leads from one state to the next. There is no context switch within a transition, it's all in the same thread. There can be multiple transitions leading out of one state (but not necessarily to a new state). + +*Choice* is what starts a new transition. This can be a different thread (i.e. scheduling choice), or different "random" data value. + +In other words, possible existence of choices is what terminates the last transition, and selection of a choice value precludes the next transition. The first condition corresponds to creating a new `ChoiceGenerator`, and letting the `SystemState` know about it. The second condition means to query the next choice value from this `ChoiceGenerator` (either internally within the VM, or in an instruction or native method). + +## How it comes to Life ## +With this terminology, we are ready to have a look at how it all works. Let's assume we are in a transition that executes a `getfield` bytecode instruction (remember, JPF executes Java bytecode), and the corresponding object that owns this field is shared between threads. For simplicity's sake, let's further assume there is no synchronization when accessing this object, (or we have turned off the property `vm.sync_detection`). Let's also assume there are other runnable threads at this point. Then we have a choice - the outcome of the execution might depend on the order in which we schedule threads, and hence access this field. There might be a data race. + +![Figure 3: ChoiceGenerator Sequence](../graphics/cg-sequence.svg){align=center width=550} + +Consequently, when JPF executes this `getfield` instruction, the `gov.nasa.jpf.jvm.bytecode.GETFIELD.execute()` method does three things: + + 1. create a new `ChoiceGenerator` (`ThreadChoiceGenerator` in this case), that has all runnable threads at this point as possible choices + 2. registers this `ChoiceGenerator` via calling `SystemState.setNextChoiceGenerator()` + 3. schedules itself for re-execution (just returns itself as the next instruction to execute within the currently running thread) + +At this point, JPF ends this transition (which is basically a loop inside `ThreadInfo.executeStep()`), stores a snapshot of the current State, and then starts the next transition (let's ignore the search and possible backtracks for a moment). The `ChoiceGenerator` created and registered at the end of the previous transition becomes the new current `ChoiceGenerator`. Every state has exactly one current `ChoiceGenerator` object that is associated with it, and every transition has exactly one choice value of this `ChoiceGenerator` that kicks it off. Every transition ends in an instruction that produces the next `ChoiceGenerator`. + +The new transition is started by the `SystemState` by setting the previously registered `ChoiceGenerator` as the current one, and calling its `ChoiceGenerator.advance()` method to position it on its next choice. Then the `SystemState` checks if the current `ChoiceGenerator` is a scheduling point (just a `ThreadChoiceGenerator` used to encapsulate threads scheduling), and if so, it gets the next thread to execute from it (i.e. the `SystemState` itself consumes the choice). Then it starts the next transition by calling `ThreadInfo.executeStep()` on it. + +The `ThreadInfo.executeStep()` basically loops until an Instruction.execute() returns itself, i.e. has scheduled itself for re-execution with a new `ChoiceGenerator`. When a subsequent `ThreadInfo.executeStep()` re-executes this instruction (e.g. `GETFIELD.execute()`), the instruction notices that it is the first instruction in a new transition, and hence does not have to create a `ChoiceGenerator` but proceeds with it's normal operations. + +If there is no next instruction, or the Search determines that the state has been seen before, the VM backtracks. The `SystemState` is restored to the old state, and checks for not-yet-explored choices of its associated ChoiceGenerator by calling `ChoiceGenerator.hasMoreChoices()`. If there are more choices, it positions the `ChoiceGenerator` on the next one by calling `ChoiceGenerator.advance()`. If all choices have been processed, the system backtracks again (until it's first `ChoiceGenerator` is done, at which point we terminate the search). + +![Figure 4: ChoiceGenerator Implementation](../graphics/cg-impl.svg){align=center width=850} + +The methods that create `ChoiceGenerators` have a particular structure, dividing their bodies into two parts: + + 1. *top half* - (potentially) creates and registers a new `ChoiceGenerator`. This marks the end of a transition + 2. *bottom half* - which does the real work, and might depend on acquiring a new choice value. This is executed at the beginning of the next transition + +To determine which branch you are in, you can call `ThreadInfo.isFirstStepInsn()`. This will return `true` if the currently executed instruction is the first one in the transition, which corresponds to the *bottom half* mentioned above. + +The only difference between scheduling choices and data acquisition choices is that the first ones are handled internally by the VM (more specifically: used by the `SystemState` to determine the next thread to execute), and the data acquisition is handled in the bottom half of `Instruction.execute()`, native method, or listener callback method (in which case it has to acquire the current `ChoiceGenerator` from the `SystemState`, and then explicitly call `ChoiceGenerator.getNextChoice()` to obtain the choice value). For a real example, look at the `JPF.gov_nasa_jpf_jvm_Verify.getBoolean()` implementation. + +As an implementation detail, creation of scheduling points are delegated to a `Scheduler` instance, which encapsulates a scheduling policy by providing a consistent set of `ThreadChoiceGenerators` for the fixed number of instructions that are scheduling relevant (`monitor_enter`, synchronized method calls, `Object.wait()` etc.). Clients of this `Scheduler` therefore have to be aware of that the policy object might not return a new `ChoiceGenerator`, in which case the client directly proceeds with the bottom half execution, and does not break the current transition. + +The standard classes and interfaces for the ChoiceGenerator mechanism can be found in package `gov.nasa.jpf.vm`, and include: + + * `ChoiceGenerator` + * `BooleanChoiceGenerator` + * `IntChoiceGenerator` + * `DoublechoiceGenerator` + * `ThreadChoiceGenerator` + * `SchedulingPoint` + * `SchedulerFactory` + * `DefaultSchedulerFactory` + +Concrete implementations can be found in package `gov.nasa.jpf.vm.choice`, and include classes like: + + * `IntIntervalGenerator` + * `IntChoiceFromSet` + * `DoubleChoiceFromSet` + * `DoubleThresholdGenerator` + * `ThreadChoiceFromSet` + +As the number of useful generic heuristics increases, we expect this package to be expanded. + + +## Cascaded ChoiceGenerators ## +There can be more than one `ChoiceGenerator` object associated with a transition. Such ChoiceGenerators are referred to as *cascaded*, since they give us a set of choice combinations for such transitions. + +For example, assume that we want to create a listener that perturbs certain field values, i.e. it replaces the result operand that is pushed by a `getfield` instruction. This is easy to do from a listener, but the VM (more specifically our on-the-fly [partial order reduction](partial_order_reduction)) might already create a `ThreadChoiceGenerator` (scheduling point) for this `getfield` if it refers to a shared object, and the instruction might cause a data race. Without cascaded `ChoiceGenerators` we could only have the perturbation listener **or** the race detection, but not both. This is clearly a limitation we want to overcome, since you might not even know when JPF - or some of the other [listeners](listener) or [bytecode_factories](bytecode_factory) - create `ChoiceGenerators` that would collide with the ones you want to create in your listener. + +Using cascaded ChoiceGenerators requires little more than what we have already seen above. It only involves changes to two steps: + + 1. ChoiceGenerator creation - you need to identify `ChoiceGenerators` with a `String` id. We can't use the type of the `ChoiceGenerator` - or it's associated choice type - to identify a particular instance, since different listeners might use different `ChoiceGenerator` instances of same types for different purposes. Resolving through unique types would throw us back to where we would have to know about all the other `ChoiceGenerators` created by all the other JPF components. We can't use the associated instruction either, because the whole point is that we can have more than one `ChoiceGenerator` for each of them. So we have to give our `ChoiceGenerator` instances names when we create them, as in + +~~~~~~~~ {.java} +... +IntChoiceFromSet cg = new IntChoiceFromSet("fieldPerturbator", 42, 43); +~~~~~~~~ + +The name should be reasonably unique, describing the context in which this choice is used. Don't go with "generic" names like "myChoice". In case of doubt, use the method name that creates the `ChoiceGenerator`. The reason why we need the *id* in the first place is that we later-on want to be able to retrieve a specific instance. Which brings us to: + + 2. ChoiceGenerator retrieval - at some point we want to process the choice (usually within the *bottom half* of the method that created the `ChoiceGenerator`), so we need to tell JPF all we know about the `ChoiceGenerator` instance, namely id and type. The simple `SystemState.getChoiceGenerator()` we used above will only give us the last registered one, which might or might not be the one we registered ourselves. Retrieval is done with a new method `SystemState.getCurrentChoiceGenerator(id,cgType)`, which in the above case would look like: + +~~~~~~~~ {.java} +... +IntChoiceFromSet cg = systemState.getCurrentChoiceGenerator("fieldPerturbator", IntChoiceFromSet.class); +assert cg != null : "required IntChoiceGenerator not found"; +... +~~~~~~~~ + +This method returns `null` if there is no `ChoiceGenerator` of the specified id and type associated with the currently executed instruction. If this is the bottom half of a method that created the instance, this is most likely an error condition that should be checked with an assertion. If the retrieval is in another method, existence of such a `ChoiceGenerator` instance could be optional and you therefore have it checked in an `if (cg != null) {..}' expression. + +This is all there is to it in case you don't refer to a particular execution state of an instruction. As an example, assume that you want to add some int choices on top of each `Verify.getInt(..)` call. Your listener would look like this: + +~~~~~~~~ {.java} + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + SystemState ss = vm.getSystemState(); + + if (executedInsn instanceof EXECUTENATIVE) { // break on method call + EXECUTENATIVE exec = (EXECUTENATIVE) executedInsn; + + if (exec.getExecutedMethodName().equals("getInt")){ // Verify.getInt(..) - this insn did create a CG on its own + if (!ti.isFirstStepInsn()){ // top half - first execution + IntIntervalGenerator cg = new IntIntervalGenerator("instrumentVerifyGetInt", 3,4); + ss.setNextChoiceGenerator(cg); + ... + + } else { // bottom half - re-execution at the beginning of the next transition + IntIntervalGenerator cg = ss.getCurrentChoiceGenerator("instrumentVerifyGetInt", IntIntervalGenerator.class); + assert cg != null : "no 'instrumentVerifyGetInt' IntIntervalGenerator found"; + int myChoice = cg.getNextChoice(); + ... // process choice + } + } + } + } +~~~~~~~~ + + +Sometimes what you do with your choice depends on the execution state of the instruction this `ChoiceGenerator` was created for, and you have to be aware of that the instruction might get re-executed (e.g. after processing the top half of another `ChoiceGenerator` creating method) before it has done what you depend on for your local choice processing. Consider our previous example of the field perturbation. Simply speaking, all we want to do in our listener is just swap operand stack values after a certain `getfield`. However, the partial order reduction of the VM might get in our way because it reschedules the instruction *before* it pushes the value if execution of this instruction might constitute a data race, and therefore required creation of a `ThreadChoiceGenerator` instance. What is worse is that the VM might do this conditionally - if there is only one runnable thread, there is no need for a scheduling point since there can't be a data race. Our own perturbator listener has to account for all that. Luckily, we can use `SystemState.getCurrentChoiceGenerator(id,type)` to unify all these cases, and we just have to restore execution state in case we want to re-execute the instruction ourselves. Here is an example: + +~~~~~~~~ {.java} + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + SystemState ss = vm.getSystemState(); + + if (executedInsn instanceof GETFIELD){ + GETFIELD getInsn = (GETFIELD) executedInsn; + FieldInfo fi = getInsn.getFieldInfo(); + if (fi.getName().equals("perturbedFieldName")){ + + IntChoiceFromSet cg = ss.getCurrentChoiceGenerator("fieldReplace", IntChoiceFromSet.class); + StackFrame frame = ti.getModifiableTopFrame(); + if (cg == null){ + + // we might get here after a preceding rescheduling exec, i.e. + // partial execution (with successive re-execution), or after + // non-rescheduling exec has been completed (only one runnable thread). + // In the first case we have to restore the operand stack so that + // we can re-execute + if (!ti.willReExecuteInstruction()){ + // restore old operand stack contents + frame.pop(); + frame.push(getInsn.getLastThis()); + } + + cg = new IntChoiceFromSet("fieldReplace", 42, 43); + ss.setNextChoiceGenerator(cg); + ti.reExecuteInstruction(); + + } else { + int v = cg.getNextChoice(); + int n = frame.pop(); + frame.push(v); + } + } + } + } +~~~~~~~~ + +These examples show you that at the beginning of each transition, there is a choice value for all the cascaded `ChoiceGenerators` associated with it. If you would add `choiceGeneratorAdvanced()` notifications to your listener, you would also see that JPF processes all related choice combinations. + +If you really want to see the context, there are a number of additional methods in `SystemState` that might help you: + + * `getChoiceGenerator()` - returns only the last registered one + * `getChoiceGenerators()` - returns an array of all `ChoiceGenerators` in the current execution path + * `getLastChoiceGeneratorOfType(cgType)` - returns the last registered `ChoiceGenerator` in the path that is of the specified type + * `getCurrentChoiceGenerators()` - returns array of all cascaded `ChoiceGenerators` associated with the current transition + * `getCurrentChoiceGenerator(id)` - returns last registered `ChoiceGenerator` of cascade with specified *id* + * `getCurrentChoiceGenerator(id,cgType)` - our workhorse: last registered `ChoiceGenerator` of cascade with specified *id* and *cgType* (which can be a supertype of the actual one) + * etc. + +How does the system detect if a `ChoiceGenerator` is cascaded or not? Very simple - within `SystemState.setNextChoiceGenerator(cg)`, we just check if `SystemState` already had a registered next `ChoiceGenerator`, and if so, we set a cascaded attribute for this one. Other than that, we just maintain normal linear `ChoiceGenerator` linkage, which is accessible through `ChoiceGenerator.getPreviousChoiceGenerator()`. If you want to iterate through a cascade yourself, use the `ChoiceGenerator.getCascadedParent()` method, which returns `null` if there is none. Just be aware of that the last registered `ChoiceGenerator` (i.e. what `SystemState.getChoiceGenerator()` returns) does *not* have the cascaded attribute set (i.e. `ChoiceGenerator.isCascaded()` returns `false`). \ No newline at end of file diff --git a/doc/devel/coding_conventions.md b/doc/devel/coding_conventions.md new file mode 100644 index 0000000..fe629e9 --- /dev/null +++ b/doc/devel/coding_conventions.md @@ -0,0 +1,41 @@ +# Coding Conventions # +JPF is an open system. In order to keep the source format reasonably consistent, we strive to keep the following minimal set of conventions + + * Two space indentation (no tabs) + * Opening brackets in same line (class declaration, method declaration, control statements) + * No spaces after opening '(', or before closing ')' + * Method declaration parameters indent on column + * All files start with copyright and license information + * All public class and method declarations have preceding Javadoc comments + * We use *camelCase* instead of *underscore_names* for identifiers + * Type names are upper case + +The following code snippet illustrates these rules. + +~~~~~~~~ {.java} +/* + * + */ + +/** + * this is my class declaration example + */ + +public class MyClass { + + /** + * this is my public method example + */ + public void foo (int arg1, int arg2, + int arg3) { + if (bar) { + .. + } else { + .. + } + } + .. +} +~~~~~~~~ + +We consider modularity to be of greater importance than source format. With its new configuration scheme, there is no need to introduce dependencies of core classes towards optional extensions anymore. If you add something that is optional, and does not seamlessly fit into an existing directory, keep it separate by adding new directories. The core JPF classes should not contain any additional dependencies to external code. diff --git a/doc/devel/create_project.md b/doc/devel/create_project.md new file mode 100644 index 0000000..1eeb9b0 --- /dev/null +++ b/doc/devel/create_project.md @@ -0,0 +1,91 @@ +# Creating a New JPF Module # + +So what do you have to do to create a new JPF module? For a quick shortcut to setting up *most* things, use the `create_project` script of the [jpf-template module](wiki:projects/jpf-template). + +However, jpf-template cannot do everything for you, so see below for more information on how to finish setting up your new project. + +Several steps are involved: + +### 1. get familiar with the JPF configuration ### +You need to understand how your project will be looked up and initialized during JPF startup, and the place to learn that is the [JPF configuration](../user/config) page. Once you know what *[site properties](../install/site-properties)* and *project properties* are, you can proceed. + +### 2. get familiar with the standard JPF project layout ### +Although this is mostly convention, and you can deviate if you really need to, please try hard not to. + +You can get the details from the [JPF Runtime Modules](modules) page, but the essence is that each project has two (possible) major build artifacts: + + * `jpf-.jar` - executed by the host (platform) VM (contains main classes and peers) + * `jpf--classes.jar` - executed by JPF (contains modeled classes) + +Consequently, your sources are kept in `src/main`, `src/peers`, `src/classes`, `src/annotations`, `src/tests` and `src/examples`. You might only have some of these, but please provide regression tests so that people can check if your project works as expected. + +All 3rd party code that is required at runtime goes into a `lib` directory. + +We keep potential annotations separate (and provide additional `jpf--annotations.jar`) so that external projects (systems under test) can use them without relying on all JPF classes to be in their `classpath`. The idea is that this jar does not contain any code which could alter the system under test behavior if you execute it outside of JPF. + + + +### 3. create a jpf.properties file ### +Within the root directory of each JPF module a project properties file is needed which is named `jpf.properties`. It contains the path settings the host VM and JPF need to know about at runtime. It looks like this: + +~~~~~~~~ {.bash} +# standard header + = ${config_path} + +# classpath elements for the host VM (java) +.native_classpath = build/.jar;lib/... + +# classpath elements for JPF +.classpath = build/-classes.jar;... + +# sources JPF should know about when creating traces etc. +.sourcepath = src/classes;... +~~~~~~~~ + +You can add other JPF properties, but be aware of that this is always processed during JPF startup if you add your module to the `extensions` list in your [site.properties](../install/site-properties), and might conflict with other JPF modules. For this reason you should only add your module to `extensions` if you know it will always be used. + + +### 4. create your build.xml ### +Our build process is [Ant](http://ant.apache.org/) based, hence we need a `build.xml` file. The standard targets are + + * `clean` + * `compile` + * `build` (the default, creates the jars and hence depends on compile) + * `test` (run JUnit regression tests, depends on build) + * `dist` (creates a binary-only distribution) + +If you stick to the general layout, you can use a template like the one attached to this page (of course you need to replace ``). + +Please note how `site.properties` and `jpf.properties` can be used from within the `build.xml` (Ant understands a subset of the JPF property syntax), which means you don't have to explicitly add the jars of other JPF components you depend on (at least jpf-core). You can reference them symbolically like this: + +~~~~~~~~ {.xml} + + + .. + + + + + + ... + + + + + + + + ... +~~~~~~~~ + +### 5. add your module to your site.properties ### +This is optional, you only need to do this if you want to be able to run your JPF module outside its own directory. If so, add an entry to your [site properties file](../install/site-properties) that looks like this: + +~~~~~~~~ {.bash} +... + = +... +~~~~~~~~ + +### 6. publish your repository ### +You can publish this wherever you want ([sourceforge](http://sourceforge.net), [bitbucket](http://bitbucket.org), [google code](http://code.google.com), or [github](http://github.com) are suitable free site supporting Mercurial), or ask us to host it on the JPF server. If you decide to use a 3rd party hosting service, please let us/the JPF community know about it (e.g. by posting to the mailing list at [java-pathfinder@googlegroups.com](https://groups.google.com/forum/#!forum/java-pathfinder). \ No newline at end of file diff --git a/doc/devel/design.md b/doc/devel/design.md new file mode 100644 index 0000000..60e0fd3 --- /dev/null +++ b/doc/devel/design.md @@ -0,0 +1,52 @@ +# JPF Top-level Design # + +JPF was designed around two major abstractions: (1) the *VM*, and (2) the *Search* component. + +## Virtual Machine (VM) ## + +The VM is the state generator. By executing bytecode instructions, the VM generates state representations that can be + + * checked for equality (if a state has been visited before) + * queried (thread states, data values etc.) + * stored + * restored + +The main VM parameterizations are classes that implement the state management (matching, storing, backtracking). Most of the execution scheme is delegated to `SystemState`, which in turn uses `Scheduler` to generate scheduling sequences of interest. + +There are three key methods of the VM employed by the Search component: + + * `forward` - generate the next state, report if the generated state has a successor. If yes, store on a backtrack stack for efficient restoration. + * `backtrack` - restore the last state on the backtrack stack + * `restoreState` - restore an arbitrary state (not necessarily on the backtrack stack) + +![Figure: JPF top-level design](../graphics/jpf-abstractions.svg){align=center width=720} + +## Search Strategy ## + +At any state, the Search component is responsible for selecting the next state from which the VM should proceed, either by directing the VM to generate the next state (`forward`), or by telling it to backtrack to a previously generated one (`backtrack`). The Search component works as a driver for the VM. + +The Search component can be configured to check for certain properties by evaluating property objects (e.g. `NotDeadlockedProperty`, `NoAssertionsViolatedProperty`). + +The object encapsulating this component includes a search method which implements a strategy used to traverse the state space. The state space exploration continues until it is completely explored, or a property violation is found. + The Search component can be configured to use different strategies, such as depth-first search (`DFSearch`), and priority-queue based search that can be parameterized to do various search types based on selecting the most interesting state out of the set of all successors of a given state (`HeuristicSearch`). + +## Package Structure ## + +The implementation of the JPF core is partitioned into the following packages: + +### `gov.nasa.jpf` ### +The main responsibility of this package is configuration and instantiation of the core JPF objects, namely the Search and VM. The configuration itself is encapsulated by the `Config` class, which contains various methods to create objects or read values from a hierarchy of property files and command line options (see Configuring JPF Runtime Options). Beyond the configuration, the JPF object has little own functionality. It is mainly a convenience construct to start JPF from inside a Java application without having to bother with its complex configuration. + +### `gov.nasa.jpf.vm` ### +This package constitutes the main body of the core code, including the various constructs that implement the Java state generator. Conceptually, the major class is VM, but again this class delegates most of the work to a set of second level classes that together implement the major functionality of JPF. These classes can be roughly divided into three categories: + +(1) class management - classes are encapsulated by `ClassInfo` which mostly includes invariant information about fields and methods captured by `FieldInfo` and `MethodInfo`, respectively. + +(2) object model - all object data in JPF is stored as integer arrays encapsulated by `Fields` objects. The execution specific lock state of objects is captured by `Monitor` instances. `Fields` and `Monitor` instances together form the objects, which are stored as `ElementInfo`. The heap contains a dynamic array of `ElementInfo` objects where the array indices being used as object reference values + +(3) bytecode execution - the execution of bytecode instructions is performed through a collaboration of `SystemState` and `ThreadInfo`, which is also delegated to policy objects implementing the partial order reduction (POR). It starts with the `VM` object calling `SystemState.nextSuccessor()`, which descends into `ThreadInfo.executeStep()` (together, these two methods encapsulate the on-the-fly POR), which in turn calls `ThreadInfo.executeInstruction()` to perform the bytecode execution. +The actual execution is again delegated to bytecode specific Instruction instances that per default reside in a sub-package `gov.nasa.jpf.vm.bytecode` (the set of bytecode classes to use can be configured via a `InstructionFactory` class which allows the user to define a different execution semantics) + +### `gov.nasa.jpf.search` ### +This package is relatively small and mainly contains the `Search` class, which is an abstract base for search policies. The major method that encapsulates the policy is `Search.search()`, which is the VM driver (that calls the methods`forward`, `backtrack` and `restore`). This package also contains the plain-vanilla depth-first search policy `DFSearch`. +More policies can be found in the sub-package `gov.nasa.jpf.search.heuristic`, which uses a `HeuristicSearch` class in conjunction with configurable heuristic objects to prioritize a queue of potential successor states. diff --git a/doc/devel/eclipse_plugin_update.md b/doc/devel/eclipse_plugin_update.md new file mode 100644 index 0000000..35f663f --- /dev/null +++ b/doc/devel/eclipse_plugin_update.md @@ -0,0 +1,36 @@ +## Hosting an Eclipse plugin update site ## + +The first step is to create the local version of the update site. For example, chapter 18, section 3 of "Eclipse Plug-ins, 3rd edition" will explain how to do this. + +> **Tip:** do not attempt to put the update site in the code repository. + +The plugin and feature files are treated like binaries and bad things will happen. Here is a sample update site for the mango plugin. + +![Local Site](../graphics/localsite.jpg){align=center width=430} + +Now you will re-create this directory structure within the wiki. For the purpose of this discussion, let's pin down the jpf site: + +~~~~~~~~ {.bash} +JPFHOME=http://babelfish.arc.nasa.gov/trac/jpf +~~~~~~~~ + +Now chose a home directory, say `HOME`. For the mango plugin, + +~~~~~~~~ {.bash} +HOME=wiki/projects/jpf-mango +~~~~~~~~ + +Whatever choice of `HOME` you make, the update site you advertise to the world will be `JPFHOME/raw-attachment/HOME/update/`. + + +The `raw-attachment` segment is the *trick* that makes everything work out. The next step is to create the directory structure for the mirrored update site. Within `JPFHOME/HOME`, create a link to `JPFHOME/HOME/update`. Now go to the update page and add the attachments artifacts.jar, content.jar, and site.xml from your local update site. Create links within `JPFHOME/HOME/update` to `JPFHOME/HOME/update/features` and `JPFHOME/HOME/update/plugins`. + +Attach your feature jar to the features page, and your plugin jar to the plugins page. That's all there is to it. + +> **Tip:** when updating your update site, be sure to sync your plugin and feature with new, higher, revision numbers. Now rebuild the local site. Delete all the corresponding attachments in the wiki, and repopulate with the updated versions. + +> **Bonus tip:** Once everything is working, you can delete the link to the update site. This will prevent your visitors from accidentally going to an uninteresting page. You can always access this page directly from the browser by entering `JPFHOME/HOME/update`. + + + + diff --git a/doc/devel/embedded.md b/doc/devel/embedded.md new file mode 100644 index 0000000..0ddd1c3 --- /dev/null +++ b/doc/devel/embedded.md @@ -0,0 +1,27 @@ +# Embedded JPF # +JPF can also be used embedded, i.e. called from another Java application. A basic code sequence to start JPF looks like this: + +~~~~~~~~ {.java} +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.Config; + +void runJPF (String[] args) { + .. + MyListener listener = new MyListener(..); + + // [optionally] if you pass through command line args, + // 'null' any consumed args not to be JPF-processed + listener.filterArgs( args); + .. + + Config config = JPF.createConfig( args); + // set special config key/value pairs here.. + + JPF jpf = new JPF( config); + jpf.addListener( listener); + jpf.run(); + .. +} +~~~~~~~~ + +Of course, you can also call `gov.nasa.jpf.JPF.main(args)` from within your application, if you don't need to control JPF's configuration or process it's output. diff --git a/doc/devel/index.md b/doc/devel/index.md new file mode 100644 index 0000000..8394c9c --- /dev/null +++ b/doc/devel/index.md @@ -0,0 +1,23 @@ +# JPF Developer Guide # + +From the previous two sections, you have learned that JPF has one recurring, major theme: it is not a monolithic system, but rather a configured collection of components that implement different functions like state space search strategies, report generation and much more. Being adaptive is JPF's answer to the scalability problem of software model checking. + +This not only makes JPF a suitable system for research, but chances are that if are you serious enough about JPF application, you sooner or later end up extending it. This section includes the following topics which describe the different mechanisms that can be used to extend JPF. + + * [Top-level design](design) + * Key mechanisms, such as + - [ChoiceGenerators](choicegenerator) + - [Partial order reduction](partial_order_reduction) + - [Slot and field attributes](attributes) + * Extension mechanisms, such as + - [Listeners](listener) + - [Search Strategies](design) + - [Model Java Interface (MJI)](mji) + - [Bytecode Factories](bytecode_factory) + * Common utility infrastructures, such as + - [Logging system](loggin) + - [Reporting system](report) + * [Running JPF from within your application](embedded) + * [Writing JPF tests](jpf_tests) + * [Coding conventions](coding_conventions) + * [Hosting an Eclipse plugin update site](eclipse_plugin_update) \ No newline at end of file diff --git a/doc/devel/jpf_tests.md b/doc/devel/jpf_tests.md new file mode 100644 index 0000000..a445c5a --- /dev/null +++ b/doc/devel/jpf_tests.md @@ -0,0 +1,148 @@ +# Writing JPF Tests # + +As a complex runtime system for (almost) arbitrary Java programs, it goes without saying that JPF needs a lot of regression tests. You can find these under the `src/tests` directories in (hopefully) all JPF projects. All tests follow the same scheme, which is motivated by the need to run tests in a number of different ways: + + 1. as part of the Ant-based build system, i.e. from build.xml + 1. as explicitly invoked JUnit tests + 1. by directly running JPF on the test application (i.e. without JUnit, either as a JPF `shell` or via RunTest.jar) + 1. by running the test application on a normal JVM + +The rationale for this is to support various levels of inspection and debugging. + +Each test conceptually consists of a test driver (e.g. executed under JUnit) which starts JPF from within its `@Test` annotated methods, and a class that is executed by JPF in order to check the verification goals. For convenience reasons, jpf-core provides infrastructure that enables you to implement both parts in the same class. This can be confusing at first - **the test class is used to start JPF on itself**. + +![Figure: Unit Testing in JPF](../graphics/new-testing.svg){align=center width=870} + +The `main()` method of `TestJPF` derived classes always look the same and can be safely copied between tests: + +~~~~~~~~ {.java} +public static void main(String[] testMethods){ + runTestsOfThisClass(testMethods); +} +~~~~~~~~ + +This method serves two purposes. First, it is used to start the test outside JUnit, either on all `@Test` annotated instance methods, or just on the ones which names are provided as arguments. Second, it serves as the entry point for JPF when it executes the class. In this case, `TestJPF` takes care of invoking JPF on the test class and providing the name of the test method this was executed from. + +Other than that, test classes just consist of (almost) normal `@Test` annotated JUnit test methods, which all share the same structure + +~~~~~~~~ {.java} +import org.junit.Test; + +@Test public void testX () { + if (verifyNoPropertyViolation(JPF_ARGS){ + .. code to verify by JPF + } +} +~~~~~~~~ + +The trick is the call to `verifyNoPropertyViolation()`, or any of the other `verifyXX()` methods of `TestJPF`. If executed by the host VM, i.e. from JUnit, it starts JPF on the same class and the containing method, and returns `false`. This means the corresponding `if` block is **not** executed by the host VM. + +When JPF is invoked, the argument to the main() method is set to the method name from which JPF got invoked, which causes `runTestsOfThisMethod()` to execute exactly this method again, but this time under JPF. Instead of re-executing the same `TestJPF.verifyX()` method again (and becoming infinitely recursive), we use a native peer `JPF_gov_nasa_jpf_util_test_TestJPF` which intercepts the `verifyX()` call and simply returns true, i.e. this time *only* the `if` block gets executed. + +The rest of the host VM executed `TestJPF.verifyX()` checks the results of the JPF run, and accordingly throws an `AssertionError` in case it does not correspond to the expected result. The most common goals are + + * `verifyNoPropertyViolation` - JPF is not supposed to find an error + * `verifyPropertyViolation` - JPF is supposed to find the specified property violation + * `verifyUnhandledException` - JPF is supposed to detect an unhandled exception of the specified type + * `verifyAssertionError` - same for AssertionErrors + * `verifyDeadlock` - JPF is supposed to find a deadlock + +Each of these methods actually delegate running JPF to a corresponding method whose name does not start with 'verify..'. These workhorse methods expect explicit specification of the JPF arguments (including SUT main class name and method names), but they return JPF objects, and therefore can be used for more sophisticated JPF inspection (e.g. to find out about the number of states). + +`TestJPF` also provides some convenience methods that can be used within test methods to find out which environment the code is executed from: + + * `isJPFRun()` - returns true if the code is executed under JPF + * `isJUnitRun()` - returns true if the code is executed under JUnit by the host VM + * `isRunTestRun()` - returns true if the code is executed by RunTest.jar + +Here is an example of a typical test method that uses some of these features: + +~~~~~~~~ {.java} + @Test public void testIntFieldPerturbation() { + + if (!isJPFRun()){ // run this outside of JPF + Verify.resetCounter(0); + } + + if (verifyNoPropertyViolation("+listener=.listener.Perturbator", + "+perturb.fields=data", + "+perturb.data.class=.perturb.IntOverUnder",... + "+perturb.data.delta=1")){ + // run this under JPF + System.out.println("instance field perturbation test"); + + int d = data; // this should be perturbated + System.out.println("d = " + d); + + Verify.incrementCounter(0); + + } else { // run this outside of JPF + assert Verify.getCounter(0) == 3; + } + } +~~~~~~~~ + +## Running JPF tests from command line ## +To run JPF tests from the command line, use the RunTest.jar either from `jpf-core/build`, or the one that is distributed with your project containing the tests (`tools/RunTest.jar` for JPF projects). This is an executable jar that expects the test class and (optional) method test names as arguments. If no method names are provided, all `@Test` annotated methods are executed. Most projects have a convenience script `bin/test` to execute RunTest.jar. + +~~~~~~~~ {.bash} +> bin/test gov.nasa.jpf.test.mc.data.PerturbatorTest testIntFieldPerturbation + +......................................... testing testIntFieldPerturbation + running jpf with args: +listener=.listener.Perturbator +perturb.fields=data +perturb.data.class=.perturb.IntOverUnder +perturb.data.field=gov.nasa.jpf.test.mc.data.PerturbatorTest.data +perturb.data.delta=1 gov.nasa.jpf.test.mc.data.PerturbatorTest testIntFieldPerturbation +JavaPathfinder v5.x - (C) RIACS/NASA Ames Research Center + + +====================================================== system under test +application: gov/nasa/jpf/test/mc/data/PerturbatorTest.java +arguments: testIntFieldPerturbation + +====================================================== search started: 9/10/10 7:03 PM +instance field perturbation test +d = 43 +d = 42 +... +====================================================== search finished: 9/10/10 7:03 PM +......................................... testIntFieldPerturbation: Ok + +......................................... execution of testsuite: gov.nasa.jpf.test.mc.data.PerturbatorTest SUCCEEDED +.... [1] testIntFieldPerturbation: Ok +......................................... tests: 1, failures: 0, errors: 0 +~~~~~~~~ + +## Running JPF tests under JUnit ## + +This is the preferred way to execute JPF regression tests, which is usually done from an Ant build.xml script containing a standard target such as + +~~~~~~~~ {.xml} + ... + + ... + + + + + ... + + + + + + + + + +~~~~~~~~ + +Most JPF projects have build.xml files you can use as examples. + +Please note this means that you should not have any inner classes, interfaces, annotation types etc. with a name ending with `"Test"` since JUnit would interpret these as test cases and most likely complain about missing constructors and `main()` methods. + +## Debugging tests ## + +Typically, JPF tests are only executed from within an IDE if they fail and need to be debugged. + +Under NetBeans, this can be done by selecting the test class, and then executing the *Debug File* command from the context menu. This will pop up a dialog that lets you enter a specific test method to debug. This method requires a properly set up ide-file-target.xml, which comes with most JPF projects. + +Under Eclipse, you can select the test class and then execute **Debug As..** -> **Java Application**. diff --git a/doc/devel/listener.md b/doc/devel/listener.md new file mode 100644 index 0000000..98af48c --- /dev/null +++ b/doc/devel/listener.md @@ -0,0 +1,332 @@ +# Listeners # +Listeners are perhaps the most important extension mechanism of JPF. They provide a way to observe, interact with and extend JPF execution with your own classes. Since listeners are dynamically configured at runtime, they do not require any modification to the JPF core. Listeners are executed at the same level like JPF, so there is hardly any limit of what you can do with them. + +![Figure 1: JPF Listeners](../graphics/listener-overview.svg){align=center width=800} + +The general principle is simple: JPF provides an observer pattern implementation that notifies registered observer instances about certain events at the search level and the VM level. These notifications cover a broad spectrum of JPF operations, from low level events like `instructionExecuted` to high level events like `searchFinished`. Each notification is parameterized with the corresponding source (either the `Search` or the `VM` instance), which can be then used by the notified listener to obtain more information about the event and the JPF's internal state. + +Configuration is usually done with the `listener` property, either from the command line, or a .jpf property file. Listeners can also be associated with annotations, to be automatically loaded whenever JPF encounters such an annotation. Applications can use the `@JPFConfig` annotation to explicitly specify JPF listeners. Lastly, if JPF is used in an embedded mode, listeners can be registered with an API. + + +## Listener Types ## + + +There are two basic listener interfaces, depending on corresponding event sources: `SearchListeners` and `VMListeners`. Since these interfaces are quite large, and listeners often need to implement both, we also provide "adapter" classes, i.e. implementors that contain all required method definitions with empty method bodies. Concrete listeners that extend these adapters therefore only have to override the notification methods they are interested in. + +The adapter classes are used for the majority of listener implementations, especially since they also support two other interfaces/extension mechanisms that are often used in conjunction with `Search` and `VMListeners`: + + 1. `Property` - to define program properties + 2. `PublisherExtension` - to produce output within [the JPF reporting system](report) + +`ListenerAdapter` is the bare adapter implementation for `SearchListener`, `VMListener` and `PublisherExtension`. This is what is mostly used to collect information during JPF execution (e.g. `CoverageAnalyzer` and `DeadlockAnalyzer`). + +`PropertyListenerAdapter` is used in case the listener implements a program property, i.e. it can terminate the search process. A prominent example of this category is `PreciseRaceDetector`. + +![Figure 2: Listener Types](../graphics/listeners.svg){align=center width=800} + +Choosing the right type for your listener is important, since JPF automatically registers listeners (and properties) based on this type. You can bypass and directly implement single listener interfaces, but then you also have to do the proper registrations. + +Usually, the notification alone is not enough, and the listener needs to acquire more information from JPF. For this purpose, we provide either the `Search` or the `VM` instance as notification arguments, and the listener has to use these as "Facades" to query or interact JPF. It therefore matters to implement the listener within the right package. + + +## SearchListener ## + + +`SearchListener` instances are used to monitor the state space search process, e.g. to create graphical representations of the state-graph. They provide notification methods for all major Search actions. + +~~~~~~~~ {.java} +package gov.nasa.jpf.search; +public interface SearchListener extends JPFListener { + void searchStarted (Search search); + void stateAdvanced (Search search); // got next state + void stateProcessed (Search search); // state is fully explored + void stateBacktracked (Search search); // state was backtracked one step (same path) + void stateStored (Search search); // somebody stored the state + void stateRestored (Search search); // previously generated state was restored (any path) + void propertyViolated (Search search); // JPF encountered a property violation + void searchConstraintHit (Search search); // e.g. max search depth + void searchFinished (Search search); +}} +~~~~~~~~ + + +For the standard depth first search (`gov.nasa.jpf.search.DFSearch`), listener implementations can assume the following notification model: + + +![Figure 3: Depth first listener notifications](../graphics/DFSListener.svg){align=center width=500} + +The most frequently used notifications are: + +`stateAdvanced` - to store additional, backtrackable state information in an associative array + +`stateBacktracked` - to restore additional state information + +`searchFinished` - to process listener results + + +## VMListener ## + + +This is a fat interface, reflecting various VM operations + +~~~~~~~~ {.java} +package gov.nasa.jpf.jvm; +public interface VMListener extends JPFListener { + //--- basic bytecode execution + void executeInstruction (JVM vm); // JVM is about to execute the next instruction + void instructionExecuted (JVM vm); // JVM has executed an instruction + + //--- thread operations (scheduling) + void threadStarted (JVM vm); // new Thread entered run() + void threadBlocked (JVM vm); // thread waits to acquire a lock + void threadWaiting (JVM vm); // thread is waiting for signal + void threadNotified (JVM vm); // thread got notified + void threadInterrupted (JVM vm); // thread got interrupted + void threadTerminated (JVM vm); // Thread exited run() + void threadScheduled (JVM vm); // new thread was scheduled by JVM + + //--- class management + void classLoaded (JVM vm); // new class was loaded + + //--- object operations + void objectCreated (JVM vm); // new object was created + void objectReleased (JVM vm); // object was garbage collected + void objectLocked (JVM vm); // object lock acquired + void objectUnlocked (JVM vm); // object lock released + void objectWait (JVM vm); // somebody waits for object lock + void objectNotify (JVM vm); // notify single waiter for object lock + void objectNotifyAll (JVM vm); // notify all waiters for object lock + + void gcBegin (JVM vm); // start garbage collection + void gcEnd (JVM vm); // garbage collection finished + + void exceptionThrown (JVM vm); // exception was thrown + + //--- ChoiceGenerator operations + void choiceGeneratorSet (JVM vm); // new ChoiceGenerator registered + void choiceGeneratorAdvanced (JVM vm); // new choice from current ChoiceGenerator + void choiceGeneratorProcessed (JVM vm); // current ChoiceGenerator processed all choices +} +~~~~~~~~ + + +The most commonly used methods are the instruction notifications: + +`executeInstruction` - is called before a bytecode instruction gets executed by the VM. The listener can even use this to skip and/or replace this instruction, which is useful for non-invasive instrumentation. + +`instructionExecuted` - is the post-execution notification, which is suitable to keep track of execution results (method invocations, assigned field values, branch results etc.) + + +## Example ## + +The following example is a slightly abbreviated form our race detector. The basic idea is simple: every time we encounter a new scheduling point (i.e. new `ThreadChoiceGenerator` object) that is due to a field access on a shared object, we check if any of the other runnable threads is currently accessing the same field on the same object. If at least one operation is a `putfield`, we have a potential race. + +The example shows three aspects that are quite typical: + + 1. listeners often use only a small number of notification methods + + 2. they often do not require a huge amount of code (most expensive operations are performed by the `VM` and the `Search` objects) + + 3. sometimes you have to dig deep into JPF internal constructs, to extract things like `ThreadInfo`, `FieldInfo` and `ChoiceGenerator` instances + +~~~~~~~~ {.java} +public class PreciseRaceDetector extends PropertyListenerAdapter { + FieldInfo raceField; + ... + //--- the Property part + public boolean check(Search search, JVM vm) { + return (raceField == null); + } + + //--- the VMListener part + public void choiceGeneratorSet(JVM vm) { + ChoiceGenerator cg = vm.getLastChoiceGenerator(); + + if (cg instanceof ThreadChoiceFromSet) { + ThreadInfo[] threads = ((ThreadChoiceFromSet)cg).getAllThreadChoices(); + ElementInfo[eiCandidates = new ElementInfo[threads.length](]); + FieldInfo[fiCandidates = new FieldInfo[threads.length](]); + + for (int i=0; i= 0){ // yes, we have multiple accesses on the same object/field + Instruction otherInsn = threads[idx].getPC(); + if (isPutInsn(otherInsn) || isPutInsn(insn)) { + raceField = ((FieldInstruction)insn).getFieldInfo(); + .. + return; + } + } else { + eiCandidates[i] = ei; + fiCandidates[i] = fi; + } + } + } + } + } + } + + public void executeInstruction (JVM jvm) { + if (raceField != null) { // we're done, report as quickly as possible + ThreadInfo ti = jvm.getLastThreadInfo(); + ti.breakTransition(); + } + } +} +~~~~~~~~ + +## Instantiation ## + +Explicit instantiation of a listener (e.g. from a JPF shell) can be done in any way. If the listener is specified as a JPF property, it's class either needs to have a default constructor, or a constructor that takes a single `gov.nasa.jpf.Config` argument. The `Config` object that is passed into this constructor by JPF is the same that was used for the initialization of JPF itself. This is the preferred method if the listener has to be parameterized. In case of the `PreciseRaceDetector` example, this can be used to filter relevant fields with regular expressions: + +~~~~~~~~ {.java} +public class PreciseRaceDetector extends PropertyListenerAdapter { + ... + StringSetMatcher includes = null; + StringSetMatcher excludes = null; + + public PreciseRaceDetector (Config conf) { + includes = StringSetMatcher.getNonEmpty(conf.getStringArray("race.include")); + excludes = StringSetMatcher.getNonEmpty(conf.getStringArray("race.exclude")); + } + ... + public void choiceGeneratorSet(JVM vm) { + ... + FieldInfo fi =.. + if (StringSetMatcher.isMatch(fi.getFullName(), includes, excludes)) + ... + } +~~~~~~~~ + + +## Configuration ## + +Listener configuration can be done in a number of ways: via JPF properties from the command line or a .jpf file, via JPF APIs from a JPF shell (a program invoking JPF), or from the system under test by using Java annotations (i.e. without code modification). + +Since listeners are executed by the host VM, they have to be in the `CLASSPATH` (`jpf-core.native_classpath` property). + + +### command line ### + + +the *listener* property can be used to specify a colon separated list of listener class names: + +~~~~~~~~ {.bash} +bin/jpf ... +listener=x.y.MyFirstListener,x.z.MySecondListener ... +~~~~~~~~ + + +### .jpf property file ### + + +If you have several listeners and/or a number of other JPF options, it is more convenient to add the `listener` property to a .jpf file: + +~~~~~~~~ {.bash} +# Racer-listener.jpf - JPF mode property file to detect data races in jpftest.Racer +target = jpftest.Racer +listener=gov.nasa.jpf.tools.PreciseRaceDetector +~~~~~~~~ + + +### Autoload Annotations ### + + +Consider your system under test is marked up with a Java annotation that represent properties. For example, you can use the `@NonNull` annotation to express that a method is not allowed to return a `null` value: + +~~~~~~~~ {.java} +import gov.nasa.jpf.NonNull; + ... + @NonNull X computeX (..) { + //.. some complex computation + } + ... +~~~~~~~~ + +You can use .jpf property files (or the command line, if you love to type) to tell JPF that it should automatically load and register a corresponding listener (e.g. `NonNullChecker`) if it encounters such a `@NonNull` annotation during class loading: + +~~~~~~~~ {.bash} +.. +listener.autoload = gov.nasa.jpf.NonNull,... +listener.gov.nasa.jpf.NonNull = gov.nasa.jpf.tools.NonNullChecker +... +~~~~~~~~ + + +### @JPFConfig annotation (SuT) ### + + +You can also explicitly direct JPF to load the listener from within your application by using the `@JPFConfig` annotation: + +~~~~~~~~ {.java} +import gov.nasa.jpf.JPFConfig; +.. +// set JPF properties via properties at class load time +@JPFConfig ({"listener+=.tools.SharedChecker", ..}) +public class TestNonShared implements Runnable { + ... +} +~~~~~~~~ + +However, this is not recommended outside JPF tests - the application would run, but not compile without JPF. + + +### Verify API (SuT) ### + + +A less often used method is to set listeners is to use the `gov.nasa.jpf.vm.Verify` API from within your application. With this, you can control the exact load time of the listener (but be aware of backtracking). With this, the above example would become + +~~~~~~~~ {.java} +import gov.nasa.jpf.vm.Verify; +.. +public class TestNonShared implements Runnable { + ... + public static void main (String[] args){ + + // set JPF properties programmatically + Verify.setProperties("listener+=.tools.SharedChecker", ...); + .. + } +} +~~~~~~~~ + +This method should only be used in special cases (models written explicitly for JPF verification), since it does not run outside JPF. + + +### JPF API (embedded mode) ### + + +If JPF is explicitly started from within another application, listeners can be instantiated at will and configured via the `JPF.addListener(..)` API: + +~~~~~~~~ {.java} +MyListener listener=new MyListener(..); +.. +Config config = JPF.createConfig( args); +JPF jpf = new JPF( config); +jpf.addListener(listener); +jpf.run(); +.. +~~~~~~~~ + +Most listeners tend to fall into three major categories: + +1. system class (e.g. for logging) - is usually configured via the default.properties. +2. complex properties - is configured with an application specific mode property file. +3. JPF debugging - is specified via the command line (`+key=value` overrides). diff --git a/doc/devel/logging.md b/doc/devel/logging.md new file mode 100644 index 0000000..3993fdf --- /dev/null +++ b/doc/devel/logging.md @@ -0,0 +1,31 @@ +# The JPF Logging API # +There is one simple rule: do not use `System.out` or `System.err` for any permanent logging + + +Of course we all do this temporarily during debugging, but it really shouldn't stay in the code. The logging infrastructure is quite easy to use. Just declare a static `Logger` instance with an appropriate id (either package or logging topic) at the top of your class, and then use the `Logger` API to create output: + +~~~~~~~~ {.java} +... +import java.util.logging.Level; +import java.util.logging.Logger; + +package x.y.z; + +class MyClass .. { + static Logger log = JPF.getLogger("x.y.z"); + ... + log.severe("there was an error"); + ... + log.warning("there was a problem"); + ... + log.info("something FYI"); + ... + if (log.isLoggable(Level.FINE)){ // (1) don't create garbage + log.fine("this is some detailed info about: " + something); + } + ... +} +~~~~~~~~ + +Note that there is only one instance for each `Logger` ID, i.e. you can have a corresponding static field in all your relevant classes, and don't have to share the fields. Another aspect that is mostly important for the lower log levels (e.g. `FINE`) is that you should't concatenate log messages in operations that occur frequently, since the corresponding `StringBuilder` instances can cause performance degradations even if the log level is not set (the arguments still get evaluated). In this case, encapsulate the logging in `log.isLoggable(level){..}` blocks. + diff --git a/doc/devel/mercurial.md b/doc/devel/mercurial.md new file mode 100644 index 0000000..b1b3051 --- /dev/null +++ b/doc/devel/mercurial.md @@ -0,0 +1,56 @@ +# Mercurial in 5 Minutes # + +[Mercurial](http://www.selenic.com/mercurial) is a *distributed version control system* (DVCS) of the same category such as the likes of [Git](http://git-scm.com/) or [Bazaar](http://bazaar.canonical.com/en/). If you know nothing else about DVCS, this means mostly one thing - **all repositories are created equal**. There is no such thing as a different repository format for public and private repositories. All repositories (that are synchronized) have the same, stored history information. + +Yes, this means you can finally synchronize your working repos with more than one "master" repository, e.g. with several local ones, closed workgroup repos, and a public master repo (that just happens to be designated as such). + +Each Mercurial repository consists of an (optional) working copy of your files, and a `.hg` directory in your repo root dir that holds all the version control info. Be careful not to delete the `.hg` dir, otherwise your repo is reduced to just a snapshot of your current working files. + +A central concept of DVCS is the *change set* - think of it as the diff of all files that have been changed when you do a commit. This is what DVCS store (e.g. Mercurial in the `.hg` dir) and compare between different repositories. One implication of this is that you can't do partial commits like in CVS or SVN (e.g. by just committing changes within a certain subdirectory). You always have to execute the Mercurial commands in the top dir of the repository you are working in. + +If you have previously worked with CVS or SVN, another difference you have to wrap your head around is that there are commands that work locally, and commands that interact with the remote repo. __The `commit` and `update` commands are only local__. The `push` and `pull` commands synchronize your local repo with an external one (like commit and update did in CVS/SVN). + +Here are the main commands to interact with Mercurial: + +![](mercurial.png) + +**hg clone ** - this is the first command that clones an external repository (either from `file:///...` or `http://...` URLs). It creates both a working copy and the `.hg` directory (with contents) + +**hg init** - is what you do if you create a local repository for which there is no external one yet. Just create your files, `cd` into the top directory, and execute the command (which will create the `.hg` for you) + +**hg pull [-u] ** - updates the repo you are currently in from the provided URL. Note that your working copy is only updated if you use the `-u` option + +**hg incoming ** - is the little brother of `pull`. It just tells you if there are changesets in the remote repository you would pull + +**hg status** - tells you if there are uncommitted changes in your working copy that have to be committed to the local `.hg` directory before you can `push` or `pull` + +**hg diff** - does a bit more, it also shows you a diff file with the uncommitted changes + +**hg add ** - adds a file to the repo + +**hg remove ** - removes a file from the repo + +**hg addremove** - adds all new files of the working copy that are not in the repository yet, and removes all which are not in the working copy anymore + +**hg commit** - saves changes in your working copy to your local `.hg`. Do this early and often, this is now just a local operation that doesn't change anything outside the repo you are working with + +**hg update** - would update your working copy from your local `.hg`. It is rarely used if you pull with the `-u` option + +**hg push ** - pushes the relevant changesets of your local `.hg` back to the external repo with the provided URL. Make sure you have no uncommitted changes (Mercurial would refuse to push), and - in case the external repo is shared - that you pulled/merged all changesets of the external repo before you push + +**hg outgoing ** - is the dry run version of a push, it tells you if there are changesets that would have to be pushed + +**hg revert** - reverts your working copy to a previous version stored in your local `.hg` + +**hg heads** - tells you if there are branches in your repo, which usually happens if you pull from a changed external repo while having un-pushed local changes that are committed + +**hg merge** - gets rid of multiple heads. Make sure to get rid of these by merging as soon as you detect them, it only gets more difficult with more external and local changes. Once there are collisions, you are back to the CVS/SVN merge mess + +You can always obtain more information by executing +~~~~~~~~ +#!sh +> hg help [command] +~~~~~~~~ +If you don't list a command, all available ones will be displayed. + +Commands that refer to external repos take URLs such as `http://babelfish.arc.nasa.gov/hg/jpf/jpf-core` as arguments. diff --git a/doc/devel/mji.md b/doc/devel/mji.md new file mode 100644 index 0000000..817cdd1 --- /dev/null +++ b/doc/devel/mji.md @@ -0,0 +1,214 @@ +# Model Java Interface (MJI) # +## Purpose ## + +Even if it is just a Java application (i.e. solely consists of Java classes), JPF can be viewed as a Java Virtual Machine (JVM) in itself. The consequence is that (*.class) class files, and even the same files at times, are processed in two different ways in a JVM running JPF + + * as ordinary Java classes managed and executed by the host JVM (standard Java library classes, JPF implementation classes) + * as "modeled" classes managed and processed (verified) by JPF + +Class lookup in both layers is based on the CLASSPATH environment variable / command line parameter, but this should not obfuscate the fact that we have to clearly distinguish between these two modes. In particular, JPF (i.e. the "Model" layer) has its own class and object model, which is completely different and incompatible to the (hidden) class and object models of the underlying host JVM executing JPF + +![Figure 1: JPF Layers](../graphics/jpf-layers.svg){align=center width=560} + +Each standard JVM supports a so called Java Native Interface (JNI), that is used to delegate execution from the Java level (i.e. JVM controlled bytecode) down into the (platform dependent) native layer (machine code). This is normally used to interface certain functionalities to the platform OS / architecture (e.g. I/O or graphics). + +Interestingly enough, there exists a analogous need to lower the "execution" level in JPF, from JPF controlled bytecode into JVM controlled bytecode. According to this analogy, the JPF specific interface is called Model Java interface (MJI). + +Even though MJI offers a wide range of applications, there are three major usages for delegating bytecode execution into the host JVM: + + 1. Interception of native methods - without a abstraction lowering mechanism, JPF would be forced to completely ignore native methods, i.e. would fail on applications relying on the side effects of such methods, which is not acceptable (even if many native methods indeed can be ignored if we restrict the set of verification targets) + + 2. Interfacing of JPF system level functionality - some system level functions of standard library classes (esp. java.lang.Class, java.lang.Thread) have to be intercepted even if they are not native because they have to affect the JPF internal class, object and thread model (etc. loading classes, creating / starting threads). It should be noted that MJI can also be used to extend the functionality of JPF without changing its implementation. + +3. State space reduction - by delegating bytecode execution into the non-state-tracked host JVM, we can cut off large parts of the state space, provided that we know the corresponding method side effects are not relevant for property verification (e.g. `System.out.println(..)`) + +Besides these standard usages, there exist more exotic applications like collecting information about JPF state space exploration and making it available both to JPF and the verification target. + + +## MJI Components ## + + +The basic functionality of MJI consists of a mechanism to intercept method invocations, and delegate them by means of Java reflection calls to dedicated classes. There are two types of classes involved, residing at different layers: + + * Model Classes - these classes execute by the VM of JPF, which might be completely unknown to the host JVM + * Native Peers - these classes, implemented by `NativePeer` subclasses, contain the implementations of the methods to intercept, and to execute by the host JVM + +As part of the JPF implementation, MJI automatically takes care of determining which method invocations have to be intercepted by looking up the corresponding native peer methods + +![Figure 2: MJI Functions](../graphics/mji-functions.svg){align=center width=600} + +This would not be very useful without being able to access the JPF object model (or other JPF intrinsics), from inside the native peer methods. Instead of requiring all native peers implementation to reside in a JPF internal package, there exists an interface class `MJIEnv` that provide access to the JPF internal structure in a controlled way. `NativePeer` classes residing in `gov.nasa.jpf.vm` (i.e. the same package as `MJIEnv`) can reach all internal JPF features. Outside this package, the available API in `MJIEnv` is mostly restricted to the access JPF object (getting and setting values). + +![Figure 3: MJI Call Sequence](../graphics/mji-call.svg){align=center width=580} + +Before a native peer method can be used, JPF has to establish the correspondence between the model class and the native peer. This takes place at load time of the model class. MJI uses a special name mangling scheme to lookup native peers, using the model class package name and class name to deduce the native peer class name. + +![Figure 3: MJI name mangling](../graphics/mji-mangling.svg){align=center width=560} + +Since the model class package is encoded in the native peer name, the package of the native peer can be chosen freely. In analogy to JNI, native peers methods names include the signature of the model method by encoding its parameter types. If there is no potential ambiguity, i.e. mapping from native peer methods to model class methods is unique, signature encoding is not required. + +Each native peer, which is an instance of a `NativePeer` subclass, is associated with exactly one `ClassInfo` instance. +All the native peer methods to be intercepted have to be `public` and annotated with `gov.nasa.jpf.annotation.MJI`. +Moreover, MJI requires them to have two parameters: + + * An instance of `MJIEnv` which can be used to access JPF internal constructs + * An integer which is a handle for the corresponding JPF `this` object (or the `java.lang.Class` object in case of a static method) including the method to be intercepted + +See [Mangling for MJI](mji/mangling) for more details and examples of mangling. + +Going beyond the JNI analogy, MJI can also be used to intercept + + * non-native methods (i.e. the lookup process is driven by the methods found in the native peer, not the `native` attributes in the model class. This can be particularly useful in case the class is used from both as a model class and a JVM class (e.g. `gov.nasa.jpf.vm.Verify`), using a method body that directly refers to the native peer + * class initialization (the corresponding native peer method has to be named `$clinit(MJIEnv env, int clsRef)`) + * constructors (the corresponding native peer method has to be named `$init__(MJIEnv env,int objRef, )` and the normal signature mangling rules apply) + + +It is important to note that type correspondence does NOT include references. All references (object types) on the JPF side are transformed in handles (int values) on the JVM side. The passed in `MJIEnv` parameter has to be used to convert/analyze the JPF object. Since MJI per default uses the standard Java reflection call mechanism, there is a significant speed penalty (lookup, parameter conversion etc.), which again is a analogy to JNI. + +Even if it is not directly related to MJI, it should be mentioned that some JPF specific model classes cannot be loaded via the CLASSPATH (e.g. `java.lang.Class`), since they contain JPF based code that is not compatible with the host JVM (e.g. relying on native methods that refer to JPF functionality). Such classes should be kept in separate directories / jars that are specified with the JPF command line option `-jpf-bootclasspath` or `-jpf-classpath`. This is mostly the case for system classes. On the other hand, model classes don't have to be JPF specific. It is perfectly fine to provide a native peer for a standard Java class (e.g. `java.lang.Character`), if only certain methods from that standard class needs to be intercepted. Native peers can contain any number of non-"native" methods and fields, but those should not be annotated with `@MJI` to avoid lookup problems. + +## Tools ## + +To ease the tedious process of manually mangle method names, MJI includes a tool to automatically create skeletons of native peers from a given Model class, called `GenPeer`. The translation process uses Java reflection, i.e. the model class needs to be in the CLASSPATH and is specified in normal dot notation (i.e. not as a file). + +![Figure 4: The GenPeer tool](../graphics/genpeer.svg){align=center width=470} + +There exist a number of command line options that can be displayed by calling `GenPeer` without arguments. `GenPeer` per default writes to stdout, i.e. the output has to be redirected into a file. + +Since method invocation by reflection used to be a slow operation, we previously also had a tool called `GenPeerDispatcher`, which used method signature hash-codes to explicitly dispatch native peer methods. With recent improvements in JVM performance, this tool became obsolete. + + +## Example ## + + +The following example is an excerpt of a JPF regression test, showing how to intercept various different method types, and using `MJIEnv` to access JPF objects. + + +### Model class (JPF side) ### + + +This is executed by JPF, which means it needs to be in JPF's `vm.classpath` setting. + +~~~~~~~~ {.java} +public class TestNativePeer { + static int sdata; + + static { + // only here to be intercepted + } + + int idata; + + TestNativePeer (int data) { + // only here to be intercepted + + } + + public void testClInit () { + if (sdata != 42) { + throw new RuntimeException("native 'clinit' failed"); + } + } + + public void testInit () { + TestNativePeer t = new TestNativePeer(42); + + if (t.idata != 42) { + throw new RuntimeException("native 'init' failed"); + } + } + + native int nativeInstanceMethod (double d, char c, boolean b, int i); + + public void testNativeInstanceMethod () { + + int res = nativeInstanceMethod(2.0, '?', true, 40); + if (res != 42) { + throw new RuntimeException("native instance method failed"); + } + } + + native long nativeStaticMethod (long l, String s); + + public void testNativeStaticMethod () { + long res = nativeStaticMethod(40, "Blah"); + + if (res != 42) { + throw new RuntimeException("native instance method failed"); + + } + } + + native void nativeException (); + + public void testNativeException () { + try { + nativeException(); + } catch (UnsupportedOperationException ux) { + String details = ux.getMessage(); + + if ("caught me".equals(details)) { + return; + } else { + throw new RuntimeException("wrong native exception details: " + + details); + } + } catch (Throwable t) { + throw new RuntimeException("wrong native exception type: " + + t.getClass()); + } + + throw new RuntimeException("no native exception thrown"); + } + } +~~~~~~~~ + + +### Native Peer class (host VM side) ### + + +This is executed by the host VM (i.e. at the same level like JPF itself), so make sure it is in your CLASSPATH. + +~~~~~~~~ {.java} +public class JPF_gov_nasa_jpf_vm_TestNativePeer { + + @MJI + public static void $clinit (MJIEnv env, int rcls) { + env.setStaticIntField(rcls, "sdata", 42); + } + + @MJI + public static void $init__I (MJIEnv env, int robj, int i) { + env.setIntField(robj, "idata", i); + } + + // preferably use full signature mangling + @MJI + public static int nativeInstanceMethod__DCZI__I (MJIEnv env, int robj, + double d, char c, + boolean b, int i) { + if ((d ## 2.0) && (c ## '?') && b) { + return i + 2; + } + return 0; + } + + //..but it also works without, if there is no overloading (don't be lazy!) + @MJI + public static long nativeStaticMethod (MJIEnv env, int rcls, + long l, int stringRef) { + String s = env.getStringObject(stringRef); + if ("Blah".equals(s)) { + return l + 2; + } + return 0; + } + + @MJI + public static void nativeException____V (MJIEnv env, int robj) { + env.throwException("java.lang.UnsupportedOperationException", + "caught me"); + } + } +~~~~~~~~ + diff --git a/doc/devel/mji/mangling.md b/doc/devel/mji/mangling.md new file mode 100644 index 0000000..5e2847a --- /dev/null +++ b/doc/devel/mji/mangling.md @@ -0,0 +1,200 @@ +# Mangling for MJI # +## Mangling Methods ## +Suppose your method looks like + +~~~~~~~~ {.java} +T1 foo(T2 x, T3 y, ...) +~~~~~~~~ + +where the `Ti` are Java types. + +If `T1` is a primitive type or `void`, then the mangled MJI method looks +like + +~~~~~~~~ {.java} +public static T1 foo__MT2MT3...__MT1(...) +~~~~~~~~ + +where the `MTi` are the mangled versions of the `Ti`. +Mangling of types is described in the Mangling Types section below. +Note that `T1` appears twice, once not mangled (`T1`) and once mangled +(`MT1`). The `__` is two consecutive underscores: `_` followed by +`_`. + +As a not-so-special case, if `foo` has no arguments, then the mangled method +will have four consecutive underscores: + +~~~~~~~~ {.java} + `T1 foo()`[[br]] +~~~~~~~~ + +goes to + +~~~~~~~~ {.java} + `public static T1 foo____MT1(...)` +~~~~~~~~ + +If `T1` is not a primitive type, then the mangled `MJI` method looks like + +~~~~~~~~ {.java} + `public static int foo__MT2MT3...__MT1` +~~~~~~~~ + +where the `MTi` are as above. Note that `T1` only appears once in this +case. The method's return type is `int`. As before, a method with no +arguments gets mangled to something with four consecutive underscores. + +Also, the use of generics is ignored when mangling names. + + +## Mangling Constructors ## +Constructors are treated as methods named `$init` with return type `void`. + + +## Mangling Static Initializers ## +Static initializers are treated as methods named `$clinit` with no +arguments and return type `void`. Thus, their MJI versions always +have the mangled signature: + +~~~~~~~~ {.java} +public static void $clinit____V (MJIEnv env, int clsObjRef) +~~~~~~~~ + +or the equivalent unmangled signature: + +~~~~~~~~ {.java} +public static void $clinit (MJIEnv env, int clsObjRef) +~~~~~~~~ + + +## Mangling Types ## + - Convert primitives and `void` as follows + + |Java Type|Mangled Type| + | ------- |:---:| + |`boolean`|`Z`| + |`byte` |`B`| + |`char` |`C`| + |`short` |`S`| + |`int` |`I`| + |`long` |`J`| + |`float` |`F`| + |`double` |`D`| + |`void` |`V`| + + - Convert a non-array reference type `T` in package `x.y` + (e.g. `java.lang.String`) as follows + - `x.y.T` --> `Lx_y_T_2` + - Example: `java.lang.String` --> `Ljava_lang_String_2` + + - Convert an array of primitive type `T` + (e.g. `byte[]`) as follows: + - `T[]` --> `_3MT` where `MT` is the mangled version of `T` + (e.g. for `T=byte`, `MT=B`) + - Example: `byte[]` --> `_3B` + + - Convert an array of reference type `T` in package `x.y` + (e.g. `java.lang.String[]`) as follows: + - `x.y.T[]` --> `_3Lx_y_T_2` + - Example: `java.lang.String[]` --> `_3Ljava_lang_String_2` + + +## Method Examples ## + + `void` return type, single primitive argument: + +~~~~~~~~ {.java} + public static void resetCounter(int id) +--> + public static final void resetCounter__I__V(MJIEnv env, int objref, int id) +~~~~~~~~ + + Primitive return type, no arguments: + +~~~~~~~~ {.java} + public native boolean isArray() +--> + public static boolean isArray____Z(MJIEnv env, int objref) +~~~~~~~~ + + Primitive return type, single primitive argument: + +~~~~~~~~ {.java} + public static double abs(double a) +--> + public static double abs__D__D(MJIEnv env, int clsObjRef, double a) +~~~~~~~~ + + Primitive return type, two primitive arguments: + +~~~~~~~~ {.java} + public static long min(long a, long b) +--> + public static long min__JJ__J(MJIEnv env, int clsObjRef, long a, long b) +~~~~~~~~ + + + `void` return type, arguments include an array of a primitive type: + +~~~~~~~~ {.java} + public native void write (byte[] buf, int off, int len); +--> + public static void write___3BII__V(MJIEnv env, int objref, + int bufRef, int off, int len) +~~~~~~~~ + + + `void` return type, argument is an array of a reference type: + +~~~~~~~~ {.java} + public static void print(String s) +--> + public static void print___3Ljava_lang_String_2__V(MJIEnv env, int clsRef, int argsRef) +~~~~~~~~ + + Array of reference types returned, no arguments: + +~~~~~~~~ {.java} + public native Annotation[] getAnnotations() +--> + public static int getAnnotations_____3Ljava_lang_annotation_Annotation_2(MJIEnv env, int robj) +~~~~~~~~ + Notice there are 5 underscores before the `3L`: two marking the + arguments, two marking the return type, and one from the `_3` + signalling an array. + + Array of reference types using generics returned, no arguments: + +~~~~~~~~ {.java} + public native Class[] getParameterTypes() +--> + public static int getParameterTypes_____3Ljava_lang_Class_2(MJIEnv env, int objref) +~~~~~~~~ + +Note: the use of generics is ignored in the mangling. + + + +## Constructor Examples ## + +Constructors are treated as though they were methods named `$init` +returning `void`, so the method examples above should also be helpful +for constructors. Here are a few more examples. + +In the class `ConsoleOutputStream`: + +~~~~~~~~ {.java} + public ConsoleOutputStream() +--> + public static void $init____V(MJIEnv env, int objref) +~~~~~~~~ + +In the class `AtomicLongFieldUpdater`: + +~~~~~~~~ {.java} + protected AtomicLongFieldUpdater(Class objClass, String fieldName) +--> + public static void $init__Ljava_lang_Class_2Ljava_lang_String_2__V + (MJIEnv env, int objRef, + int tClsObjRef, int fNameRef) +~~~~~~~~ diff --git a/doc/devel/modules.md b/doc/devel/modules.md new file mode 100644 index 0000000..45e84d7 --- /dev/null +++ b/doc/devel/modules.md @@ -0,0 +1,21 @@ +# JPF Runtime Modules # + +JPF is partitioned into separate projects that all follow the same directory layout and build process. Modules can be distributed as source or binary distributions. Binary distributions are just slices through the directory tree of a source distribution that preserve the permanent build artifact, i.e. both distribution forms are runtime-compatible. + +![Figure: JPF Modules](../graphics/jpf-project.svg){align=center width=750} + +The main artifacts are the *.jar files created and stored in the `build` directory. We can divide this into classes that are executed by the host VM (i.e. have to be in JPF's `native_classpath` setting), and classes that are executed by JPF itself (i.e. have to be in JPF's `classpath` setting). The first category includes [listeners](listener) and [native peers](mji), the second one model classes (compiled from `src/classes`) and annotations, i.e. the system under test code. + +The build process is [Ant](http://ant.apache.org/) based, which means every source distribution comes with a build.xml script that implements the basic build targets `clean`, `compile`, `build` and `test`. + +We do not include required 3rd party runtime and build libraries in the project distributions. +The `compile` Ant target uses the standard `javac` command which requires a full JDK installation. `test` generally executes a JUnit based regression test suite. Both JUnit and Ant libraries are also need to be installed. + + + + + + + +For convenience reasons, JPF modules come with corresponding NetBeans and Eclipse configurations, i.e. can be directly opened as projects within these IDEs. + diff --git a/doc/devel/partial_order_reduction.md b/doc/devel/partial_order_reduction.md new file mode 100644 index 0000000..7077a48 --- /dev/null +++ b/doc/devel/partial_order_reduction.md @@ -0,0 +1,67 @@ +# On-the-fly Partial Order Reduction # + +The number of different scheduling combinations is the prevalent factor for the state space size of concurrent programs. Fortunately, for most practical purposes it is not necessary to explore all possible instruction interleavings for all threads. The number of scheduling induced states can be significantly reduced by grouping all instruction sequences in a thread that cannot have effects outside this thread itself, collapsing them into a single transition. This technique is called partial order reduction (POR), and typically results in more than 70% reduction of state spaces. + +JPF employs an on-the-fly POR that does not rely on user instrumentation or static analysis. JPF automatically determines at runtime which instructions have to be treated as state transition boundaries. If POR is enabled (configured via `vm.por` property), a forward request to the VM executes all instructions in the current thread until one of the following conditions is met: + + - the next instruction is scheduling relevant + - the next instruction yields a "nondeterministic" result (i.e. simulates random value data acquisition) + +Detection of both conditions are delegated to the instruction object itself (`Instruction.execute()`), passing down information about the current VM execution state and threading context. If the instruction is a transition breaker, it creates a ChoiceGenerator and schedules itself for re-execution. + +~~~~~~~~ {.java} +executeStep () { + .. + do { + if ((nextPc # executeInstruction()) #= pc) { + break; + } else { + pc = nextPc; + } + .. + } while (pc != null); + .. +} +~~~~~~~~ + +Each bytecode instruction type corresponds to a concrete gov.nasa.jpf.Instruction subclass that determines scheduling relevance based on the following factors: + + * **Instruction Type** - due to the stack based nature of the JVM, only about 10% of the Java bytecode instructions are scheduling relevant, i.e. can have effects across thread boundaries. The interesting instructions include direct synchronization (`monitorEnter`, `monitorexit`, `invokeX` on synchronized methods), field access (`putX`, `getX`), array element access (`Xaload`, `Xastore`), and invoke calls of certain Thread (`start()`, `sleep()`, `yield()`, `join()`) and Object methods (`wait()`, `notify()`). + * **Object Reachability** - besides direct synchronization instructions, field access is the major type of interaction between threads. However, not all putX / getX instructions have to be considered, only the ones referring to objects that are reachable by at least two threads can cause data races. While reachability analysis is an expensive operation, the VM already performs a similar task during garbage collection, which is extended to support POR. + * **Thread and Lock Information** - even if the instruction type and the object reachability suggest scheduling relevance, there is no need to break the current transition in case there is no other runnable thread. In addition, lock acquisition and release (`monitorenter`, `monitorexit`) do not have to be considered as transition boundaries if there they happen recursively - only the first and the last lock operation can lead to rescheduling. + +![Figure 1: Scheduling Relevance Filters](../graphics/por-scheduling-relevance.svg){align=center width=650} + +While JPF uses these informations to automatically deduce scheduling relevance, there exist three mechanisms to explicitly control transition boundaries (i.e. potential thread interleavings) + + 1. `Attributor` - a configurable concrete class of this type is used by JPF during class loading to determine object, method and field attributes of selected classes and class sets. The most important attributes with respect to POR are method atomicity and scheduling relevance levels: (a) never relevant, (b) always scheduling relevant, (c) only relevant in the context of other runnables. (d) only relevant of top-level lock. The default Attributor executes all java code atomically, which is can be too aggressive (i.e. can cause `BlockedAtomicExceptions`). + + 2. `VMListener` - a listener can explicitly request a reschedule by calling `ThreadInfo.yield()` in response of a instruction execution notification. + + 3. `Verify` - a class that serves as an API to communicate between the test application and JPF, and contains `beginAtomic()`, `endAtomic()` functions to control thread interleaving + +The main effort of JPFs POR support relates to extending its precise mark and sweep collector. POR reachability is a subset of collector reachability, hence the mechanism piggybacks on the mark phase object traversal. It is complicated by the fact that certain reference chains exist only in the (hidden) VM implementation layer. For instance, every thread has a reference to its ThreadGroup, and the ThreadGroup objects in turn have references to all included threads, hence - from a garbage collection perspective - all threads within a group are mutually reachable. If the application under test does not use Java reflection and runtime queries like thread enumeration, POR reachability should follow accessibility rules as closely as possible. While JPF's POR does not yet support protected and private access modifiers, it includes a mechanism to specify that certain fields should not be used to promote POR reachability. This attribute is set via the configured Attributor at class load time. + +![Figure 2: Mark Phase of Reachability Analysis](../graphics/por-mark.svg){align=center width=460} + +With this mechanism, calculating POR reachability becomes a straight forward approach that is divided into two phases. Phase 1 non-recursively marks all objects of the root set (mostly static fields and thread stacks), recording the id of the referencing thread. In case an object is reachable from a static field, or from two threads, it's status is set to shared. Phase 2 recursively traverses all heap objects, propagating either a set shared status or the referencing thread id through all reference fields that are not marked as reachability firewalls. Again, if the traversal hits an object that is already marked as referenced by another thread, it promotes the object status to shared, and from there propagates the shared status instead of the thread id. + +To further reduce irrelevant context switches, JPF can check for lock protection to determine if a field access is scheduling relevant. If the property `vm.por.sync_detection` is set to true, JPF looks for potential lock candidates when analyzing `GET_x/SET_x` instructions. The policy of detecting lock candidates is configurable with the property `vm.por.fieldlockinfo.class`, the default `gov.nasa.jpf.jvm.StatisticFieldLockInfo` just defers the decision by recording the set of locks held when executing the field instruction, computing the set intersection at subsequent accesses. If the set does not get empty for a configurable number of field accesses, the field is marked as lock protected, and henceforth not treated as transition boundary. If however the set should afterwards become empty, a warning like + +~~~~~~~~ {.bash} +Warning: unprotected field access of: Event@70.count in thread: "Thread-1" oldclassic.java:107 + sync-detection assumed to be protected by: Event@70 + found to be protected by: {} + >>> re-run with 'vm.por.sync_detection=false' or exclude field from checks <<< +~~~~~~~~ + +is issued, and the field access is again treated as transition breaker. + +The set of fields to be analyzed can be specified with the properties `vm.por.include_fields` and `vm.por.exclude_fields`. Per default, fields of system library classes are not analyzed (this is esp. useful to avoid context switches for global objects like `System.out`). + +Even with all these optimizations, some unwanted transition breakers are likely to remain. This is mostly due to two constraints: + + * JPF only considers reachability, not accessibility + * write once, read multiple conditions cannot be detected a priori for fields that are not final, or inside immutable objects (like `java.lang.String`) + +Especially the last issue might be subject to further enhancements diff --git a/doc/devel/report.md b/doc/devel/report.md new file mode 100644 index 0000000..aecfd6b --- /dev/null +++ b/doc/devel/report.md @@ -0,0 +1,70 @@ +# The JPF Report API # +The JPF report system consists of three major components: + + - the `Reporter` + - any number of format specific `Publisher` objects + - any number of tool-, property-, Publisher-specific `PublisherExtension` objects + +Here is the blueprint: + +![Figure: JPF Report System](../graphics/report.svg){align=center width=800} + +The `Reporter` is the data collector. It also manages and notifies `Publisher` extensions when a certain output phase is reached. The `Publishers` are the format (e.g. text, XML) specific output producers, the most prominent one being the `ConsolePublisher` (for normal, readable text output on consoles). `PublisherExtensions` can be registered for specific `Publishers` at startup time, e.g. from Listeners implementing properties or analysis modes such as `DeadlockAnalyzer`. This is so common that the `ListenerAdapter` actually implements all the required interface methods so that you just have to override the ones you are interested in. + +Configuration is quite easy, and involves only a handful of JPF properties that are all in the report category. The first property specifies the Reporter class itself, but is not likely to be redefined unless you have to implement different data collection modes. + +~~~~~~~~ {.bash} +report.class=gov.nasa.jpf.report.Reporter +~~~~~~~~ + +The next setting specifies a list of Publisher instances to use, using symbolic names: + +~~~~~~~~ {.bash} +report.publisher=console,xml +~~~~~~~~ + +Each of these symbolic names has to have a corresponding class name defined: + +~~~~~~~~ {.bash} +report.console.class=gov.nasa.jpf.report.ConsolePublisher +~~~~~~~~ + +Finally, we have to specify for each symbolic publisher name and output phase what topics should be processed in which order, e.g. + +~~~~~~~~ {.bash} +report.console.property_violation=error,trace,snapshot +~~~~~~~~ + +Again, the order of these topics matters, and gives you complete control over the report format. As usual, please refer to `defaults.properties` for default values. + +Publisher classes can have their own, additional properties. For instance, the `ConsolePublisher` implementation can be further configured with respect to the information that is included in traces (bytecodes, method names etc.), and to redirect output (file, socket). Please refer to the constructor of this class for further details. + +~~~~~~~~ {.bash} +# save report to file +report.console.file=My_JPF_report +~~~~~~~~ + +All of the involved core classes and interfaces reside in the `gov.nasa.jpf.report` package. The most common way to extend the system is to use your own `PublisherExtension` implementation, which involves two steps: + + - implement the required phase and format specific methods + - register the extension for a specific Publisher class + + +The `DeadlockAnalyzer` (which is a listener to analyze concurrency defects) can be used as an example of how to do this: + +~~~~~~~~ {.java} +public class DeadlockAnalyzer extends ListenerAdapter { + ... + public DeadlockAnalyzer (Config config, JPF jpf){ + jpf.addPublisherExtension(ConsolePublisher.class, this); // (1) + ... + } + ... + public void publishPropertyViolation (Publisher publisher) { // (2) + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("thread ops " + publisher.getLastErrorId()); + + ... // use 'pw' to generate the output + } +} +~~~~~~~~ diff --git a/doc/graphics/DFSListener.svg b/doc/graphics/DFSListener.svg new file mode 100644 index 0000000..1684827 --- /dev/null +++ b/doc/graphics/DFSListener.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2005-10-21 18:50:44 +0000Canvas 1Layer 1searchStartedsearchFinishedstateAdvancedpropertyViolatedstateBacktrackedsearchConstraintHit diff --git a/doc/graphics/app-types.svg b/doc/graphics/app-types.svg new file mode 100644 index 0000000..f845707 --- /dev/null +++ b/doc/graphics/app-types.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2015-01-05 22:17:29 +0000App TypesLayer 1non-functional properties ■ unhandled exceptions (incl. AssertionError) ■ deadlocks ■ racesrestricted choice types ■ scheduling sequences ■ java.util.Random improved inspection ■ coverage statistics ■ exact object counts ■ execution costsconstraintsbenefitsrestricted application models ■ UML statemachines ■ does not run w/o JPF libraries runtime costs ■ order of magnitude slower ■ state storage memorystandard library support ■ java.net, javax.swing, .. (needs abstraction models) functional (domain) properties ■ built-in into JPF librariesfunctional property impl. costs ■ listeners, MJI knowledgeflexible state space ■ domain specific choices (e.g. UML "enabling events")runtime costs & library support ■ usually not a problem, domain libs can control state spaceruns on anyJVMruns onlyunder JPFlow modeling costs ■ statemachine w/o layout hassle,..initial domain impl. costs ■ domain libs can be tricky "sweet spot"annotate program ■ requirements ■ sequences (UML) ■ contracts (PbC) ■ tests … analyze program ■ symbolic exec → test data ■ thread safety / races *.class*.java@V*.javaJPF unawareprogramsJPF enabledprogramsJPF dependentprograms diff --git a/doc/graphics/attributes.svg b/doc/graphics/attributes.svg new file mode 100644 index 0000000..2aa20a4 --- /dev/null +++ b/doc/graphics/attributes.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2011-05-16 18:21:11 +0000Canvas 1Layer 1dup(), push(), pop(), ..------getOperandAttr(idx)setOperandAttr(idx,obj)getLocalAttr(idx)setLocalAttr(idx,obj)int[] localsObject[] localAttrint[] operandsObject[] operandAttrStackFramegetIntValue(idx), ...setIntValue(idx, v), ...------getFieldAttr(idx)setFieldAttr(idx,obj)getObjectAttr()setObjectAttr(obj)int[] valuesObject[] fieldAttrsObject objectAttrFieldslocalsvaluesattributesoperandsslotsfield-valuesattributesputfieldgetfielddup..iload..istore..invokevirtual..return..attributeobjectsetAttr(i,o)getAttr(i)- listener- Instruction- native peerget?Attr(i)set?Attr(i,o)JPF coreJPFextensionattribute APIobject-attrThreadInfoElementInfo diff --git a/doc/graphics/bc-factory.svg b/doc/graphics/bc-factory.svg new file mode 100644 index 0000000..f69c951 --- /dev/null +++ b/doc/graphics/bc-factory.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2011-05-16 18:32:22 +0000Canvas 1Layer 1*.classInstruction ifeq(tgt)...«interface»InstructionFactory...Instruction execute()InstructionIFEQIFEQ......Instruction execute (){.. cond = popCondition() if (cond) return jumpTarget else return getNextInsn()setCode(code)factoryInstruction[] codeMethodInfoconcrete execution semanticsabstract execution semanticsconcrete valueexecutionsymbolic valueexecutioninstruction setInstruction execute(){.. if (!firstStepInsn()){ setNextCG(new PCChoiceGenerator()) return this } popCondition() // not interested cond = getCG().getNextChoice() if (cond){... return jumpTarget } else {... return getNextInsn()per bytecodefactory methodsInstruction ifeq(tgt)...gov.nasa.jpf.jvm.bytecodeInstructionFactoryInstruction ifeq(tgt)...gov.nasa.jpf.symbcSymbolicInstructionFactoryInstruction ifeq(int jumpTarget){ return new IFEQ(jumpTarget)ClassInfoClassFileCodeBuilderConfigvm.insn_factory.class=... diff --git a/doc/graphics/cg-impl.svg b/doc/graphics/cg-impl.svg new file mode 100644 index 0000000..07a14cb --- /dev/null +++ b/doc/graphics/cg-impl.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-02 07:14:49 +0000Canvas 1Layer 1initNextTransition(){... curCg = nextCg nextCg = null curCg.advance() ..setExecThread() ...executeTransition(){.. isFirstStepInsn = true while (pc != null) { nextPc = executeInstruction() if (ss.breakTransition()) break else pc = nextPc isFirstStepInsn = falseexecute(){.. if (!ti.isFirstStepInsn()) { ChoiceGenerator cg = ..createMonitorEnterCG(..) if (cg != null){ ss.setNextChoiceGenerator(cg) return this // repeat } ei.lock(ti) return getNextPc(ti);execute()InstructioninitNextTransition()breakTransition()setNextChoiceGenerator()nextCgcurCgSystemStatehasMoreChoices()advance()ChoiceGeneratorgetNextChoice()threadSetThreadCGgetNextChoice()doubleSetDoubleCG......executeTransition()executeInstruction()isFirstStepInsn(){pc, nextPc}ThreadInfoMonitorEnterInvoke.....MethodInfoNativePeere.g. JPF_gov_nasa_jpf_vm_Verify.getBoolean(env)top half: executed on first invocationoptionally sets next CG and reexecutesbottom half: executed on revisit (orif no CG created because of policy)does semantic action based oncurrent CGs choicescheduling choicesdata acquisition choices123top halfbottomhalfif (!ti.isFirstStepInsn()){ cg = new BooleanCG() ss.setNextChoiceGenerator(cg) env.repeatInvocation() ..} else { cg = ss.getChoiceGenerator() return ((BooleanCG)cg).getNextChoice()}breakTransition(){... return nextCg != null diff --git a/doc/graphics/cg-motivation.svg b/doc/graphics/cg-motivation.svg new file mode 100644 index 0000000..e8c750c --- /dev/null +++ b/doc/graphics/cg-motivation.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2010-02-22 05:27:10 +0000Canvas 1Layer 1T ± Δ.. double v = Verify.getDouble("velocity"); ..velocity.class = gov.nasa.jpf.jvm.choice.DoubleThresholdGeneratorvelocity.threshold = 13250velocity.delta = 500application code(test driver)configuration (e.g. mode property file)C = { T-Δ, T, T+ Δ }Verify.getBoolean()Verify.getInt(0,4)Verify.getDouble(1.0,1.5)C = { true, false }C = { 0, 1, 2, 3, 4 }✓?potentially large sets with lots of uninteresting values??no finite value set without heuristicsC = { ∞ }e.g. "Threshold" heuristicChoice Generators+Configurable Heuristic Choice ModelsJPF internal object to store and enumerate a set of choicesconfigurable classes tocreate ChoiceGenerator instanceshasMoreChoices()advance()getNextChoice() → xchoiceSet: {x}xChoiceGenerator diff --git a/doc/graphics/cg-ontology.svg b/doc/graphics/cg-ontology.svg new file mode 100644 index 0000000..fab55e3 --- /dev/null +++ b/doc/graphics/cg-ontology.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2010-02-22 02:58:46 +0000Canvas 1Layer 1TransitionStateChoiceScheduling ChoiceData Choiceboolean b = Verify.getBoolean();double d = Verify.getDouble("MyHeuristic");..synchronized (..) {..}wait (..)x = mySharedObject..Control Choiceif (<cond>) ..INVOKECG.setInvocations(..).. diff --git a/doc/graphics/cg-sequence.svg b/doc/graphics/cg-sequence.svg new file mode 100644 index 0000000..5e0ff92 --- /dev/null +++ b/doc/graphics/cg-sequence.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2006-05-05 17:02:45 +0000Canvas 1Layer 1......get_field...monitor_enter...get_fieldmonitor_enter...ChoiceGeneratorTjTj+1Tj+2CGkCGlsetNextCGgetNextChoiceTransitionc1kc2kc3kSkc1kc2k{{}},==Statebacktrackadvancec2k,c1l...,execute{Instruction}Sl diff --git a/doc/graphics/choicegen-example.svg b/doc/graphics/choicegen-example.svg new file mode 100644 index 0000000..675ec8d --- /dev/null +++ b/doc/graphics/choicegen-example.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2006-05-03 17:51:17 +0000Canvas 1Layer 1T ± Δ.. double v = Verify.getDouble("velocity"); ..velocity.class = DoubleThresholdvelocity.threshold = 13250velocity.delta = 500application code(test driver)configuration (e.g. mode property file)C = { T-Δ, T, T+ Δ }Verify.getBoolean()Verify.getInt(0,4)Verify.getDouble(1.0,1.5)C = { true, false }C = { 0, 1, 2, 3, 4 }✓?potentially large sets with lots of uninteresting values??no finite value set without heuristicsC = { ∞ }e.g. "DoubleThresholdChoice"Choice Generators+Configurable Heuristic Choice ModelsJPF internal object to store and enumerate a set of choicesconfigurable classes tocreate ChoiceGenerator instanceshasMoreChoices()advance()getNextChoice() → xchoiceSet: {x}xChoiceGenerator diff --git a/doc/graphics/genpeer.svg b/doc/graphics/genpeer.svg new file mode 100644 index 0000000..6887428 --- /dev/null +++ b/doc/graphics/genpeer.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-04 01:29:55 +0000Canvas 1Layer 1GenPeerpackage x.y.z;class MyClass { ... native String foo (int i, String s);}class JPF_x_y_z_MyClass { ... @MJI public static int foo__ILjava_lang_String__2 (MJIEnv env, int objRef, int i, int sRef) { int ref = MJIEnv.NULL; // <2do> fill in body return ref; }}"java gov.nasa.jpf.GenPeer x.y.z.MyClass > JPF_x_y_z_MyClass.java" diff --git a/doc/graphics/interleavings.svg b/doc/graphics/interleavings.svg new file mode 100644 index 0000000..4dfa19e --- /dev/null +++ b/doc/graphics/interleavings.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-11-19 20:18:08 +0000Canvas 1Layer 1.........12P1P2PNn1n2...AtomicInstructionsThreads12I1∑niIM......nN.........Interleavings(∑ n )!∏ (n !)Ni=1iNi=1iM = diff --git a/doc/graphics/jpf-abstractions.svg b/doc/graphics/jpf-abstractions.svg new file mode 100644 index 0000000..b636c6f --- /dev/null +++ b/doc/graphics/jpf-abstractions.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-11-26 21:24:31 +0000Canvas 1Layer 1search ()VM vmSearchforward ()backtrack ()restoreState ()VMsearch ()DFSearchrun ()search, vm, configJPFexecuteTransition ()executeInstruction ()ThreadInfoinitializeNextTransition()executeNextTransition()SystemStateClassInfoMethodInfoFieldInfoElementInfoFieldsMonitorStaticsbytecode executiontype + codemgntobjectmodelgov.nasa.jpfgov.nasa.jpf.searchsearch ()HeuristicSearchgov.nasa.jpf.vmgov.nasa.jpf.search.heuristicgov.nasa.jpf.vm.bytecodeexecute ()Instruction.........search ()BFSHeuristic...while (notDone) { ..vm.forward(); ..vm.backtrack(); if (!properties.check()){ reportError(); break; ...search.class=...vm.class=...push (), pop() ...StackFrameConfigHeap diff --git a/doc/graphics/jpf-basic.svg b/doc/graphics/jpf-basic.svg new file mode 100644 index 0000000..fdfae11 --- /dev/null +++ b/doc/graphics/jpf-basic.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-11-19 18:37:23 +0000Canvas 1Layer 1JPF*.classreport*.jpfSystem under Test(Java bytecode)Verification ResultJPF ConfigurationProperties to Verify diff --git a/doc/graphics/jpf-intro-new.svg b/doc/graphics/jpf-intro-new.svg new file mode 100644 index 0000000..56fc211 --- /dev/null +++ b/doc/graphics/jpf-intro-new.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2009-04-10 01:07:23 +0000Canvas 1Layer 1------------------------------------ error path..Step #14 Thread #1 oldclassic.java:95 event2.waitForEvent(); oldclassic.java:37 wait();------------------------------------ thread stacksThread: Thread-0 at java.lang.Object.wait(Object.java:429) at Event.waitForEvent(oldclassic.java:37) ..======================== 1 Error Found: DeadlockJPFCorebytecodesetlistener/propertypublisher/ -extchoicegeneratorserializer/restorerannotation (optional) in-sourceproperty specdomainframeworkmodellibraryapplicationSuTexecutionenvironmentsearchstrategyJavavirtualmachinebytecodereportJPFendseenerror-pathproperty violationhost - JVMJPF distribution...nativepeer......extensions*.jpfJPF configurationreportstandardJava libraries*.jar*.jar diff --git a/doc/graphics/jpf-layers.svg b/doc/graphics/jpf-layers.svg new file mode 100644 index 0000000..ada4957 --- /dev/null +++ b/doc/graphics/jpf-layers.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-02 21:48:18 +0000Canvas 1Layer 1platform OShost JVMnative librarieslibrary classesJPF (Java application)modeled classesrt.jarJNIMJI*.classsystem under teststandard Java installationCLASSPATHModel layerJava layerNative layer"Java Native Interface""Model Java Interface" diff --git a/doc/graphics/jpf-project.svg b/doc/graphics/jpf-project.svg new file mode 100644 index 0000000..790b51b --- /dev/null +++ b/doc/graphics/jpf-project.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2009-09-09 23:36:00 +0000Canvas 1Layer 1jpf-Xsrcbuildbuild.xmljpf.propertiesX.jarX-classes.jarX-annotations.jarmainpeersclassesannotationstestsexampleslibtoolsbinRunJPF.jarRunAnt.jarjpfantnbprojectproject.xmlide-file-targets.xml.classpathmainpeersclassesannotationstestsexampleseclipserun-jpf.launchJPF project properties file(runtime def: native_classpath, classpath, sourcepath)host-VM executed classes (listeners, infrastructure etc.)host-VM executed library classes (MJI native peers)JPF executed library classes →sourcepathJPF processed Java annotationsregression testsdemos →sourcepathAnt build script (compile, build, test, clean)temporary build artifacts (classfiles)main host-VM executed project jar (main,peers →native_classpath)JPF executed library jar (classes,annotations →classpath)separate anotations jar (for JPF external SUT exec)required runtime jars →native_classpathbuild toolsant.jar, junit.jar, ...bcel.jar, antlr.jar, ..(example) 3rd party jarsbuild artifactspermanent build artifacts(example) 3rd party jarsJPF startup jar (executable)JPF build jar (executable)scriptsJPF startup script (→RunJPF.jar)JPF build script (→RunAnt.jar)Eclipse project configurationproject sourcesproject root directorybinary distributionNetBeans project configurationNetBeans file actions (JPF execution)Eclipse launch configs (JPF execution)IDE supportcompilebuildtest diff --git a/doc/graphics/listener-overview.svg b/doc/graphics/listener-overview.svg new file mode 100644 index 0000000..8a58bd9 --- /dev/null +++ b/doc/graphics/listener-overview.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-02 07:42:37 +0000Canvas 1Layer 1SearchVMJPFSystem under testlistenersexecuted by JPFexecuted by host JVMsearch event notificationsexecution event notificationsconfigured- classLoaded (vm)- threadScheduled (vm)- threadNotified (vm) ...- executeInstruction (vm)- instructionExecuted (vm) ...- objectCreated (vm) ...- exceptionThrown(vm) ...- choiceGeneratorAdvanced (vm) ...- stateAdvanced (search)- stateBacktracked (search)- propertyViolated (search)- searchFinished (search) ...- +listener=<listener-class>- @JPFConfig(..)- listener.autoload=<annotations>- jpf.addListener(..) ...≪SearchListener≫≪VMListener≫ diff --git a/doc/graphics/listeners.svg b/doc/graphics/listeners.svg new file mode 100644 index 0000000..681d1ad --- /dev/null +++ b/doc/graphics/listeners.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2009-04-08 19:52:28 +0000Canvas 1Layer 1«interface»JPFListenerexecuteInstruction(vm)instructionExecuted(..)threadStarted(..)objectCreated(..)choiceGeneratorSet(..)choiceGeneratorAdvanced(..). . .«interface»VMListenersearchStarted(search)stateAdvanced(..)stateBacktracked(..)propertyViolated(..)searchFinished(..). . .«interface»SearchListenercheck(search,vm)getErrorMessage()«interface»Propertycheck(search,vm) {}. . .GenericPropertyinstructionExecuted(vm) {}searchStarted(search) {}. . .ListenerAdapterpublishStart(publisher)publishFinished(..). . .«interface»PublisherExtensioninstructionExecuted(vm) {}searchStarted(search) {}. . .PropertyListenerAdapter diff --git a/doc/graphics/mji-call.svg b/doc/graphics/mji-call.svg new file mode 100644 index 0000000..d5db418 --- /dev/null +++ b/doc/graphics/mji-call.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2011-05-24 04:08:50 +0000Canvas 1Layer 1package x.y.z;class C { ... native int foo (int p);}class JPF_x_y_z_C { ... public static int foo__I__I (MJIEnv env, int thisRef, int p) { int d = env.getIntField(thisRef, "data"); .. }}...int a = c.foo(3);...aload_1icont_3invokevirtual ..executeMethod (ThreadInfo ti..){ MJIEnv env = ti.getMJIEnv(); Object[] args = getArguments(); .. mth.invoke(peerCls, args); ..}ClassInfo (..){ peerCls = loadNativePeer(..); ..}executeMethod()peerClsClassInfoexecuteMethod()methodsNativePeergetXField(..)setXField(..)...threadInfoMJIEnvenvThreadInfoJPFclassloadingJPFmethodinvocationJPFobjectaccessJPF (model) classJVM (Java) classJava reflection callreflection diff --git a/doc/graphics/mji-functions.svg b/doc/graphics/mji-functions.svg new file mode 100644 index 0000000..bac9b5c --- /dev/null +++ b/doc/graphics/mji-functions.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2011-05-24 04:01:26 +0000Canvas 1Layer 1class JPF_x_y_z_MyClass { public static int foo__ILjava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int i, int sRef) { String s = env.getStringObject(sRef); .. int ref = env.newString(..); return ref; }}package x.y.z;class MyClass { .. native String foo (int i, String s);}MJIEnvJPF objectsJava objectsNativePeerJPF executedhost VM executed- method lookup- parameter conversion- invocation- field access- object conversion- JPF intrinsics access"Model" Class"NativePeer" ClassMJI - "Model Java Interface" diff --git a/doc/graphics/mji-mangling.svg b/doc/graphics/mji-mangling.svg new file mode 100644 index 0000000..7e59270 --- /dev/null +++ b/doc/graphics/mji-mangling.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-02 21:54:02 +0000Canvas 1Layer 1package x.y;class MyClass { native int foo (int i, String s);}class JPF_x_y_MyClass { public static int foo__ILjava_lang_String_2 (MJIEnv env, int objref, int i, int sRef) {..}}Model ClassNative Peer Classmodel parameters(refs become 'int')MJI parametersJNI conformant manglingbooleanbytecharshortintlongfloatdoubleZBCSIJFD'_'';''['_1_2_3<type> [][<type>x.y.ZLx_y_Z_2<func> (..)<func>__<signature> diff --git a/doc/graphics/new-testing.svg b/doc/graphics/new-testing.svg new file mode 100644 index 0000000..4254ad1 --- /dev/null +++ b/doc/graphics/new-testing.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-05 00:34:03 +0000Canvas 1Layer 1@Test public void testX() { if (verifyNoPropertyViolation()) { String s = "one" + " two"; assert "one two".equals(s); }}boolean verifyNoPropertyViolation (String... jpfArgs) { ... args = append(jpfArgs, caller.getClassName(), caller.getMethodName()); .. JPF jpf = createAndRunJPF(args); ... errors = jpf.getSearchErrors(); if (!errors.isEmpty()) throw new AssertionError(..); ... return false; // -> don't execute test block}boolean verifyNoPropertyViolation(..){ return true;}start()JPFShellrunTestsOfThisClass()createAndRunJPF()...verifyNoPropertyViolation()verifyPropertyViolation()verifyUnhandledException()verifyAssertionError()...TestJPFtestX()...MyJPFProjectTestjpf-coretested JPF projectverifyNoPropertyViolation()verifyPropertyViolation()verifyUnhandledException()verifyAssertionError()JPF_.._TestJPFnative peercode verified by JPFexecuted by JPF whenrunning testexecuted outside JPF (starting JPF on test) diff --git a/doc/graphics/por-mark.svg b/doc/graphics/por-mark.svg new file mode 100644 index 0000000..f47b060 --- /dev/null +++ b/doc/graphics/por-mark.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-12-02 07:35:36 +0000Canvas 1Layer 1XX1XX12Xstatic fieldsT1T2root setheapphase 1phase 21 & 2 : referencing thread numberX : shared diff --git a/doc/graphics/por-scheduling-relevance.svg b/doc/graphics/por-scheduling-relevance.svg new file mode 100644 index 0000000..45c2886 --- /dev/null +++ b/doc/graphics/por-scheduling-relevance.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2011-05-11 18:17:44 +0000Canvas 1Layer 1executed bytecode instructionfield insnsync insninvoke insnsync mththreading callscheduling relevant insn typeother runnable threadsrecursive locksshared objectslock protected accessscheduling relevant instruction (registeres a ThreadChoiceGenerator)data racesdeadlocks(lock races)tracking of access threadslock distance & statisticsThread. start(), yield() sleep(), join()Object.wait(),notify()configuredclass/mthdattributesGETFIELDPUTFIELDGETSTATICPUTSTATICxALOADxASTOREMONITORENTERMONITOREXITINVOKEVIRTUALINVOKESTATIC diff --git a/doc/graphics/properties.svg b/doc/graphics/properties.svg new file mode 100644 index 0000000..ad56b87 --- /dev/null +++ b/doc/graphics/properties.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2011-05-11 18:07:23 +0000Canvas 1Layer 1jpf.home = ${user.home}/projects/jpfjpf-core = ${jpf.home}/jpf-corejpf-awt = ${jpf.home}/awtjpf-shell = ${jpf.home}/jpf-shelljpf-aprop = ......extensions = ${jpf-core},${jpf-shell}jpf-core = ${config_path}jpf-core.native_classpath=\ ${jpf-core}/build/jpf.jar;\ ... ${jpf-core}/lib/bcel.jar;jpf-core.classpath=\ build/jpf-classes.jarjpf-core.test_classpath=\ build/testsjpf-core.sourcepath=\ src/classes...jpf-awt-shell = ${config_path}@using = jpf-awtjpf-awt-shell.native_classpath=...jpf-awt-shell.classpath=......target = RobotManagertarget_args = ...@using = jpf-aprop@import = ./my.propertiesshell = .shell.basicshell.BasicShelllistener = .aprop.listener.SharedChecker...1. site properties2. project properties3. application properties4. command line~/.jpf/site.properties<project>/jpf.properties<project>/.../*.jpf> bin/jpf [-log][-show] {+log.info=..} .../RobotManager.jpf all jpf.properties inorder of extensionsjpf.properties in current directory- project locations- pre-loaded projects- project class paths- project dependencies- system-under-test- listeners, shells- debuggingcommand line property arguments...applicationpropertiessite properties diff --git a/doc/graphics/report.svg b/doc/graphics/report.svg new file mode 100644 index 0000000..cad3324 --- /dev/null +++ b/doc/graphics/report.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2010-09-10 23:02:45 +0000Canvas 1Layer 1JPF()addPublisherExtension()setPublisherTopics()reporterJPF..reporter = config.getInstance("report.class", Reporter.class,..);..searchStarted()propertyViolated()searchFinished()publishersReporterpublishStart()getOut()extensionstopicsoutPublisherpublishStart()publishTransition()publishPropertyViolation()publishFinished()<<PublisherExtension>>........for (Publisher p : publishers){ p.openChannel(); .. p.publishStart();.. public void publishStart() { for (String topic : startTopics) { if ("jpf".equals(topic)){ publishJPF(); ... for (PublisherExtension e : extensions) { e.publishStart(this); } ...out.println("JPF version" + ..);publishJPF()...ConsolePublisherpublishFinished()...DeadlockAnalyzerPrintWriter out = publisher,getOut();printTraceAnalysis(out);data collectionpublisher managementdata formattingtopic managementoutput channel managementproperty/listenerspecific output topicsreport.class=.report.Reporterreport.publisher=console,..report.console.class=.report.ConsolePublisherreport.console.start=jpf,..JPF configuration(e.g. jpf.properties or *.jpf files) diff --git a/doc/graphics/states-mc.svg b/doc/graphics/states-mc.svg new file mode 100644 index 0000000..8d9f5fd --- /dev/null +++ b/doc/graphics/states-mc.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2009-09-06 18:37:27 +0000Canvas 1Layer 1☠model checking:all program state are explored until none left or defect foundbacktrack≡≡≡match✘ diff --git a/doc/graphics/states-testing.svg b/doc/graphics/states-testing.svg new file mode 100644 index 0000000..12e5396 --- /dev/null +++ b/doc/graphics/states-testing.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-11-19 20:33:35 +0000Canvas 1Layer 1☠based on input set {d}only one pathexecuted at a time✔testing:{d} diff --git a/doc/graphics/sw-model-checking-2.svg b/doc/graphics/sw-model-checking-2.svg new file mode 100644 index 0000000..a0575f7 --- /dev/null +++ b/doc/graphics/sw-model-checking-2.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2015-01-05 22:19:29 +0000Canvas 1Layer 1a=0b=0b=1b=2c=0c=0c=0/0starta=1b=0b=1b=2c=-1c=1/0c=1✘12345✔✔6 diff --git a/doc/graphics/sw-model-checking.svg b/doc/graphics/sw-model-checking.svg new file mode 100644 index 0000000..1fd0a54 --- /dev/null +++ b/doc/graphics/sw-model-checking.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.1 2014-11-19 20:40:12 +0000Canvas 1Layer 1Random random = new Random() int a = random.nextInt(2)int b = random.nextInt(3)int c = a/(b+a -2)①②③④a=0b=0b=1b=2c=0c=0c=0/0starta=1b=0b=1b=2c=-1c=1/0c=1✔ diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 0000000..a40d030 --- /dev/null +++ b/doc/index.md @@ -0,0 +1,66 @@ +## Welcome to the Java™Pathfinder System ## + +This is the main page for Java™ Pathfinder (JPF). JPF is an extensible software model checking framework for Java™ bytecode programs. The system was developed at the [NASA Ames Research Center](http://arc.nasa.gov), open sourced in 2005, and is freely available on this server under the [Apache-2.0 license](http://www.apache.org/licenses/LICENSE-2.0). + + +This page is our primary source of documentation, and is divided into the following sections. + + --- + + * [Introduction](intro/index) -- a brief introduction into model checking and JPF + * [What is JPF?](intro/what_is_jpf) + * [Testing vs. Model Checking](intro/testing_vs_model_checking) + - [Random value example](intro/random_example) + - [Data race example](intro/race_example) + * [JPF key features](intro/classification) + + --- + + * [How to obtain and install JPF](install/index) -- everything to get it running on your machine + - [System requirements](install/requirements) + - Downloading [binary snapshots](install/snapshot) and [sources](install/repositories) + - [Creating a site properties file](install/site-properties) + - [Building, testing, and running](install/build) + - Installing the JPF plugins + - [Eclipse](install/eclipse-plugin) + - [NetBeans](install/netbeans-plugin) + + --- + + * [How to use JPF](user/index) -- the user manual for JPF + - [Different applications of JPF](user/application_types) + - [JPF's runtime components](user/components) + - [Starting JPF](user/run) + - [Configuring JPF](user/config) + - [Understanding JPF output](user/output) + - [Using JPF's Verify API in the system under test](user/api) + + --- + + * [Developer guide](devel/index) -- what's under the hood + * [Top-level design](devel/design) + * Key mechanisms, such as + - [ChoiceGenerators](devel/choicegenerator) + - [Partial order reduction](devel/partial_order_reduction) + - [Slot and field attributes](devel/attributes) + * Extension mechanisms, such as + - [Listeners](devel/listener) + - [Search Strategies](devel/design) + - [Model Java Interface (MJI)](devel/mji) + - [Bytecode Factories](devel/bytecode_factory) + * Common utility infrastructures, such as + - [Logging system](devel/logging) + - [Reporting system](devel/report) + * [Running JPF from within your application](devel/embedded) + * [Writing JPF tests](devel/jpf_tests) + * [Coding conventions](devel/coding_conventions) + * [Hosting an Eclipse plugin update site](devel/eclipse_plugin_update) + + --- + + * [JPF core project](jpf-core/index) -- description and link to jpf-core + + --- + + * [Related research and publications](papers/index) + diff --git a/doc/install/build.md b/doc/install/build.md new file mode 100644 index 0000000..9e8d3d6 --- /dev/null +++ b/doc/install/build.md @@ -0,0 +1,112 @@ +# Building, Testing, and Running # + +If you downloaded binary snapshots, you don't have anything to build (except of creating/updating you [site.properties](./site-properties) file). + +## Building JPF ## + +If you have cloned the project repositories you are interested in (which at least includes [jpf-core](../jpf-core/index)), you can build and test each of them by means of their included [Ant](http://ant.apache.org) `build.xml` scripts. Note that you have to install Ant and JUnit separately, e.g. following directions [here](../install/requirements). + + +### Using the command line ### + +~~~~~~~~ {.bash} +> cd jpf-core +> ant test + +... lots of output, at the end you should see something like: +BUILD SUCCESSFUL +Total time: 2 minutes 31 seconds +~~~~~~~~ + +### Within NetBeans ### + + 1. run **File/Open Project..** from the application menu, entering the JPF project you just downloaded (e.g. "jpf-core") + 1. select the project that appears in our project pane (e.g. "jpf-core") + 1. run **Build** from the project context menu + +### Within Eclipse ### + +* Ensure that the `JAVA_HOME` environment variable points to the jdk1.6xxx directory. If it is empty or points to a JRE then errors such as **javac not found** maybe seen. If you do not want the system Java settings to point to jdk1.6xxx, you can also set project specific settings in eclipse. + +* If you eclipse settings are set to **Build Automatically** then the project after being cloned will be built. + +* To build a particular project in the Project menu select **Build Project**. All the dependencies for the project will be built automatically. + +#### Project Specific JDK settings within Eclipse #### +1. In Eclipse go to **Project** -> **Properties** + +2. Select **Builders** + +3. Pick **Ant_Builder** -> click **Edit** + +4. Click on the **JRE** tab + +5. Select **Separate JRE** -> **Installed JREs** + +6. On Windows and Unix-based systems pick JDK1.6xxx. If it is not listed under the installed JREs, click on **Add**, browse your file system to where JDK1.6xxx resides and select. On OSx systems pick the JVM 1.6.0. + + +## Running JPF ## + +### Using the command line ### + + +~~~~~~~~ {.bash} +> cd jpf-core +> java -jar build/RunJPF.jar src/examples/Racer.jpf +JavaPathfinder v5.0 - (C) 1999-2007 RIACS/NASA Ames Research Center +..... +====================================================== statistics +elapsed time: 0:00:00 +states: new=9, visited=1, backtracked=4, end=2 +search: maxDepth=5, constraints=0 +choice generators: thread=8, data=0 +heap: gc=8, new=291, free=32 +instructions: 3112 +max memory: 79MB +loaded code: classes=73, methods=1010 + +====================================================== search finished: 1/12/10 2:30 PM +~~~~~~~~ + +### Using eclipse plugin ### + + 1. Right click on a .jpf file. Examples can be found in the src\examples directory in jpf-core + 1. If the eclipse plugin is correctly installed, a Verify option will appear. + 1. Select the Verify option and the verification process of the system specified in the .jpf file begins + +Note that the Application.jpf file essentially replaces previous uses of eclipse launch configurations. The required element of a .jpf file is the `target=MAIN_CLASS` where `MAIN_CLASS` is the class containing main method of the system under test. Any other configurations that need to be specified can be added here. for example `listener=gov.nasa.jpf.tools.SearchMonitor`. + +Specify `classpath=PATH_TO_BIN_DIRECTORY` to add the class files for the program under test to JPF's class path. Windows users will need to use the double-backslash notation in specifying paths in the .jpf file. An example .jpf file for the Windows platform is included below for convenience: + +~~~~~~~~ {.bash} +target=mutex.DekkerTestMain +report.console.property_violation=error,trace,snapshot +listener=gov.nasa.jpf.listener.EndlessLoopDetector +classpath=C:\\Users\\fred\\Documents\\ch02-mutex\\bin +sourcepath=C:\\Users\\fred\\Documents\\ch02-mutex\\src,C:\\Users\\Fred\\Documents\\ch02-mutex\\src-test +~~~~~~~~ + +The .jpf file not only indicates the `target` and `classpath`, but it also turns on error reporting with trace generation (`report.console.property_violation`) and configures the source path (`sourcepath`). Note that multiple source directories are specified using the comma separator. + +### Using eclipse Run Configuration ### + + 1. Select a .jpf file by clicking on it in the Package Explorer + 1. Click **Run** -> **Run Configurations** -> **run-JPF-core**. It is important the correct .jpf file is selected when the configuration is run. + +#### Windows users #### +After a fresh install of jpf-core you may see the following when trying to use the Eclipse Run-jpf-core configuration: + +~~~~~~~~ +java.lang.NoClassDefFoundError: gov/nasa/jpf/Main +Caused by: java.lang.ClassNotFoundException: gov.nasa.jpf.Main + at java.net.URLClassLoader$1.run(Unknown Source) + at java.security.AccessController.doPrivileged(Native Method) + at java.net.URLClassLoader.findClass(Unknown Source) + at java.lang.ClassLoader.loadClass(Unknown Source) + at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) + at java.lang.ClassLoader.loadClass(Unknown Source) +Exception in thread "main" +~~~~~~~~ + +In this particular case, the error was generated after the initial build after the clone had completed. To resolve the issue, **refresh the Eclipse workspace** (F5 or right click Refresh). After the refresh, the Run-jpf-core configuration should work as described above. diff --git a/doc/install/eclipse-jpf.md b/doc/install/eclipse-jpf.md new file mode 100644 index 0000000..bae977d --- /dev/null +++ b/doc/install/eclipse-jpf.md @@ -0,0 +1,24 @@ +# eclipse-jpf # + +This is a plugin to launch JPF on selected application property files (*.jpf) from within Eclipse. This plugin is the Eclipse analog to netbeans-jpf. This plugin is minimal by design and serves mostly to start an external JPF process from within Eclipse. + +To this end, the plugin adds a "Verify.." popup menu item for *.jpf files that are selected in the package explorer window. + +Depending on the selected application property file, output will appear either in the eclipse console view or a jpf-shell. + +The site.properties location can be entered in the "JPF Preferences" pane within the normal Eclipse Preferences window. The default location is `$HOME/.jpf/site.properties`. + + +This project is *not* a normal JPF project, i.e. it does not follow the usual JPF directory structure and artifacts. This is an Eclipse plugin project that builds into a jar file (attached) that installs into Eclipse as a plugin. Of course that means you need an Eclipse installation that includes the Plugin Development Environment (PDE) in order to build this project. + +### Repository ### +The eclipse-jpf source repository is located on http://babelfish.arc.nasa.gov/hg/jpf/eclipse-jpf + +### Installation ### +If you have the eclipse PDE installed, the preferred way is to get the eclipse-jpf sources from the repository, build via the eclipse plugin Export Wizard into the /dropins folder and restart eclipse. + +If you don't have the eclipse PDE, you can either install this plugin via "Eclipse/Help/Install New Software..." by entering the the eclipse-jpf update site URL: + + http://babelfish.arc.nasa.gov/trac/jpf/raw-attachment/wiki/projects/eclipse-jpf/update + +or download the attached eclipse-jpf_.jar file and move it into your /dropins folder. In both cases, you need to restart eclipse in order to load the plugin. Note however that this might not be the latest eclipse-jpf version and it might or might not work with your eclipse. \ No newline at end of file diff --git a/doc/install/eclipse-plugin.md b/doc/install/eclipse-plugin.md new file mode 100644 index 0000000..2bcbb3a --- /dev/null +++ b/doc/install/eclipse-plugin.md @@ -0,0 +1,15 @@ +# Installing the Eclipse JPF plugin # + +Note that this is assuming the latest Eclipse and Java versions, which is Eclipse 4.3.x and Java 7 at the time of this writing. Older versions might or might not work. +There are three different ways to install the plugin, which are listed in the order of preference if you want to ensure that you are using the latest plugin version: + +### Build from sources ### +If you have the Eclipse Plugin Development Environment installed (PDE -comes with standard Eclipse distribution), the preferred way is to download the [eclipse-jpf](./eclipse-jpf) sources from the repository, build the plugin into your /dropins/plugins directory, and restart Eclipse. This ensures you are using the latest version of the plugin, and the build process will tell you if your Eclipse is compatible. + +### Install from attached plugin jar ### +Alternatively, you can download one of the attached eclipse-jpf_.jar files, place it into your /dropins/plugins directory, and restart Eclipse. + +### Install from update site ### +The most convenient, but least up-to-date way to install eclipse-jpf is to use the Eclipse/Help/Install New Software... dialog, by entering the the eclipse-jpf update site URL: + + http://babelfish.arc.nasa.gov/trac/jpf/raw-attachment/wiki/projects/eclipse-jpf/update diff --git a/doc/install/eclipse-plugin/update.md b/doc/install/eclipse-plugin/update.md new file mode 100644 index 0000000..18ccf75 --- /dev/null +++ b/doc/install/eclipse-plugin/update.md @@ -0,0 +1 @@ +This is the target location for the eclipse-jpf update site. \ No newline at end of file diff --git a/doc/install/eclipse-plugin/update/features.md b/doc/install/eclipse-plugin/update/features.md new file mode 100644 index 0000000..f22f5b8 --- /dev/null +++ b/doc/install/eclipse-plugin/update/features.md @@ -0,0 +1 @@ +Nothing to see here, just a place holder to upload the eclipse-jpf feature. \ No newline at end of file diff --git a/doc/install/eclipse-plugin/update/plugins.md b/doc/install/eclipse-plugin/update/plugins.md new file mode 100644 index 0000000..180eefa --- /dev/null +++ b/doc/install/eclipse-plugin/update/plugins.md @@ -0,0 +1 @@ +Nothing to see here, just a place holder to upload the eclipse-jpf plugin. \ No newline at end of file diff --git a/doc/install/index.md b/doc/install/index.md new file mode 100644 index 0000000..b7f40b8 --- /dev/null +++ b/doc/install/index.md @@ -0,0 +1,19 @@ +# How to Obtain and Install JPF # + +The JPF core and most of its extensions are pure Java applications, so they are not many platform requirements other than sufficient memory and a reasonably fast machine. Use of IDEs is optional, but most JPF modules include out-of-the-box configuration files for both Eclipse and Netbeans. + +You can obtain JPF sources from the [Mercurial](http://mercurial.selenic.com/wiki/) repositories, but it is not recommended to clone this directory itself (you most likely would get old sub-repository revisions). You need at least the core of JPF, [jpf-core](../jpf-core/index) which can be built with [Ant](http://ant.apache.org) from the command line, or directly opened as a [NetBeans](http://www.netbeans.org) or [Eclipse](http://www.eclipse.org) project. + +The JPF core project already come with its configuration file, but you have to create a per-site [site.properties](site-properties) file. + +If you use the JPF shells (graphical JPF front-ends), you might also want to install the corresponding NetBeans or Eclipse adapter plugins, although shells are standalone Java (swing) applications that can also be used without an IDE. + +Here are the details: + + - [System requirements](requirements) + - [Downloading binary snapshots](snapshot) + - [Downloading sources from the Mercurial repositories](repositories) + - [Creating a site properties file](site-properties) + - [Building, testing, and running](build) + - [Installing the Eclipse plugin](eclipse-plugin) + - [Installing the NetBeans plugin](netbeans-plugin) \ No newline at end of file diff --git a/doc/install/netbeans-jpf.md b/doc/install/netbeans-jpf.md new file mode 100644 index 0000000..539e0df --- /dev/null +++ b/doc/install/netbeans-jpf.md @@ -0,0 +1,10 @@ +# netbeans-jpf # + +This is a plugin to launch JPF on selected application properties (*.jpf) files from within NetBeans. No worries, this is a minimal plugin that mainly starts an external process (JPF), so it doesn't muck with your NetBeans views. + +The main functions are + + - start the JPF shell in an external process + - wait for editor positioning requests from the JPF shell, and show the corresponding source lines + +Why is this named differently than all the other projects? Because it is a different kind of project: this is *not* a normal JPF project, i.e. it is not a freeform NetBeans project with the usual JPF directory structure and artifacts. It is a NetBeans module, and it's main artifact is a *.nbm file in the build directory. \ No newline at end of file diff --git a/doc/install/netbeans-plugin.md b/doc/install/netbeans-plugin.md new file mode 100644 index 0000000..c5360a4 --- /dev/null +++ b/doc/install/netbeans-plugin.md @@ -0,0 +1,11 @@ +# Installing the NetBeans JPF plugin # + 1. Download and install [jpf-core](../jpf-core/index), e.g. from the [Mercurial repository](../install/repositories) + 2. -------------- take a break --------------- + 3. Download the `gov-nasa-jpf-netbeans-runjpf.nbm` file from [here](http://babelfish.arc.nasa.gov/trac/jpf/attachment/wiki/install/netbeans-plugin/gov-nasa-jpf-netbeans-runjpf.nbm). + 4. From within Netbeans go to **Tools**->**Plugins** (Alt+T followed by Alt+g) + 5. Select the **Downloaded** tab + 6. Click on **Add Plugins...** (Alt+A) + 7. Select the `gov-nasa-jpf-netbeans-runjpf.nbm` file that was downloaded in step 3 + 8. Select **install** + 9. Agree to the License agreement + 10. Restart Netbeans \ No newline at end of file diff --git a/doc/install/repo_shell.md b/doc/install/repo_shell.md new file mode 100644 index 0000000..e5609b1 --- /dev/null +++ b/doc/install/repo_shell.md @@ -0,0 +1,74 @@ +# Checkout and Build from Shell Prompt (Unix) # + +While there is a CVS repository on the JPF Sourceforge site, it is not in use anymore. The current version is kept in the Subversion repository. + + We will shift to a distributed version control system (Mercurial or Git) soon + + +# SVN # + +This is not a general introduction of [nor do we cover details of [[https://sourceforge.net/svn/?group_id=136825|Subversion on Sourceforge]((SVN),)(http://subversion.tigris.org|Subversion]]). To obtain the current JPF version, execute the following command from a shell prompt: + +~~~~~~~~ {.bash} +>svn checkout https://javapathfinder.svn.sourceforge.net/svnroot/javapathfinder/trunk +~~~~~~~~ + +To update later-on, enter from within one of the javapathfinder directories + + +~~~~~~~~ {.bash} +>svn update +~~~~~~~~ + +To commit (in case you are a project member and have a sourceforge account), use + + +~~~~~~~~ {.bash} +>svn commit -m "commit message" +~~~~~~~~ + +In order to build and test JPF from the commandline, you need Ant and JUnit. If you do not want to use the scripts and versions that are provided with JPF, make sure you have set up your *CLASSPATH* to contain both tools. As of Ant 1.6.5 and JUnit 4.1, this involves the following environment settings: + + +~~~~~~~~ {.bash} +>export PATH=$PATH:/bin +>export CLASSPATH=/lib/ant.jar:/junit-4.1.jar +~~~~~~~~ + +~~~~~~~~ + for your convenience, we have added all required external libraries +and scripts to the *build-tools* directory, so you do not have to install +any of the external components. +~~~~~~~~ +Now you can proceed as described in section Building JPF from a Command Line. For the impatient reader, this is mainly one command + + +~~~~~~~~ {.bash} +>cd javapathfinder-trunk +>build-tools/bin/ant run-tests + +Buildfile: build.xml + +init: + [mkdir] Created dir: /users/pcmehlitz/projects/javapathfinder-trunk/build + ... +compile-jpf: + [javac] Compiling 543 source files to /users/pcmehlitz/projects/javapathfinder-trunk/build/jpf + ... +run-tests: + [echo] --- running Junit tests from build/test.. + [junit] Running TestJavaLangObjectJPF + [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.876 sec + ... +BUILD SUCCESSFUL +Total time: 2 minutes 25 seconds +~~~~~~~~ + +or (especially for non-Unix folk) + + +~~~~~~~~ {.bash} +>java RunAnt run-tests +~~~~~~~~ + +which should compile the whole system and runs the regression test suite with the provided Ant and JUnit versions. \ No newline at end of file diff --git a/doc/install/repositories.md b/doc/install/repositories.md new file mode 100644 index 0000000..7d43566 --- /dev/null +++ b/doc/install/repositories.md @@ -0,0 +1,68 @@ +# JPF Source Repository Access # + +JPF sources are kept as [Mercurial](http://www.selenic.com/mercurial) repositories within the http://babelfish.arc.nasa.gov/hg/jpf directory. You need to clone the subrepositories (e.g. http://babelfish.arc.nasa.gov/hg/jpf/jpf-core) that you are interested in, **not** the root directory ../hg/jpf itself (which most likely will give you old subrepo revisions). + +We provide anonymous, public read access. If you want to push your changes back to the repository, and you are not a NASA Ames employee, you need to [obtain a JPF contributor account](wiki:about/account). + +Mercurial is a [Distributed Version Control System](http://betterexplained.com/articles/intro-to-distributed-version-control-illustrated/) (DVCS), like Git. If you are not familiar with this, it means "all repositories are created equal", and you have to read up a bit. The foremost authority is ["Mercurial: The Definite Guide"](http://hgbook.red-bean.com/). + +For the inpatient, we also provide a short [Mercurial primer](../devel/mercurial). + +## Command Line Access ## + +To check out the jpf-core use the mercurial command `clone`: + +~~~~~~~~ {.bash} +> cd ~/projects + +> hg clone http://babelfish.arc.nasa.gov/hg/jpf/jpf-core +destination directory: jpf-core +requesting all changes +... +added 71 changesets with 2045 changes to 1694 files +updating working directory +683 files updated, 0 files merged, 0 files removed, 0 files unresolved +~~~~~~~~ + +The same process can be repeating by substituting `jpf-core` with the [project](../projects/index) you are interested in. You can install the projects wherever you want, but you have to remember where you installed them for the subsequent [site.properties](../install/site-properties) configuration. + +To update your local repository, change to its directory and do `pull` (don't forget the `-u` option, or your working directories will not get updated) + +~~~~~~~~ {.bash} +> cd ~/projects/jpf-core +> hg pull -u +~~~~~~~~ + +If you want - and are allowed - to push back your changes, you use **`https://`**`babelfish.arc.nasa.gov/hg/jpf/` as the URL, which will require entering your user-name and password. Before pushing the changes you have to commit the changes from your working directory to your local repository. + +~~~~~~~~ {.bash} +> cd ~/projects/jpf-core +> hg commit -m "this commits to the local repository" +~~~~~~~~ + +The changes now can be pushed to the central repository using the following command + +~~~~~~~~ {.bash} +> hg push https://babelfish.arc.nasa.gov/hg/jpf/jpf-core +~~~~~~~~ + +## Mercurial Support within NetBeans ## + +There is no need to install any plugins, NetBeans is distributed with Mercurial support. + + +## Mercurial Plugin for Eclipse ## + +To work within Eclipse + +* Download and install the [MercurialEclipse](http://javaforge.com/project/HGE) plugin, which at the time of this writing is available from the update site: http://cbes.javaforge.com/update (the usual Eclipse spiel: **Help** -> **Install New Software...** -> **add site**, enter the update URL above) + +* In the eclipse menu: **File** -> **Import** -> **Mercurial** -> **Clone repository using Mercurial** -> **Next** + +* In the repository location, URL, specify http://babelfish.arc.nasa.gov/hg/jpf/jpf-core + +* Check the box for 'Search for .project files in clone and use them to create projects' + +* Click on **Finish** + +The steps listed above will clone the repository in your workspace. Right clicking on the project will show a 'Team' option that allows to perform all the version control operations. diff --git a/doc/install/requirements.md b/doc/install/requirements.md new file mode 100644 index 0000000..ccec451 --- /dev/null +++ b/doc/install/requirements.md @@ -0,0 +1,79 @@ +# System Requirements # + +## Java ## +Most of the JPF components, including the [jpf-core](../jpf-core/index), are pure Java applications. The minimal version is Java SE 8 (if you have to use JDK 1.7 or JDK 1.6 you have to check out the 'java-7' and 'java-1.6' branches of our repository, respectively), we generally advise to use the latest stable Java version that is available for your platform. You can find out about your java by running the following statement from the command line. + +~~~~~~~~ {.bash} +> java -version +java version "1.8.0_20" +... +~~~~~~~~ + +JPF is a resource hungry application. We recommend at least 2Gb of memory, and generally use a `-Xmx1024m` setting when launching Java. The disk footprint for most JPF projects is fairly small, the jpf-core takes about 40M when fully expanded with sources, compiled classes and jar files. The binary distribution (jar files) takes less than 1.5M. + +Some JPF projects do require 3rd party native executables (like DLLs) that are platform specific. Please refer to the specific project pages for details. + +### Java specifics for Windows ### +Make sure you have the JDK installed, otherwise there is no javac compiler available. + +In order to build JPF from a Windows Command Prompt (executing `ant.bat` from inside the respective JPF project directory), you have to set the `JAVA_HOME` environment variable. + +### Java specifics for OS X ### +On Mac OS X 10.10, Java 1.7 is default, but `/Applications/Utilities/Java Preferences.app` can change the setting. In some cases, it may be necessary to manually change the symlink that determines which version is default: + +~~~~~~~~ {.bash} +sudo rm /System/Library/Frameworks/JavaVM.framework/Versions/Current +sudo ln -s 1.8 /System/Library/Frameworks/JavaVM.framework/Versions/Current +~~~~~~~~ + +## Mercurial (Version Control System) ## +If you want to download the JPF source repositories, you need to install the [Mercurial](http://mercurial.selenic.com/wiki/) distributed version control system on your machine, which requires [Python](http://www.python.org). If you are using a Windows machine, you can install [TortoiseHg](http://tortoisehg.bitbucket.org/), which provides a Windows Explorer extension and includes Python. + +On some Mac OS X systems, it may be necessary to set the `LC_ALL` and `LANG` environment variables for Mercurial to work correctly. + +in `~/.bashrc`: + +~~~~~~~~ {.bash} +export LC_ALL=en_US.UTF-8 +export LANG=en_US.UTF-8 +~~~~~~~~ + +in `~/.cshrc`: + +~~~~~~~~ {.bash} +setenv LC_ALL en_US.UTF-8 +setenv LANG en_US.UTF-8 +~~~~~~~~ + + +If you already have Eclipse installed, and want to download the source repositories from within the IDE, you need the [MercurialEclipse](http://javaforge.com/project/HGE) plugin, which you can install from this update-site: http://cbes.javaforge.com/update + +Note that NetBeans comes with Mercurial support by default. + + +## Apache Ant ## + +Although you can also build from Eclipse, we use [Apache Ant](http://ant.apache.org) as our primary build system. **Ant is no longer included in the jpf-core distribution** so you have to install it separately. Currently (as of Ant 1.9.3), this involves + + * getting Ant binaries e.g. from http://www.apache.org/dist/ant/binaries/ + * setting the `ANT_HOME` environment variable to the directory where you unpacked the binaries + * adding `ANT_HOME/bin` to your `PATH` environment variable + + +## JUnit ## + +Our Ant script (build.xml) includes a `test` target which uses [JUnit](http://junit.org) to run regression tests. **JUnit is no longer included in the jpf-core distribution**. For JUnit-4.11 installation involves the following steps + + * get junit-.jar and hamcrest-core-.jar, e.g. from the links on https://github.com/junit-team/junit/wiki/Download-and-Install + * add both jars to your `CLASSPATH` environment variable + + +## JPF IDE plugins ## + +JPF components come with project configurations for both [NetBeans](http://www.netbeans.org) and [Eclipse](http://www.eclipse.org), so you might want to use your favorite IDE. Since the JPF build process is [Ant](http://ant.apache.org)-based, NetBeans is generally a better fit because it is Ant-based and can make direct use of your JPF site configuration. + +If you want to install the [Eclipse plugin](./eclipse-jpf), you need an Eclipse version >= 3.5 (Galileo) **running under JavaSE-1.8**. Please see the [Installing the Eclipse JPF plugin](./eclipse-plugin) page for details. + +If you want to go with Eclipse and have to rebuild the JPF [Eclipse plugin](./eclipse-jpf), make sure you install the Eclipse Plugin Development Environment (PDE) from the respective Eclipse server. + +If you want to use the [NetBeans plugin](./netbeans-jpf), the minimal NetBeans version is 6.5. \ No newline at end of file diff --git a/doc/install/site-properties.md b/doc/install/site-properties.md new file mode 100644 index 0000000..691fa4d --- /dev/null +++ b/doc/install/site-properties.md @@ -0,0 +1,32 @@ +# Creating a site.properties file # + +The site.properties file tells JPF at startup time where to look for installed projects, so that it can add classpaths accordingly without you having to type off your fingers. It is a normal [Java properties](http://en.wikipedia.org/wiki/.properties) file, which supports a few additional things like key expansion. + +While you can tell JPF at startup time where to look for `site.properties`, we recommend using the default location, which is **`/.jpf/site.properties`**. If you don't know what value the standard Java system property `user.home` has on your machine, please run the attached Java program. On Unix systems, this is your home directory. + +Assuming that you installed your JPF projects under `/projects/jpf`, a typical `site.properties` looks like this: + +~~~~~~~~ {.bash} +# JPF site configuration + +jpf-core = ${user.home}/projects/jpf/jpf-core + +# numeric extension +jpf-numeric = ${user.home}/projects/jpf/jpf-numeric + +# annotation-based program properties extension +jpf-aprop = ${user.home}/projects/jpf/jpf-aprop + +extensions=${jpf-core},${jpf-aprop} + +#... and all your other installed projects +~~~~~~~~ + +If you are a Windows user, and you want to enter absolute pathnames, don't use unquoted backslashes '\' since the `java.util.Properties` parser would interpret these as special chars (like `"\n"`). You can use ordinary slashes '/' instead. To avoid drive letters, use system properties like `${user.home}`. + + +A sample site.properties file is attached to this page. Note that the "`${..}`" terms are automatically expanded by JPF, i.e. you do not have to enter explicit paths. + +Each installed project is defined by a "` = `" key/value pair. The project name is usually the same as the repository name. + +Note that we don't require anymore that all projects are in the extensions list, **but** jpf-core (or wherever your JPF core classes are) now needs to be in there. In fact, you probably want to have only `jpf-core` in `extensions`, and use the `@using ` for the other ones from either your project properties (jpf.properties, for project dependencies) or - usually - from your application properties (*.jpf) files. See [JPF configuration](../user/config) for details. \ No newline at end of file diff --git a/doc/install/snapshot.md b/doc/install/snapshot.md new file mode 100644 index 0000000..d7839c1 --- /dev/null +++ b/doc/install/snapshot.md @@ -0,0 +1,14 @@ +# Downloading Binary Snapshots # + + +Available binary snapshots are attached as *.zip archives to the [jpf-core](../jpf-core/index) page. Just click the on the download link and tell your browser where to store them on disk, which you need to remember for your subsequent [site.properties](../install/site-properties) configuration. We recommend putting all JPF modules under a single parent directory that holds the site.properties file: + +~~~~~~~~ {.bash} +jpf/ + site.properties + jpf-core/ + jpf-symbc/ + … +~~~~~~~~ + +Many JPF modules are still fast moving, so we recommend using the source repositories to stay up-to-date. Our policy is to only push changes to this server which pass all regression tests \ No newline at end of file diff --git a/doc/intro/classification.md b/doc/intro/classification.md new file mode 100644 index 0000000..667e755 --- /dev/null +++ b/doc/intro/classification.md @@ -0,0 +1,25 @@ +# JPF Key Features # + +By now, it should be clear that JPF is not just a model checker: it is a JVM that can be used for model checking. However, if you are familiar with formal methods, you might want to know what kind of model checking methods and features are supported. + +Some of the basic model checking traits are: + +* **Explicit State** model checking is JPF's standard mode of operation. It means JPF keeps track of concrete values of local variables, stackframes, heap objects and thread states. Other than the intentionally different scheduling behavior, JPF should produce the same results like a normal JVM. Of course it is slower (it is a JVM running on top of a JVM, doing a lot of additional work). + +* **Symbolic Execution** means that JPF can perform program execution with symbolic values obtained from how a certain variable was used along the current path of execution (e.g. `x>0 && x<43`). Moreover, JPF can even mix concrete and symbolic execution, or switch between them. Please see the Symbolic Pathfinder project documentation for details. + +* **State Matching** is a key mechanism to avoid unnecessary work. The execution state of a program mainly consists of heap and thread-stack snapshots. While JPF executes, it checks every new state if it already has seen an equal one, in which case there is no use to continue along the current execution path, and JPF can backtrack to the nearest non-explored non-deterministic choice. What variables contribute to state matching, and how state matching is performed can be controlled by the user. + +* **Backtracking** means that JPF can restore previous execution states, to see if there are unexplored choices left. For instance, if JPF reaches a program end state, it can walk backwards to find different possible scheduling sequences that have not been executed yet. While this theoretically can be achieved by re-executing the program from the beginning, backtracking is a much more efficient mechanism if state storage is optimized. + +* **Partial Order Reduction** is what JPF employs to minimize context switches between threads that do not result in interesting new program states. This is done on-the-fly, i.e. without prior analysis or annotation of the program, by examining which instructions can have inter-thread effects. While this is fast, it cannot handle the “diamond case”, since it cannot look ahead of the current execution. + +JPF's flexibility is achieved by an architecture that provides a large number of extension points, of which the most important ones are: + + * search strategies - to control in which order the state space is searched + * listeners - to monitor and interact with JPF execution (e.g. to check for new properties) + * native peers - to model libraries and execute code at the host VM level + * bytecode factories - to provide different execution models (like symbolic execution) + * publishers - to generate specific reports + +In general, flexibility through configuration is JPF's answer to the scalability problem of software model checking. \ No newline at end of file diff --git a/doc/intro/index.md b/doc/intro/index.md new file mode 100644 index 0000000..8fcec1f --- /dev/null +++ b/doc/intro/index.md @@ -0,0 +1,17 @@ +# Introduction # +JPF started as a software model checker, but nowadays, JPF is a runtime system with many different execution modes and extensions which go beyond model checking. All the various modes of JPF, while serving different purposes, used to verify Java programs by + + * detecting and explaining defects + * collecting "deep" runtime information like coverage metrics + * deducing interesting test vectors and creating corresponding test drivers + * and many more... + +Although JPF is mostly associated with software model checking, it can be applied in variety of ways. People often confuse this with testing, and indeed JPF's notion of model checking can be close to systematic testing. Below we use a simple example that illustrates the differences. + +Here is the outline of this section: + + * [What is JPF?](what_is_jpf) + * [Testing vs. Model Checking](testing_vs_model_checking) + * [Random value example](random_example) + * [Data race example](race_example) + * [JPF key features](classification) diff --git a/doc/intro/race_example.md b/doc/intro/race_example.md new file mode 100644 index 0000000..bb7074b --- /dev/null +++ b/doc/intro/race_example.md @@ -0,0 +1,105 @@ +# Example: Data Race # + +That's nice, but of course we also could have provoked the error in our random value example by using explicit loops instead of the `Random.nextInt()` calls, i.e. by explicitly enumerating all possible `a` and `b` values in our program. This would be typically done in a program that is a dedicated test driver, in a process which is called *systematic testing*. However, the program we want to verify might not be a test driver, and we might not even have the sources so that we could modify it accordingly. + +But the real show stopper for systematic testing lies within the instructions representing choices: at the application level, we might neither be aware of that there are choices, what the choice values are, nor be able to explicitly pick them. + +To demonstrate this point, let us look at a little concurrency example using two threads of execution. Quite obviously, the program produces different results depending on if line (2) or (4) gets executed first. But assuming we can't control what happens in (1) and (2), this time we cannot explicitly enumerate the choices - they are made by the system scheduler, i.e. outside of our application. + +~~~~~~~~ {.java} +public class Racer implements Runnable { + + int d = 42; + + public void run () { + doSomething(1000); // (1) + d = 0; // (2) + } + + public static void main (String[] args){ + Racer racer = new Racer(); + Thread t = new Thread(racer); + t.start(); + + doSomething(1000); // (3) + int c = 420 / racer.d; // (4) + System.out.println(c); + } + + static void doSomething (int n) { + // not very interesting.. + try { Thread.sleep(n); } catch (InterruptedException ix) {} + } +} +~~~~~~~~ + +Chances are, we don't encounter this defect at all during normal testing: + +~~~~~~~~ {.bash} +> java Racer +10 +> +~~~~~~~~ + +Not so with JPF. Being a real virtual machine, there is nothing we can't control. And being a different kind of a Java virtual machine, JPF recognizes that 'racer' is an object that is shared between two threads, and hence executes all possible statement sequences / scheduling combinations in which this object can be accessed. This time, we give the complete output, which also shows the trace (the execution history) that lead to the defect found by JPF: + +~~~~~~~~ {.bash} +> bin/jpf Racer +JavaPathfinder v4.1 - (C) 1999-2007 RIACS/NASA Ames Research Center +====================================================== system under test +application: /Users/pcmehlitz/tmp/Racer.java + +====================================================== search started: 5/24/07 12:32 AM +10 +10 + +====================================================== error #1 +gov.nasa.jpf.jvm.NoUncaughtExceptionsProperty +java.lang.ArithmeticException: division by zero + at Racer.main(Racer.java:20) + +====================================================== trace #1 +------------------------------------------------------ transition #0 thread: 0 +gov.nasa.jpf.jvm.choice.ThreadChoiceFromSet {>main} + [insn w/o sources](282) + Racer.java:15 : Racer racer = new Racer(); + Racer.java:1 : public class Racer implements Runnable { + [insn w/o sources](1) + Racer.java:3 : int d = 42; + Racer.java:15 : Racer racer = new Racer(); + Racer.java:16 : Thread t = new Thread(racer); + [insn w/o sources](51) + Racer.java:16 : Thread t = new Thread(racer); + Racer.java:17 : t.start(); +------------------------------------------------------ transition #1 thread: 0 +gov.nasa.jpf.jvm.choice.ThreadChoiceFromSet {>main,Thread-0} + Racer.java:17 : t.start(); + Racer.java:19 : doSomething(1000); // (3) + Racer.java:6 : try { Thread.sleep(n); } catch (InterruptedException ix) {} + [insn w/o sources](2) + Racer.java:6 : try { Thread.sleep(n); } catch (InterruptedException ix) {} + Racer.java:7 : } + Racer.java:20 : int c = 420 / racer.d; // (4) +------------------------------------------------------ transition #2 thread: 1 +gov.nasa.jpf.jvm.choice.ThreadChoiceFromSet {main,>Thread-0} + Racer.java:10 : doSomething(1000); // (1) + Racer.java:6 : try { Thread.sleep(n); } catch (InterruptedException ix) {} + [insn w/o sources](2) + Racer.java:6 : try { Thread.sleep(n); } catch (InterruptedException ix) {} + Racer.java:7 : } + Racer.java:11 : d = 0; // (2) +------------------------------------------------------ transition #3 thread: 1 +gov.nasa.jpf.jvm.choice.ThreadChoiceFromSet {main,>Thread-0} + Racer.java:11 : d = 0; // (2) + Racer.java:12 : } +------------------------------------------------------ transition #4 thread: 0 +gov.nasa.jpf.jvm.choice.ThreadChoiceFromSet {>main} + Racer.java:20 : int c = 420 / racer.d; // (4) + +====================================================== search finished: 5/24/07 12:32 AM +> +~~~~~~~~ + +Looking at the output created by our test program, we see the result `"10"` printed twice, but that doesn't confuse us anymore. From our first example, we know this simply means that JPF first tried two scheduling sequences that normally terminated the program without provoking the defect, before finally picking the one that causes the error. + +It still might be a bit confusing that the printed trace contains some source lines twice. Ignoring the details of its choice generation mechanism, this is caused by JPF executing bytecode instructions, not source lines, and a single source line can easily get translated into a number of bytecode instructions. This would go away if we configure JPF so that it reports the executed bytecode, but at the cost of much larger trace that is harder to read. What is more interesting is that JPF tells us about the thread choices it made in each transition (the lines starting with `gov.nasa.jpf.jvm.ThreadChoice..`). diff --git a/doc/intro/random_example.md b/doc/intro/random_example.md new file mode 100644 index 0000000..3499e9f --- /dev/null +++ b/doc/intro/random_example.md @@ -0,0 +1,95 @@ +# Example: `java.util.Random` # + +We start with a simple example that uses java.util.Random. Consider the following program that obtains two random values in (2) and (3), and then performs some computation (4) with them. + +~~~~~~~~ {.java} +import java.util.Random; + +public class Rand { + public static void main (String[] args) { + Random random = new Random(42); // (1) + + int a = random.nextInt(2); // (2) + System.out.println("a=" + a); + + //... lots of code here + + int b = random.nextInt(3); // (3) + System.out.println(" b=" + b); + + int c = a/(b+a -2); // (4) + System.out.println(" c=" + c); + } +} +~~~~~~~~ + + +## Testing ## + +Executing this program with a normal Java VM yields something like the following output. If we don't provide an explicit seed when creating the Random object in (1), the result is going to differ between runs, but every run will choose just a single `a` and `b` value (i.e. print just a single `"a=.."` and `"b=.."` line. + +~~~~~~~~ {.java} +> java Rand +a=1 + b=0 + c=-1 +> +~~~~~~~~ + +Let's look at a graphical representation of all the ways our program could be executed, and how it actually was executed in our test run. The nodes of the graph represent *program states*, and the edges *transitions* the execution could take from a certain state. + +![Figure 1: Random example](../graphics/sw-model-checking.svg){align=center width=700} + +## Model Checking ## + +Enter JPF - not much different results if we start JPF as a plain 'java' replacement. The only difference is that it (a) takes longer to complete, and (b) tells us something about a "search", which hints on that something more than in our test run is going on + +~~~~~~~~ {.bash} +> bin/jpf Rand +JavaPathfinder v4.1 - (C) 1999-2007 RIACS/NASA Ames Research Center +====================================================== system under test +application: /Users/pcmehlitz/tmp/Rand.java + +====================================================== search started: 5/23/07 11:48 PM +a=1 + b=0 + c=-1 + +====================================================== results +no errors detected + +====================================================== search finished: 5/23/07 11:48 PM +> +~~~~~~~~ + +What is this "search" supposed to mean? Looking at source line (4) we realize that there is a potential problem: for certain `a` and `b` values, this expression can cause a division by zero `ArithmeticException`. Depending on the random seed used in (1), it's quite possible we would never encounter this case if we run (i.e. test) the program with a normal JVM. + +Re-enter JPF - but this time we tell it to not only consider single values for `a` and `b`, but look at all possible choices: + +~~~~~~~~ {.bash} +> bin/jpf +cg.enumerate_random=true Rand +JavaPathfinder v4.1 - (C) 1999-2007 RIACS/NASA Ames Research Center +====================================================== system under test +application: /Users/pcmehlitz/tmp/Rand.java + +====================================================== search started: 5/23/07 11:49 PM +a=0 + b=0 + c=0 + b=1 + c=0 + b=2 + +====================================================== error #1 +gov.nasa.jpf.jvm.NoUncaughtExceptionsProperty +java.lang.ArithmeticException: division by zero + at Rand.main(Rand.java:15) +.... +> +~~~~~~~~ + +What has happened? By specifying "+vm.enumerate_random=true" we told JPF to consider all possible values for expressions (2) and (3). JPF starts with `"a=0"`, then picks `"b=0"`, which yields a valid `"c=0"` value. But instead of terminating like a normal VM, JPF recognized that there are more choices left, so it backtracks to (3) and picks `"b=1"`. Again, no problem here with computing `"c=0"`. Back to (3), JPF now tries `"b=2"`, which of course spells disaster for our little program when executing (4), as can be seen by the following error report. + +Here is a graphical representation of this search process. It should be noted that JPF per default only runs up to the point where it finds an error or there are no more choices left to explore. But if we would somehow fix the `"a=0,b=2"` case, JPF would still find the `"a=1,b=1"` case in the next run, since it systematically tries all choices. No matter what error it finds, JPF also keeps the complete trace (execution path) how it got to this error (denoted by the red arrows), which means we don't have to debug the program to find out. + +![Figure 2: Random example](../graphics/sw-model-checking-2.svg){align=center width=450} diff --git a/doc/intro/testing_vs_model_checking.md b/doc/intro/testing_vs_model_checking.md new file mode 100644 index 0000000..56b41d5 --- /dev/null +++ b/doc/intro/testing_vs_model_checking.md @@ -0,0 +1,28 @@ +# Testing vs. Model Checking # + +So what JPF does is test our program for defects? No, it usually does more, at least when used as a model checker. How does testing differ from model checking? + +Software testing is an empirical set of techniques where you execute your program with a number of inputs in order to find out if it behaves correctly. This comes with two parts that involve the right choices: test input and test oracle. + +![Figure 1: Testing](../graphics/states-testing.svg){align=center} + +Testing techniques differ on how we choose the input (random, "interesting" problem domain values like corner cases etc.), and on how much knowledge about the SUT and its execution environment we assume (black/grey/white box), which especially affects how we can define and check correct behavior. This involves a lot of educated guesses, or as Edsger Dijkstra has put it: "program testing can at best show the presence of errors but never their absence". We usually compensate this by performing "enough" tests - which would be the next guess. Testing complex systems can easily turn into finding a needle in a haystack. If you are a good tester, you make the right guesses and hit the defect that is inevitably there. If not, don't worry - your users will find it later. + +![Figure 2: Model checking](../graphics/states-mc.svg){align=center} + +[Model Checking](http://en.wikipedia.org/wiki/Model_checking) as a [Formal Method](http://en.wikipedia.org/wiki/Formal_methods) does not depend on guesses. At least as the theory goes, if there is a violation of a given specification, model checking will find it. Model checking is supposed to be a rigorous method that exhaustively explores all possible SUT behaviors. + +To illustrate this, look at the [Random value example](random_example), which shows how testing differs from model checking if we have a program that uses a sequence of random values: the test always processes just one set of values at a time, and we have little control over which ones. Model checking doesn't stop until it has checked all data combinations or has found an error. + +With the random example, we can at least see the choices in our program. Consider a concurrent program, such as [Data race example](race_example) - do you know where the operating system switches between threads? All we know is that different scheduling sequences can lead to different program behavior (e.g. if there are data races), but there is little we can do in our tests to force scheduling variation. There are program/test spec combinations which are "untestable". Being a virtual machine, our software model checker doesn't suffer the same fate - it has complete control over all threads of our program, and can execute all scheduling combinations. + +![Figure 3: Threads interleaving](../graphics/interleavings.svg){align=center width=550} + +That is the theory. In reality "all possible" can be a pretty large number - too large for existing computing resources or our patience. Just assume the number of different scheduling sequences of a program consisting of N threads P,,1,, .. P,,N,, that each have n,,i,, atomic instruction sequences. + +For 2 threads with 2 atomic sections each this gives us 6 different scheduling combinations. For 8 sections the result is 12870, 16 sections yield 601080390 - that is why it is called *state explosion*. Software model checking has a scalability problem, even more so than model checking of hardware, since programs usually have a lot more states. + +There are several things we can do. First, we can optimize the model checker, which is simply an engineering feat. Next, we can find program states which are equivalent with respect to the properties we are checking, which can be done with various degrees of abstractions and value representations. Last, we can try to get to the defect first, before we run out of time or memory. But this is where the boundary between testing and model checking becomes blurred, as it involves things like heuristics about interesting input values or system behaviors, and these heuristics tend to drop reachable program states. + +JPF does all of the above to curb the state space explosion, and most things are configured instead of hardwired, so you don't depend on built-in heuristics. But no matter how much we shrink the state space, JPF can still observe a lot more about the program execution than normal tests (i.e. we can be more precise with our oracles), and it still knows about the execution history in case we find a defect, which is always just the first part - we also need to understand it so that it can be fixed eventually. + diff --git a/doc/intro/what_is_jpf.md b/doc/intro/what_is_jpf.md new file mode 100644 index 0000000..e8a5ce2 --- /dev/null +++ b/doc/intro/what_is_jpf.md @@ -0,0 +1,44 @@ +# What is JPF? # + +That depends on how you configure it. +First and foremost, there is no single, monolithic JPF - it is a runtime configured combination of different components. The project *jpf-core* is the essential component that constitutes the core structure of JPF. +Here we explain what *jpf-core* is. + + +## The Core : a VM that supports Model Checking ## + +![Figure 1: High level view of JPF](../graphics/jpf-basic.svg){align=center width=400} + +The JPF core is a Virtual Machine (VM) for Java™ bytecode. That means that JPF is a program which executes the system under test (SUT). The VM of JPF is able to handle bytecode instructions that are created by a standard Java compiler. While execution semantics of Java bytecodes are clearly defined in [Sun's Java virtual machine specifications](http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html/), we have little hardwired semantics in JPF - the VM instruction set is represented by a set of classes that can be replaced. +JPF is a special VM. JPF itself is written in Java, so it is not as fast as your normal Java. That implies that JPF is VM which is running on top of another VM. + +As JPF executes the SUT, it checks for certain properties which are given to JPF as input. Some of the properties that can be checked by JPF are unhandled exceptions, deadlocks, and user-defined assertions which are used to test properties of the code's behavior. +JPF gets back to you with a report that says if the properties hold and/or which verification artifacts have been created by JPF for further analysis (like test cases). + +JPF (theoretically) explores *all* potential executions in a systematic way. In contrast, an ordinary JVM executes the code in only one possible way. +Basically, JPF can identify points, which represent *execution choices*, in your program from which the execution could proceed differently. Then it systematically explores all of them. +Typical execution choices are different scheduling sequences or random values, but JPF allows you to introduce your own type of choices such as user input or state machine events. + +The number of paths can grow out of hand, and it usually will. This is known as the most challenging problem in software model checking referred to as *state space explosion problem*. +JPF uses different ways to mitigate this problem. The first line of defense employed by JPF is *state matching*: each time JPF reaches a choice point, it checks if it has already seen a similar program state, in which case it can safely abandon this path, *backtrack* to a previous choice point that has still unexplored choices, and proceed from there. That's right, JPF can restore program states, which is like telling a debugger "go back 100 instructions". + +So what are these features used for? Normally to find defects in the SUT, but what kind of defects? By now you know the answer: it depends on how you configure JPF. By default, the core checks for properties that can be identified by the VM without you having to specify them: deadlocks and unhandled exceptions (which also covers Java `assert` expressions). We call these *non-functional* properties, and no application should violate them. But JPF doesn't stop there - you can define your own properties, which is mostly done with so called *listeners*, little "plugins" that let you closely monitor all actions taken by JPF, like executing single instructions, creating objects, reaching a new program state and many more. An example of a property implemented in the form of a listener is a race detector, which identifies unsynchronized access to shared variables in concurrent programs (the JPF core comes with two of them). + +One additional feature that comes in handy in case JPF finds a defect is the complete execution history that leads to the defect, including every executed bytecode instruction. We call this a program *trace*, and it is invaluable to find out what really caused the defect. Think of a deadlock - usually there is not much you can directly deduce from a snapshot of call stacks. + +All this explains why JPF is called "a debugger toolbox on steroids": first it automatically executes your program in all possible ways to find defects you don't even know about yet, then it explains you what caused these defects. + +## Caveat : not a lightweight tool ## + +Of course that is the ideal world. In reality, this can require quite a lot of configuration and even some programming. JPF is not a "black box" tool like a compiler, and the learning curve can be steep. What makes this worse is that JPF cannot execute *native code* which is implemented in a language other than Java but invoked from Java applications. +Not because it doesn't know how to do that, but because it often doesn't make sense: native code like system calls to write to a file cannot easily be reverted - JPF would loose its capability to match or backtrack program states. But of course there is a remedy, and it is configurable: *native peers* and *model classes*. Native peers are classes that hold methods that are executed in lieu of real native methods. This code is executed by the real Java VM, not JPF, hence it can also speed up things. Model classes are simple replacements of standard classes, like `java.lang.Thread` that provide alternatives for native methods which are fully observable and backtrackable. + +If you are familiar with Java implementations, you know about the humongous proportions of the included libraries, and hence it is obvious that we cannot handle all of them, at least not yet. There is no theoretical limit, and implementing missing library methods is usually pretty easy, but you should be prepared to encounter `UnsatisfiedLinkErrors` and such if you let JPF loose on large production systems. Notorious white spots are `java.io` and `java.net`, but there are people working on it. Who knows, maybe you are interested to join the effort - JPF is open sourced and there is nothing you can't see. We now have more than two dozen major collaborators in industry, government and academia around the world. + +So what makes it worthwhile to invest in JPF? After all, it is a heavyweight tool, not a quick and simple bug finder. First, if you are looking for a research platform to try out your new software verification ideas, chances are you can get along with JPF in a fraction of time compared to native production VMs, which are typically optimized towards speed and care little about extensibility or observability. + +The second answer is that - as of this writing - there are bugs *only* JPF can find (before the fact, that is), and there are more and more Java applications that cannot afford to learn about these bugs after the fact. JPF is a tool for mission critical applications, where failure is not an option. No surprise it was started by NASA. + + + diff --git a/doc/jpf-core/AssertionProperty.md b/doc/jpf-core/AssertionProperty.md new file mode 100644 index 0000000..21c49e8 --- /dev/null +++ b/doc/jpf-core/AssertionProperty.md @@ -0,0 +1,88 @@ +# AssertionProperty # + +This listener adds some special capabilities for `java.lang.AssertionError` processing: + + * report `AssertionErrors` that are otherwise carelessly caught in `... catch (Throwable t) {..}` clauses + * ignore AssertionErrors if `ap.go_on` is set + +`AssertionErrors` differ a bit from other exceptions - they should never be handled, and they usually represent functional properties (as opposed to non-functionals like `NullPointerExceptions` and `ArithmeticExceptions`). Consequently, it can be regarded as an error if an `AssertionError` is swallowed by a 'catch-all', and it is at least an option to ignore an unhandled `AssertionError`, e.g. to see what non-functional defects - if any - it might cause downstream. + +### Example 1: catch-all ### + +~~~~~~~~ {.java} +public class CatchAll { + public static void main(String[] args){ + try { + int d = 42; + //.. some stuff + assert d > 50 : "d below threshold"; + int x = d - 50; + //.. some more stuff + } catch (Throwable t) { // bad + // ..I'm careless + } + } +} +~~~~~~~~ + +Checked with: + +~~~~~~~~ {.bash} +>jpf +listener=.listener.AssertionProperty CatchAll +~~~~~~~~ + +Produces: + +~~~~~~~~ +JavaPathfinder v5.0 - (C) 1999-2007 RIACS/NASA Ames Research Center +====================================================== system under test +application: CatchAll.java + +====================================================== search started: 10/13/09 1:33 PM + +====================================================== error #1 +gov.nasa.jpf.listener.AssertionProperty +d below threshold +... +~~~~~~~~ + + +### Example 2: go-on ### + +~~~~~~~~ {.java} +public class GoOn { + public static void main (String[] args){ + int d = 42; + // lots of computations... + assert d > 50 : "d below threshold"; + int x = Math.max(0, d - 50); + // lots of more computations... + int y = 42000 / x; + } +} +~~~~~~~~ + +Checked with + +~~~~~~~~ {.bash} +>jpf +listener=.listener.AssertionProperty +ap.go_on GoOn +~~~~~~~~ + +Produces: + +~~~~~~~~ {.bash} +JavaPathfinder v5.0 - (C) 1999-2007 RIACS/NASA Ames Research Center + +====================================================== system under test +application: GoOn.java + +====================================================== search started: 10/13/09 1:59 PM +WARNING - AssertionError: d below threshold + at GoOn.main(GoOn.java:5) + +====================================================== error #1 +gov.nasa.jpf.jvm.NoUncaughtExceptionsProperty +java.lang.ArithmeticException: division by zero + at GoOn.main(GoOn.java:8) +... +~~~~~~~~ diff --git a/doc/jpf-core/ErrorTraceGenerator.md b/doc/jpf-core/ErrorTraceGenerator.md new file mode 100644 index 0000000..0edf13c --- /dev/null +++ b/doc/jpf-core/ErrorTraceGenerator.md @@ -0,0 +1,32 @@ +## Error Trace Generator ## + +This is a listener to output a lightweight error trace. It prints the instructions at POR boundaries or points where there are multiple choices. An example is shown below. + +~~~~~~~~ + +====================### Lightweight Error Trace ###======================= + + +Length of Error Trace: 35 +--------------------------------------------------- Thread1 + Event.wait_for_event(oldclassic.java:79) + wait(); +--------------------------------------------------- Thread2 + SecondTask.run(oldclassic.java:129) + if (count == event2.count) { // ditto +--------------------------------------------------- Thread2 + SecondTask.run(oldclassic.java:127) + event1.signal_event(); // updates event1.count +--------------------------------------------------- Thread2 + SecondTask.run(oldclassic.java:133) + count = event2.count; // ditto +--------------------------------------------------- Thread1 + FirstTask.run(oldclassic.java:103) + event1.wait_for_event(); +--------------------------------------------------- Thread1 + +~~~~~~~~ + +Configuration: **+listener=gov.nasa.jpf.listener.ErrorTraceGenerator** + +Note the Error trace generator does not have the same memory bottlenecks as **report.console.property_violation=trace** that stores every bytecode instruction executed along the path from the start of the program to the error state. The error trace generator dynamically recreates the counterexample by tracing back to the start from the error state. The head of the error trace (list shown in the example) represents the last instruction in the error trace while the tail represents the first instruction. \ No newline at end of file diff --git a/doc/jpf-core/ExceptionInjector.md b/doc/jpf-core/ExceptionInjector.md new file mode 100644 index 0000000..4ab7766 --- /dev/null +++ b/doc/jpf-core/ExceptionInjector.md @@ -0,0 +1,105 @@ +# ExceptionInjector # + +The ExceptionInjector is a listener that can throw user configured exceptions at arbitrary program locations. The main purpose is to ease the testing of exception handler code that would otherwise hard to reach, e.g. because it is not clear if/how an exception could be thrown in 3rd party code. + +## Properties ## + +~~~~~~~~ {.bash} +**ei.exception** = ;... \ + + := '@' \ + + := [[string-literal]('(') ')'] \ + + := ':'line | '.'[ [[BR](':'line])] +~~~~~~~~ + +Relative line numbers count from the first executable statement in the method body. They are mostly used to have tests that are more robust against changes in the target source file. + +If a method is given without a line offset, the exception is thrown before executing INVOKE instructions that call the specified method. + +If a line is specified (either absolute or method-body relative), the exception is thrown before executing the associated bytecode at this line. + +If more than one exception specification is given, these need to be separated by semicolons ';' (commas cannot be used because they can appear within argument type lists of the target method). + +Method argument types have to be specified the same way as they are reported by 'javap', i.e. with fully qualified type names in dot notation (e.g. "`foo(java.lang.String,int[])`"). Return types can be omitted. + +`ei.throw_first` [`boolean`] - if true, throw exception on first bytecode instruction associated with the given (absolute or relative) source line. If false, throw on last associated bytecode instruction + + +## Examples ## + +### (1) throw exception on absolute line 42 in xyz.MyClass: ### + +The application property file + +~~~~~~~~ {.bash} +target = yxz.MyClass +ei.exception = ArithmeticException@xyz.MyClass:42 +~~~~~~~~ +on file +~~~~~~~~ {.java} +1: package x.y.z; + .. + public class MyClass { + .. + try { + .. +42: int z = x / y; + .. + } catch (ArithmeticException ax){ + // the handler code to test + } + .. +~~~~~~~~ + +will throw an ArithmeticException on line 42 regardless of the 'x' and 'y' values. + +### (2) throw a `Zapp("gotcha")` exception on (relative) line 2 in method body `xyz.MyClass.foo()` ### + +The application property file + +~~~~~~~~ {.bash} +target = yxz.MyClass +ei.exception = Zapp("gotcha")@xyz.MyClass.foo(int[]):2 +~~~~~~~~ +on file +~~~~~~~~ {.java} + package x.y.z; + .. + public class MyClass { + .. + void foo (int[] whatever) { + // some comment (doesn't count for line offsets) ++0: int n = .. // first statement line in foo() ++1: // some more comment (does count for line offsets) ++2: doSomething(n); // can throw a Zapp exception + .. +~~~~~~~~ +will throw a Zapp("gotcha") exception on relative line 2 of method body xyz.MyClass.foo(). Note that the line offset counts from the first executable statement line within foo(). + + +### (3) throw an `IOException` when calling `File.createTempFile()` ### +The application property file + +~~~~~~~~ {.bash} +target = yxz.MyClass +ei.exception = java.io.IOException@java.io.File.createTempFile(java.lang.String,java.lang.String) +~~~~~~~~ + +will throw an exception on the first call of File.createTempFile(), regardless of where this occurs and what the parameters to the call are + +~~~~~~~~ {.java} +1: package x.y.z; + .. + public class MyClass { + .. + try { + .. + File tmp = File.createTempFile(prefix,suffix); + .. + } catch (IOException iox) { + // the handler code to test + } + .. +~~~~~~~~ diff --git a/doc/jpf-core/IdleFilter.md b/doc/jpf-core/IdleFilter.md new file mode 100644 index 0000000..03c6e98 --- /dev/null +++ b/doc/jpf-core/IdleFilter.md @@ -0,0 +1,99 @@ +# IdleFilter # + +The `gov.nasa.jpf.listener.IdleFilter` is a listener that can be used to close state spaces with loops. Consider a simple "busy waiting" loop + +~~~~~~~~ {.java} +for (long l=0; l<10000000; l++); +~~~~~~~~ + +While not a good thing to do in general, it is benign if executed in a normal VM. For JPF, it causes trouble because it adds a lot of useless steps to the stored path, and slows down execution considerably. + +In addition, people who expect JPF to match states can get surprised by programs like + +~~~~~~~~ {.java} +while (true){ + // no transition break in here +} +~~~~~~~~ +not being state matched, and hence not terminating (it wouldn't terminate in a normal VM either). + +`IdleFilter` is a little tool to deal with such (bad) loops. It counts the number of back-jumps it encounters within the same thread and stackframe, and if this number exceeds a configured threshold it takes one of the following actions: + + * warn - just prints out a warning that we have a suspicious loop + * break - breaks the transition at the back-jump `goto` instruction, to allow state matching + * prune - sets the transition ignored, i.e. prunes the search tree + * jump - skips the back-jump. This is the most dangerous action since you better make sure the loop does not contain side-effects your program depends on. + + +### Properties ### +Consequently, there are two options: + + * `idle.max_backjumps = \` : max number of back-jumps that triggers the configured action (default 500) + * `idle.action = warn|break|prune|jump` : action to take when number of back-jumps exceeds threshold + +### Examples ### + +**(1)** The test program + +~~~~~~~~ {.java} +... +public void testBreak () { + int y = 4; + int x = 0; + + while (x != y) { // JPF should state match on the backjump + x = x + 1; + if (x > 3) { + x = 0; + } + } +} +~~~~~~~~ + +would never terminate under JPF or a host VM. Running it with + +~~~~~~~~ {.bash} +> bin/jpf +listener=.listener.IdleFilter +idle.action=break ... +~~~~~~~~ + +does terminate due to state matching and produces the following report + +~~~~~~~~ {.bash} +... +====================================================== search started: 4/8/10 4:14 PM +[WARNING] IdleFilter breaks transition on suspicious loop in thread: main + at gov.nasa.jpf.test.mc.basic.IdleLoopTest.testBreak(gov/nasa/jpf/test/mc/basic/IdleLoopTest.java:42) +... +====================================================== results +no errors detected +~~~~~~~~ + +----- +**(2)** The following program would execute a long time under JPF + +~~~~~~~~ {.java} +... +public void testJump () { + for (int i=0; i<1000000; i++){ + //... + } + + System.out.println("Ok, jumped past loop"); +} +~~~~~~~~ + +If we run it with + +~~~~~~~~ {.bash} +> bin/jpf +listener=.listener.IdleFilter +idle.action=jump ... +~~~~~~~~ + +JPF comes back quickly with the result + +~~~~~~~~ {.bash} +====================================================== search started: 4/8/10 4:20 PM +[WARNING] IdleFilter jumped past loop in: main + at gov.nasa.jpf.test.mc.basic.IdleLoopTest.testJump(gov/nasa/jpf/test/mc/basic/IdleLoopTest.java:74) +Ok, jumped past loop +... +~~~~~~~~ diff --git a/doc/jpf-core/index.md b/doc/jpf-core/index.md new file mode 100644 index 0000000..28fda0e --- /dev/null +++ b/doc/jpf-core/index.md @@ -0,0 +1,43 @@ +# jpf-core # +This is the basis for all JPF projects, i.e. you always need to install it. jpf-core contains the basic VM and model checking infrastructure, and can be used to check for concurrency defects like deadlocks, and unhandled exceptions like `NullPointerExceptions` and `AssertionErrors`. + + +## Repository ## +The Mercurial repository is on http://babelfish.arc.nasa.gov/hg/jpf/jpf-core + +## Properties ## +jpf-core supports two rather generic properties, which are configured by default: + + * `gov.nasa.jpf.jvm.NoUncaughtExceptionsProperty` + * `gov.nasa.jpf.jvm.NotDeadlockedProperty` + +There is no need to parameterize any of them. `NoUncaughtExceptionsProperty` covers all `Throwable` objects that are not handled within the application, i.e. would terminate the process. + +Some of the listeners (like `PreciseRaceDetector`) are `ListenerAdapter` instances, i.e. work as more specific Property implementations. + +## Listeners ## +jpf-core includes a variety of [listeners](../devel/listener) that fall into three major categories: + + * program properties + * execution monitoring + * execution control + +Some of the main listeners are + + * [AssertionProperty](./AssertionProperty) + * [IdleFilter](./IdleFilter) + * [ExceptionInjector](./ExceptionInjector) + +## Properties ## +jpf-core uses many JPF properties, you can find most of them in the `defaults.properties` file. The following ones are of interest for users + + * `listener` - a comma separated list of class names representing listeners that should be automatically instantiated and registered during JPF startup + * `listener.autoload` - a comma separated list of annotation types. If JPF encounters such an annotation in one of the analyzed classes at runtime, it automatically loads and registered the associated listener + * `listener.` - class name of the listener associated with `` + * `vm.insn_factory.class` - class name of a [`BytecodeInstructionFactory`](../devel/bytecode_factory), e.g. to switch to the symbolic execution mode or to use specific bytecode implementations for checking numeric properties + * `vm.halt_on_throw (true|false)` - tells JPF if it should try to find a handler if it encounters an exception in the analyzed program (useful to avoid masking exceptions within handlers) + * [`cg.randomize_choices`](../user/config/random) `(random|path|def)` - tells JPF if it should randomize the order of choices for each [`ChoiceGenerator`](../devel/choicegenerator), to avoid degenerated searches (e.g. always indexing with the main thread in scheduling choices). + * `report.console.property_violation` - comma separated list of topics that should be printed by JPF if it detects an error. Possible values include + - `error` error description + - `snapshot` thread stacks + - `trace` instruction/statement trace (can be long and memory-expensive) \ No newline at end of file diff --git a/doc/papers/chicago-author-date.csl b/doc/papers/chicago-author-date.csl new file mode 100644 index 0000000..595235f --- /dev/null +++ b/doc/papers/chicago-author-date.csl @@ -0,0 +1,549 @@ + + diff --git a/doc/papers/index.md b/doc/papers/index.md new file mode 100644 index 0000000..87fb93a --- /dev/null +++ b/doc/papers/index.md @@ -0,0 +1,133 @@ +# Related Publications # + +JPF has been both a research target and a system in use for a number of years. A broad collection of papers and reports is available, including the following (incomplete) list + +> **Notes:** some of the older papers now have mostly historical relevance. JPF has undergone a lot of changes since 2000. If you need more recent information, especially about the design and usage of current +JPF versions, please consult the documentation. + + +--- +bibliography: ./references.bib +csl: ./chicago-author-date.csl +... + +## Core Papers ## + +@visser:2003 + +@lerda:2001 + +## JPF Infrastructure and Features ## + +@shafiei:breugel:2014 + +@nshafiei:2012 + +@kulikov:2010 + +## Testing and Symbolic Execution ## + +@indradeep:2013 + +@person:2008 + +@pasareanu:2008 + +@visser:2004 + +@pasareanu:2004 + +@artho:2003 + +@khurshid:2003 + +## Heuristic Search ## + +@groce:2004 + +@groce:2002 + +@groce:visser:2002 + +## Verification of Networked Software ## + +@shafiei:2014 + +@artho:2011 + +@artho:2009 + +@artho:2008 + +## Explaining Counter Examples ## + +@grove:2003 + +## Applying Java PathFinder ## + +@shafiei:2013 + +@stergiopoulos:2012 + +@mehlitz:2008 + +@penix:2005 + +@giannakopoulou:2004 + +@brat:2004 + +@bordini:2003 + + +## Misc ## + +@havelund:2007 + +@mansouri:2007 + +@havelund:2002 + +@pasareanu:dwyer:2003 + +@brat:2001 + +@visser:park:2000 + +@havelund:2000 + +@havelund:1999 + +@havelund:skakkebaek:1999 + +@havelund:Pressburger:1998 + +## Papers from Darko Marinov's group ## + +@gligoric:2010 + +@gligoric:jagannath:2010 + +@lauterburg:2010 + +@sobeih:2010 + +@lauterburg:2009 + +@gligoric:2009 + +@damorim:2008 + +@lauterburg:2008 + +@gvero:2008 + +@damorim:2007 + +@zhou:2007 + +@damorim:2006 + +@damorim:pacheco:2006 + +## References ## \ No newline at end of file diff --git a/doc/papers/references.bib b/doc/papers/references.bib new file mode 100644 index 0000000..698195f --- /dev/null +++ b/doc/papers/references.bib @@ -0,0 +1,636 @@ +@article{visser:2003, + author = {Visser, Willem and Havelund, Klaus and Brat, Guillaume and Park, Seungjoon and Lerda, Flavio}, + title = "{M}odel {C}hecking {P}rograms", + journal = {Automated Software Engineering}, + volume = {10}, + number = {2}, + month = {April}, + year = {2003}, + pages = {203--232}, + publisher = {Kluwer Academic Publishers}, + url = "http://dl.acm.org/citation.cfm?id=641186" + } + +@inproceedings{lerda:2001, + author = {Lerda, Flavio and Visser, Willem}, + title = {Addressing Dynamic Issues of Program Model Checking}, + booktitle = {Proceedings of the 8th International SPIN Workshop on Model Checking of Software}, + year = {2001}, + pages = {80--102}, + publisher = {Springer}, + url = "http://dl.acm.org/citation.cfm?id=380921.380931", +} + +@inproceedings{khurshid:2003, + author = {Sarfraz Khurshid and Corina S. P\v{a}s\v{a}reanu and Willem Visser}, + title = {Generalized Symbolic Execution for Model Checking and Testing}, + booktitle = {Proceedings of the Ninth International Conference on Tools and Algorithms for the Construction and Analysis of Systems}, + year = {2003}, + pages = {553--568}, + publisher = {Springer}, + url = "http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.8.8862" +} + +@article{visser:2004, + author = {Visser, Willem and P\v{a}s\v{a}reanu, Corina S. and Khurshid, Sarfraz}, + title = {Test Input Generation with Java PathFinder}, + journal = {Proceedings of International Symposium on Software Testing and Analysis}, + volume = {29}, + number = {4}, + month = jul, + year = {2004}, + pages = {97--107}, + publisher = {ACM}, + url = "http://dl.acm.org/citation.cfm?id=1007526", +} + +@article{pasareanu:2004, +year={2004}, +volume={2989}, +series={Lecture Notes in Computer Science}, +title={Verification of Java Programs Using Symbolic Execution and Invariant Generation}, +url={http://link.springer.com/chapter/10.1007%2F978-3-540-24732-6_13#}, +publisher={Springer}, +author={Păsăreanu, Corina S. and Visser, Willem}, +pages={164-181}, +} + +@inproceedings{person:2008, + author = {Person, Suzette and Dwyer, Matthew B. and Elbaum, Sebastian and P\v{a}s\v{a}reanu, Corina S.}, + title = {Differential Symbolic Execution}, + booktitle = {Proceedings of the 16th {ACM} {SIGSOFT} International Symposium on Foundations of Software Engineering}, + year = {2008}, + pages = {226--237}, + url = {http://doi.acm.org/10.1145/1453101.1453131}, + publisher = {ACM}, + } + +@inproceedings{pasareanu:2008, + author = {Corina S. P\v{a}s\v{a}reanu and + Peter C. Mehlitz and + David H. Bushnell and + Karen Gundy{-}Burlet and + Michael R. Lowry and + Suzette Person and + Mark Pape}, + title = {Combining unit-level symbolic execution and system-level concrete + execution for testing {NASA} software}, + booktitle = {Proceedings of the {ACM} {SIGSOFT} International Symposium on Software + Testing and Analysis}, + pages = {15--26}, + year = {2008}, + url = {http://doi.acm.org/10.1145/1390630.1390635}, +} + +@inproceedings{pasareanu:2007, + author = {Corina S. P\v{a}s\v{a}reanu and + Willem Visser}, + title = {Symbolic Execution and Model Checking for Testing}, + booktitle = {Hardware and Software: Verification and Testing, Third International + Haifa Verification Conference}, + pages = {17--18}, + year = {2007}, + url = {http://dx.doi.org/10.1007/978-3-540-77966-7_5}, +} + +@inproceedings{artho:2003, + author = {Cyrille Artho and + Doron Drusinsky and + Allen Goldberg and + Klaus Havelund and + Michael R. Lowry and + Corina S. P\v{a}s\v{a}reanu and + Grigore Rosu and + Willem Visser}, + title = {Experiments with Test Case Generation and Runtime Analysis}, + booktitle = {Abstract State Machines, Advances in Theory and Practice}, + pages = {87--107}, + year = {2003}, + url = {http://dx.doi.org/10.1007/3-540-36498-6_5}, +} + +@article{groce:2004, + author = {Alex Groce and + Willem Visser}, + title = {Heuristics for model checking Java programs}, + journal = {International Journal on Software Tools for Technology Transfer}, + volume = {6}, + number = {4}, + pages = {260--276}, + year = {2004}, + url = {http://dx.doi.org/10.1007/s10009-003-0130-9}, +} + +@inproceedings{groce:2002, + author = {Alex Groce and + Willem Visser}, + title = {Model checking Java programs using structural heuristics}, + booktitle = {Proceedings of International Symposium on Software Testing and Analysis}, + pages = {12--21}, + year = {2002}, + url = {http://doi.acm.org/10.1145/566172.566175}, +} + +@inproceedings{groce:visser:2002, + author = {Alex Groce and + Willem Visser}, + title = {Heuristic Model Checking for Java Programs}, + booktitle = {Proceedings of the 9th International SPIN Workshop on Model Checking of Software}, + pages = {242--245}, + year = {2002}, + url = {http://dx.doi.org/10.1007/3-540-46017-9_21}, +} + +@inproceedings{artho:2011, + author = {Leungwattanakit, Watcharin and Artho, Cyrille and Hagiya, Masami and Tanabe, Yoshinori and Yamamoto, Mitsuharu}, + title = {Model checking distributed systems by combining caching and process checkpointing}, + booktitle = {Proceedings of the 26th IEEE/ACM International Conference on International Conference on Automated Software Engineering}, + year = {2011}, + pages = {103--112}, + publisher = {IEEE}, +month={November}, + address = {Lawrence, KS, USA}, + url = {​http://staff.aist.go.jp/c.artho/papers/checkpointing.pdf}, +} + +@inproceedings{artho:2009, + author = {Artho, Cyrille and Leungwattanakit, Watcharin and Hagiya, Masami and Tanabe, Yoshinori and Yamamoto, Mitsuharu}, + title = {Cache-Based model Checking of Networked Applications: From Linear to Branching Time}, + booktitle = {Proceedings of the 27th International Conference on Automated Software Engineering}, + year = {2009}, +month = {November}, + pages = {447--458}, + publisher = {IEEE}, + address = {Auckland, New Zealand}, + url = {​http://staff.aist.go.jp/c.artho/papers/ase-2009.pdf}, +} + +@inproceedings{artho:2008, +author={Artho, Cyrille and Leungwattanakit, Watcharin and Hagiya, Masami and Tanabe, Yoshinori}, +title={Efficient Model Checking of Networked Applications}, +year={2008}, +volume={11}, +series={Lecture Notes in Business Information Processing}, +booktitle = {Proceedings of the 46th International Conference on Objects, Components, Models and Patterns}, +publisher={Springer}, +pages={22--40}, +address={Zurich, Switzerland}, +month={June/July}, +url = {http://staff.aist.go.jp/c.artho/papers/tools-2008.pdf} +} + +@inproceedings{grove:2003, + author = {Alex Groce and + Willem Visser}, + title = {What Went Wrong: Explaining Counterexamples}, + booktitle = {Proceedings of the 10th International SPIN Workshop on Model Checking of Software}, + pages = {121--135}, + year = {2003}, + url = {http://dx.doi.org/10.1007/3-540-44829-2_8}, + publisher = {Springer}, + address = {Portland}, +} + +@article{penix:2005, + author = {John Penix and + Willem Visser and + Seungjoon Park and + Corina S. P\v{a}s\v{a}reanu and + Eric Engstrom and + Aaron Larson and + Nicholas Weininger}, + title = {Verifying Time Partitioning in the {DEOS} Scheduling Kernel}, + journal = {Formal Methods in System Design}, + volume = {26}, + number = {2}, + pages = {103--135}, + year = {2005}, + url = {http://dx.doi.org/10.1007/s10703-005-1490-4}, +} + +@article{brat:2004, + author = {Guillaume P. Brat and + Doron Drusinsky and + Dimitra Giannakopoulou and + Allen Goldberg and + Klaus Havelund and + Michael R. Lowry and + Corina S. Pasareanu and + Arnaud Venet and + Willem Visser and + Richard Washington}, + title = {Experimental Evaluation of Verification and Validation Tools on Martian + Rover Software}, + journal = {Formal Methods in System Design}, + volume = {25}, + number = {2-3}, + pages = {167--198}, + year = {2004}, + url = {http://dx.doi.org/10.1023/B:FORM.0000040027.28662.a4}, +} + +@inproceedings{bordini:2003, + author = {Rafael H. Bordini and + Michael Fisher and + Carmen Pardavila and + Willem Visser and + Michael Wooldridge}, + title = {Model Checking Multi-Agent Programs with {CASP}}, + booktitle = {Proceedings of Computer Aided Verification}, + pages = {110--113}, + year = {2003}, + url = {http://dx.doi.org/10.1007/978-3-540-45069-6_10}, +} + +@inproceedings{giannakopoulou:2004, + author = {Dimitra Giannakopoulou and + Corina S. Pasareanu and + Jamieson M. Cobleigh}, + title = {Assume-Guarantee Verification of Source Code with Design-Level Assumptions}, + booktitle = {26th International Conference on Software Engineering {(ICSE} 2004), + 23-28 May 2004, Edinburgh, United Kingdom}, + pages = {211--220}, + year = {2004}, + url = {http://doi.ieeecomputersociety.org/10.1109/ICSE.2004.1317443}, +} + +@inproceedings{mehlitz:2008, + author = {Peter Mehlitz}, + title = {Trust Your Model - Verifying Aerospace System Models with Java Pathfinder}, + booktitle = {Aerospace Conference, 2008 IEEE}, + pages = {1--11}, + year = {2008}, + url = {http://ti.arc.nasa.gov/m/pub-archive/1402/1402%20(Mehlitz).pdf}, +} + +@inproceedings{stergiopoulos:2012, + author = {Stergiopoulos, George and Tsoumas, Bill and Gritzalis, Dimitris}, + title = {Hunting Application-level Logical Errors}, + booktitle = {Proceedings of the 4th International Conference on Engineering Secure Software and Systems}, + year = {2012}, + address = {Eindhoven, The Netherlands}, + pages = {135--142}, + url = {http://dx.doi.org/10.1007/978-3-642-28166-2_13}, + publisher = {Springer}, +} + +@article{mansouri:2007, + author = {Masoud Mansouri-Samani and John Penix and Lawrence Markosian}, + title = {Assume-Guarantee Verification of Source Code with Design-Level Assumptions}, + journal = {Software Assurance Research Program (SARP), NASA IV&V publication}, + year = {2007}, + pages = {203--232}, + publisher = {Kluwer Academic Publishers}, + url = {http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20080015887.pdf}, + } + + @article{havelund:2002, + author = {Klaus Havelund and Willem Visser}, + title = {Program Model Checking as a New Trend}, + journal = {International Journal on Software Tools for Technology Transfer (STTT)}, + volume = {4}, + number = {1}, + month = {October}, + year = {2002}, + url = {http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20030003734.pdf}, +} + +@article{pasareanu:dwyer:2003, + author = "C. P\v{a}s\v{a}reanu and M. Dwyer and W. Visser.", + title = "{Finding Feasible Abstract Counter-Examples}", + journal = "International Journal on Software Tools for Technology Transfer (STTT)", + year = "2003", + volume = "5", + number = "1", + month = "November", + url = "http://ti.arc.nasa.gov/m/profile/pcorina/papers/tacas_sttt01.ps" +} + +@inproceedings{brat:2001, + author = {Guillaume Brat and Willem Visser}, + title = {Combining Static Analysis and Model Checking for Software Analysis}, + booktitle = {Proceedings of the 15th IEEE International Conference on Automated Software Engineering}, + year = {2001}, + address = {San Diego, USA}, + month = {November}, + url = {http://dl.acm.org/citation.cfm?id=872568}, +} + +@inproceedings{visser:park:2000, + author = {Willem Visser and Seungjoon Park and John Penix}, + title = {Using Predicate Abstraction to Reduce Object-Oriented Programs for Model Checking}, + booktitle = {Proceedings of the 3rd ACM SIGSOFT Workshop on Formal Methods in Software Practice}, + year = {2000}, + pages = {3--12}, + month = {August}, + url = "http://ti.arc.nasa.gov/m/tech/rse/publications/papers/SIGSOFT00/fmsp00.pdf", +} + +@article{havelund:2000, + author = {Klaus Havelund and + Thomas Pressburger}, + title = {Model Checking {Java} Programs using {Java} PathFinder}, + journal = {International Journal on Software Tools for Technology Transfer (STTT)}, + volume = {2}, + number = {4}, + pages = {366--381}, + year = {2000}, + url = {http://www.havelund.com/Publications/jpf-sttt.ps.Z}, +} + +@inproceedings{havelund:1999, + author = {Klaus Havelund}, + title = {Java PathFinder, {A} Translator from Java to Promela}, + booktitle = {Theoretical and Practical Aspects of {SPIN} Model Checking}, + month = {July}, + year = {1999}, + url = {http://www.havelund.com/Publications/jpf1-spin-99.pdf}, +} + +@inproceedings{havelund:skakkebaek:1999, + author = {Klaus Havelund and + Jens U. Skakkeb{\ae}k}, + title = {Applying Model Checking in Java Verification}, + booktitle = {Theoretical and Practical Aspects of {SPIN} Model Checking, 5th and + 6th International {SPIN} Workshops}, + pages = {216--231}, + year = {1999}, + url = {http://www.havelund.com/Publications/jpf-fm99.ps.Z}, +} + +@article{havelund:2007, + author = {Klaus Havelund}, + title = {Java PathFinder User Guide}, + booktitle = {Unpublished Report}, + year = {1999}, + url = {​http://www.havelund.com/Publications/jpf-manual.ps.Z}, +} + +@article{havelund:Pressburger:1998, + author = {Klaus Havelund and Thomas Pressburger}, + title = {Java PathFinder, A Translator from Java to Promela}, + booktitle = {Unpublished Report}, + year = {1998}, + url = {​​http://www.havelund.com/Publications/jpf1-report-99.pdf}, +} + +@inproceedings{gligoric:2010, + author = {Milos Gligoric and + Tihomir Gvero and + Vilas Jagannath and + Sarfraz Khurshid and + Viktor Kuncak and + Darko Marinov}, + title = {Test generation through programming in {UDITA}}, + booktitle = {Proceedings of the 32nd {ACM/IEEE} International Conference on Software + Engineering}, + address = {Cape Town, South Africa}, + month = {May}, + pages = {225--234}, + year = {2010}, + url = {http://mir.cs.illinois.edu/~marinov/publications/GligoricETAL10UDITA.pdf}, +} + +@inproceedings{gligoric:jagannath:2010, + author = {Milos Gligoric and + Vilas Jagannath and + Darko Marinov}, + title = {MuTMuT: Efficient Exploration for Mutation Testing of Multithreaded + Code}, + booktitle = {Third International Conference on Software Testing, Verification and + Validation}, + pages = {55--64}, + month = {April}, + address = {Paris, France}, + year = {2010}, + url = {http://mir.cs.illinois.edu/~marinov/publications/GligoricETAL10MuTMuT.pdf}, +} + +@inproceedings{lauterburg:2010, + author = {Steven Lauterburg and + Rajesh K. Karmani and + Darko Marinov and + Gul Agha}, + title = {Evaluating Ordering Heuristics for Dynamic Partial-Order Reduction + Techniques}, + booktitle = {Fundamental Approaches to Software Engineering}, + address = {Paphos, Cyprus}, + month = {March}, + pages = {308--322}, + year = {2010}, + url = {http://mir.cs.illinois.edu/~marinov/publications/LauterburgETAL10DPORHeuristics.pdf}, +} + +@inproceedings{lauterburg:2009, + author = {Steven Lauterburg and + Mirco Dotta and + Darko Marinov and + Gul A. Agha}, + title = {A Framework for State-Space Exploration of Java-Based Actor Programs}, + booktitle = {24th {IEEE/ACM} International Conference on Automated Software Engineering}, + month = {November}, + address = {Auckland, New Zealand}, + pages = {468--479}, + year = {2009}, + url = {http://mir.cs.illinois.edu/~marinov/publications/LauterburgETAL09Basset.pdf}, +} + +@article{sobeih:2010, + author = {Ahmed Sobeih and + Marcelo d'Amorim and + Mahesh Viswanathan and + Darko Marinov and + Jennifer C. Hou}, + title = {Assertion Checking in J-Sim Simulation Models of Network Protocols}, + journal = {Simulation: Transactions of The Society for Modeling and Simulation International}, + volume = {86}, + number = {11}, + pages = {651--673}, + year = {2010}, + url = {http://dx.doi.org/10.1177/0037549709349326}, +} + +@inproceedings{gligoric:2009, + author = {Milos Gligoric and + Tihomir Gvero and + Steven Lauterburg and + Darko Marinov and + Sarfraz Khurshid}, + title = {Optimizing Generation of Object Graphs in Java PathFinder}, + booktitle = {Second International Conference on Software Testing Verification and Validation}, + month = {April}, + address = {Denver, Colorado, {USA}}, + pages = {51--60}, + year = {2009}, + url = {http://mir.cs.illinois.edu/~marinov/publications/GligoricETAL09OptimizingGeneration.pdf}, +} + +@article{damorim:2008, + author = {Marcelo d'Amorim and + Steven Lauterburg and + Darko Marinov}, + title = {Delta Execution for Efficient State-Space Exploration of Object-Oriented Programs}, + journal = {{IEEE} Transactions on Software Engineering}, + volume = {34}, + number = {5}, + pages = {597--613}, + year = {2008}, + month = {September/October}, + url = {http://mir.cs.illinois.edu/~marinov/publications/dAmorimETAL08DeltaExecution.pdf}, +} + +@inproceedings{lauterburg:2008, + author = {Steven Lauterburg and + Ahmed Sobeih and + Darko Marinov and + Mahesh Viswanathan}, + title = {Incremental state-space exploration for programs with dynamically + allocated data}, + booktitle = {International Conference on Software Engineering}, + address = {Leipzig, Germany}, + month = {May}, + pages = {291--300}, + year = {2008}, + url = {​http://mir.cs.illinois.edu/~marinov/publications/LauterburgETAL08IncrementalChecking.pdf}, +} + +@inproceedings{gvero:2008, + author = {Tihomir Gvero and + Milos Gligoric and + Steven Lauterburg and + Marcelo d'Amorim and + Darko Marinov and + Sarfraz Khurshid}, + title = {State extensions for java pathfinder}, + booktitle = {International Conference on Software Engineering, Demo Papers}, + address = {Leipzig, Germany}, + month = {May}, + pages = {863--866}, + year = {2008}, + url = {http://mir.cs.illinois.edu/~marinov/publications/GligoricETAL09OptimizingGeneration.pdf}, +} + +@inproceedings{damorim:2007, + author = {Marcelo d'Amorim and + Steven Lauterburg and + Darko Marinov}, + title = {Delta execution for efficient state-space exploration of object-oriented + programs}, + booktitle = {Proceedings of the {ACM/SIGSOFT} International Symposium on Software + Testing and Analysis}, + address = {London, UK}, + month = {July}, + pages = {50--60}, + year = {2007}, + url = {http://mir.cs.illinois.edu/~marinov/publications/dAmorimETAL07DeltaExecution.pdf}, +} + +@inproceedings{zhou:2007, + author = {Zhou, Yuanyuan and Marinov, Darko and Sanders, William and Zilles, Craig and d'Amorim, Marcelo and Lauterburg, Steven and Lefever, Ryan M. and Tucek, Joe}, + title = {Delta Execution for Software Reliability}, + booktitle = {Proceedings of the 3rd Workshop on on Hot Topics in System Dependability}, + series = {HotDep'07}, + year = {2007}, + address = {Edinburgh, UK}, + url = {http://mir.cs.illinois.edu/~marinov/publications/ZhouETAL07DeltaExecution.pdf}, + publisher = {USENIX Association}, +} + +@inproceedings{damorim:2006, + author = {Marcelo d'Amorim and + Ahmed Sobeih and + Darko Marinov}, + title = {Optimized Execution of Deterministic Blocks in Java PathFinder}, + booktitle = {Proceedings of Formal Methods and Software Engineering, 8th International Conference + on Formal Engineering Methods}, + address = {Macao, China}, + month = {November}, + pages = {549--567}, + year = {2006}, + url = {http://mir.cs.illinois.edu/~marinov/publications/dAmorimETAL06OptimizedDeterministicBlocks.pdf}, +} + +@inproceedings{damorim:pacheco:2006, + author = {Marcelo d'Amorim and + Carlos Pacheco and + Tao Xie and + Darko Marinov and + Michael D. Ernst}, + title = {An Empirical Comparison of Automated Generation and Classification + Techniques for Object-Oriented Unit Testing}, + booktitle = {Proceedings of 21st {IEEE/ACM} International Conference on Automated Software Engineering}, + address = {Tokyo, Japan}, + month = {September}, + pages = {59--68}, + year = {2006}, + url = {​http://mir.cs.illinois.edu/~marinov/publications/dAmorimETAL06Symclat.pdf}, +} + +@unpublished{kulikov:2010, + author = {Sergey Kulikov and Nastaran Shafiei and Franck van Breugel and Willem Visser}, + title = {{Detecting Data Races with Java PathFinder}}, + year = "2010", + url = {http://www.cse.yorku.ca/~franck/research/drafts/race.pdf} +} + +@inproceedings{indradeep:2013, + author = {Ghosh, Indradeep and Shafiei, Nastaran and Li, Guodong and Chiang, Wei-Fan}, + title = {{JST: an automatic test generation tool for industrial Java applications with strings}}, + booktitle = {Proceedings of the 35th International Conference on Software Engineering}, + year = {2013}, + month = {May}, + address = {San Francisco, CA, USA}, + pages = {992--1001}, + publisher = {IEEE}, + url = {http://dl.acm.org/citation.cfm?id=2486925} +} + +@article{nshafiei:2012, + author = {Shafiei, Nastaran and Mehlitz, Peter C.}, + journal = {ACM SIGSOFT Software Engineering Notes}, + number = 6, + pages = {1-5}, + title = {{Modeling class loaders in Java PathFinder version 7}}, + volume = 37, + year = 2012, + month = {November}, + url = {http://dl.acm.org/citation.cfm?id=2382800} +} + +@article{shafiei:2014, + author = {Shafiei, Nastaran and Mehlitz, Peter C.}, + journal = {ACM SIGSOFT Software Engineering Notes}, + number = 1, + pages = {1-5}, + title = {{Extending JPF to verify distributed systems}}, + volume = 39, + year = 2014, + month = {January}, + url = {http://dl.acm.org/citation.cfm?id=2560577}, +} + +@inproceedings{shafiei:2013, + author = {Nastaran Shafiei and + Franck van Breugel}, + title = {Towards model checking of computer games with Java PathFinder}, + booktitle = {Proceedings of the 3rd International Workshop on Games and Software + Engineering}, + address = {San Francisco, CA, USA}, + month = {May}, + pages = {15--21}, + year = {2013}, + url = {http://dl.acm.org/citation.cfm?id=2662596}, +} + + +@inproceedings{shafiei:breugel:2014, + author = {Nastaran Shafiei and + Franck van Breugel}, + title = {Automatic handling of native methods in Java PathFinder}, + booktitle = {Proceedings of the International SPIN Workshop on Model Checking of Software}, + address = {San Jose, CA, USA}, + month = {July}, + pages = {97--100}, + year = {2014}, + url = {http://dl.acm.org/citation.cfm?id=2632363}, +} \ No newline at end of file diff --git a/doc/user/api.md b/doc/user/api.md new file mode 100644 index 0000000..fdfd9a6 --- /dev/null +++ b/doc/user/api.md @@ -0,0 +1,125 @@ +# The Verify API # +Although the primary purpose of JPF is to verify applications that are not JPF dependent, it can also be used to check programs that are explicitly written to execute under JPF. There are two ways to do this + + * use of jpf annotations such as `@gov.nasa.jpf.annotation.JPFConfig` and `@gov.nasa.jpf.annotation.FilterField` + * use of the various `gov.nasa.jpf.vm.Verify` APIs + +The first method provides only directives to JPF (by means of Java annotations), and does not modify or add any specific code to your system under test. The second one is imperative and should only be used by JPF specific test drivers. + +## JPF Annotations ## +The JPF core currently supports two annotation types: `@JPFConfig` and `@FilterField` + +~~~~~~~~ {.java} +import gov.nasa.jpf.annotation.JPFConfig +... +@JPFConfig({"listener+=,gov.nasa.jpf.aprop.listener.SharedChecker", ..}) +public class MyClass { + .. +} +~~~~~~~~ + +The `@JPFConfig` annotation allows to set JPF properties (= pairs) for classes and methods of your application, which is especially useful to add specific listeners. You have to be aware of the property effects though, since not all behavior can be changed at runtime, and you usually cannot reverse features with this method + +The `@FilterField` annotation is used to mark certain fields in your application as not relevant for state matching. This is useful if you have to add debugging information like counters that would otherwise increase the state space (i.e. would prevent state matching). + +~~~~~~~~ {.java} +import gov.nasa.jpf.annotation.FilterField; +... +public class MyClass { + .. + @FilterField int counter; + .. +} +~~~~~~~~ + +This does not change execution of your program in any way, and also does not affect backtracking within JPF (i.e. values are properly restored). It only tells JPF to ignore marked fields when hashing/matching program states. + +There is a [jpf-aprop](wiki:projects/jpf-aprop) JPF module that is dedicated to Java annotation based program properties such as `@Nonnull`, `@NonShared`, `@Immutable`, `@Requires` and many others. + +## The Verify API ## + +Sometimes it is useful to create JPF specific test drivers, like you create JUnit test cases. In this code, you can make explicit use of JPF APIs, since it is not supposed to run outside JPF. There are several categories of APIs which are encapsulated in the `gov.nasa.jpf.vm.Verify` class. + +### Data ChoiceGenerators ### +Data ChoiceGenerators (CGs) are suitable for writing test drivers that are JPF aware. The idea is to obtain non-deterministic input values from JPF in a way that it can systematically analyze all relevant choices. In its most simple form, this can be used like + +~~~~~~~~ {.java} +// test driver code +import gov.nasa.jpf.vm.Verify; +.. +boolean cond = Verify.getBoolean(); +// following code is executed for both cond=true AND cond=false +.. +~~~~~~~~ + +The `Verify` class contains methods for creating a number of different choice generators for builtin Java types, like + +~~~~~~~~ {.java} +.. +int i = Verify.getInt(min,max); // evaluates for all values between 'min' and 'max' (inclusive) +.. +double d = Verify.getDoubleFromSet(-42.0, 0.0, 42.0 ..); // evaluates all given values +.. +~~~~~~~~ + + +CGs don't stop at value sets that can be completely enumerated based on their type (like boolean, and - at least theoretically - integers). JPF also supports configured heuristics based choice generators, where the values sets are application dependent and can be specified in property files. + +![Figure: Data ChoiceGenerators](../graphics/choicegen-example.svg){align=center width=750} + +Choice generator implementation is described in a [separate section](wiki:devel/choicegenerator) of this documentation. + +### Search Pruning ### + +Explicitly restricting the search is useful for highly application specific properties, where it is obvious that certain values are not of interest with respect to the property. + +~~~~~~~~ {.java} +// ..compute some data.. +Verify.ignoreIf(data > someValue); // prune search if true +// ..do some stuff with data.. +~~~~~~~~ +If the provided expression evaluates to true, JPF does not continue to execute the current path, and backtracks to the previous non-deterministic choice point. + +### State Annotation ### +Based on certain value combinations, an application might give JPF hints about the relevance of a program state that can be subsequently used by Search and/or Heuristic implementations. + +~~~~~~~~ {.java} +// ..compute some data +Verify.interesting( data < someValue ); +// ..do some stuff with data +~~~~~~~~ + +This does not stop execution by JPF, but stores an 'interesting' attribute for the current state. Its more general version is used to attach arbitrary strings to states: + +~~~~~~~~ {.java} +// ..compute some data +if (data < someValue) { + Verify.setAnnotation("critical data value"); + // ..do some stuff with dat +~~~~~~~~ + +Again, this category is about to become less important since Search- and VMListeners are superior mechanisms to store not just strings but arbitrary objects as state annotations. + +### Verification Output ### + +This is the most simple category, which is used to differentiate between normal program output (that is executed and analyzed by JPF), and output that is strictly verification relevant, i.e. should not appear when executing a program outside JPF. Not very surprising, it contains a number of print(..) methods. + +### Atomicity Control ### + +this category can be used to control the number of thread interleavings JPF has to analyze. While this is problematic in terms of missing potential defects, it is was often the only way to constrain the state space so that JPF could verify a given application. + +~~~~~~~~ {.java} +Verify.beginAtomic(); +... +// all code in here is executed by JPF in one transition +... +Verify.endAtomic(); +~~~~~~~~ + +Direct atomicity control was mainly used before the automatic, on-the-fly partial order reduction (POR) was implemented, and only remains relevant for applications that are (still) problematic with respect to POR. JPF's on-the-fly POR implementation is described in a [separate section](../devel/partial_order_reduction) of this documentation. + +### Other Usages ### + +Some `Verify` methods support collecting information during JPF execution, which is persistent and can be later-on queried by JPF embedding code (programs that execute JPF). This uses an MJI trick where the [native peer](../devel/mji) class (`JPF_gov_nasa_jpf_vm_Verify`) is used to set some data during JPF execution, which can be later-on retrieved by model class code (through `gov.nasa.jpf.vm.Verify`) that is executed outside of JPF. This is currently used to implement counters, which in turn are used to verify JPF itself. + +It should be noted that while most of the Verify APIs have alternative implementations that enable execution outside of JPF, applications using them at least don't build outside the JPF environment. Their use therefore is only recommended for JPF specific test drivers. \ No newline at end of file diff --git a/doc/user/application_types.md b/doc/user/application_types.md new file mode 100644 index 0000000..352e9c9 --- /dev/null +++ b/doc/user/application_types.md @@ -0,0 +1,36 @@ +# JPF Application Goals and Types # + +By now, you already know that you run JPF on compiled Java programs, just like a normal VM. But what are the goals to apply JPF, and - based on these goals - what are the different JPF application types? + +## Why to Use JPF? ## +Before we classify the different types of JPF applications, it is worth to spend a few thoughts on why we actually want to apply it. A word of caution: if you have a strictly sequential program with only a few well defined input values, you are probably better off writing a few tests - using JPF won't tell you much. There are two major reasons to run JPF: + +### Explore Execution Alternatives ### +After all, JPF started as a software model checker, so its original domain is to explore execution choices, of which we have four different types: + + - scheduling sequences - concurrent applications are still the major domain for JPF application because (a) defects like deadlocks and data races are subtle and usually spurious, and (b) the scheduler can usually not be controlled from a testing environment, i.e. this is hard to impossible to test. JPF on the other hand not only "owns" the scheduler (it is a virtual machine) and explores all interesting scheduling combinations, it even lets you define your own scheduling policies + - input data variation - JPF allows you to explore input value sets that can be defined by heuristics (e.g. a value below, at, and above a certain threshold). This is especially useful when writing test drivers + - environment events - program types like Swing or web applications usually react to external events like user input. Such events can be simulated by JPF as choice sets + - control flow choices - JPF can not only check how your program reacts to a concrete input, it can also turn around and systematically explore the program control structure (branch instructions) to compute input data values that would execute a certain part of your code. + +### Execution Inspection ### + +Even if your program does not have a lot of execution alternatives, you can make use of JPF's inspection capabilities. Being an extensible virtual machine, it is relatively easy to implement coverage analyzers, or non-invasive tests for conditions that would otherwise go unnoticed because they are hard or tedious to implement (like overflow in numerical instructions). + +## JPF Application Types ## +There are three basic JPF application types, each of them having different strengths and weaknesses: JPF- aware, unaware, and "enabled" programs. + +![Figure: JPF application types](../graphics/app-types.svg){align=center width=800} + +### JPF Unaware Programs ### +This is the usual case - you run JPF on an application that is not aware of verification in general, or JPF in particular. It just runs on any VM that is Java compatible. The typical reason to check such an application with JPF is to look for violations of so called non-functional properties that are hard to test for, such as deadlocks or race conditions. JPF is especially good at finding and explaining concurrency related defects, but you have to know the costs: JPF is much slower than a production VM (for a reason - it does a lot more than a normal byte code interpreter), and it might not support all the Java libraries that are used by the system under test. + +### JPF Dependent Programs ### +On the other side of the spectrum we have applications that are models - their only purpose in life is to be verified by JPF (e.g. to check a certain algorithm), so Java just happens to be the implementation language because that is what JPF understands. Typically, these applications are based on a domain specific framework (such as the [statechart extension](../projects/jpf-statechart) that has been written so that JPF can verify the model. As a consequence, the model applications themselves are usually small, scale well, and do not require additional property specification. The downside is that it is quite expensive to develop the underlying domain frameworks. + +### JPF Enabled Programs ### +The third category probably has the best return on investment - programs that can run on any VM, but contain Java annotations that represent properties which cannot easily be expressed with standard Java language. + +For example, assume you have a class which instances are not thread safe, and hence are not supposed to be used as shared objects. You can just run JPF and see if it finds a defect (like a data race) which is caused by illegally using such an object in a multi-threaded context. But even if JPF out-of-the-box can handle the size of the state space and finds the defect, you probably still have to spend a significant effort to analyze a long trace to find the original cause (which might not even be visible in the program). It is not only more easy on the tool (means faster), but also better for understanding if you simply mark the non-threadsafe class with a `@NonShared` annotation. Now JPF only has to execute up to the point where the offending object reference escapes the creating thread, and can report an error that immediately shows you where and how to fix it. + +There is an abundance of potential property-related annotations (such as `@NonNull` for a static analyzer and JPF), including support for more sophisticated, embedded languages to express pre- and post-conditions. diff --git a/doc/user/components.md b/doc/user/components.md new file mode 100644 index 0000000..55a01d2 --- /dev/null +++ b/doc/user/components.md @@ -0,0 +1,57 @@ +# JPF components # +Java is more than a programming language. It is a set of layers that starts with a platform specific VM implementation (which is referred to as the *host VM*) that sits on top of native libraries written for and using your operating system. To this stack, we add JPF - a Java application that runs on top of the "host VM", but is itself a VM which then executes your System Under Test (SUT). + +![Figure 1: Different layers involved when using JPF](../graphics/jpf-layers.svg){align=center width=700} + +With all this recursion, it is easy to get confused about what Java code gets processed at which level. To make things worse, most of the standard library class files (java.* classes) and some of the annotations get processed by both VMs, but of course in different instantiations. Purpose of this page is to shed some light on what code is associated with the different layers and parts of the system. + +In order to untangle, we have to step back and look at what components are involved when applying JPF to the SUT. We categorize the components with respect to two aspects: + + 1. processing VM (host VM, JPF) + 1. associated distribution entity (host Java installation, JPF core, JPF extensions, SUT) + +Remember the [What is JPF](../intro/what_is_jpf) diagram from the introduction? This is a more detailed version of it.  + +![Figure 2: JPF infrastructure](../graphics/jpf-intro-new.svg){align=center width=800} + +Let us walk this diagram left-to-right. We start with the compiled Java application we want to verify. This is of course not part of the JPF distribution, but will be executed by JPF, so the corresponding class files do not have to be visible to the host VM (that runs JPF). However, the application code might use classes and interfaces that reside in the JPF distribution. Together, the application and such modeling libraries and/or annotations form the System under Test (SUT) + +Next comes the JPF core itself. By now we know this is mainly a VM that is written in Java itself, so you run it on whatever Java system is installed on your machine. This means all classes that constitute JPF need to be visible to the host JVM, e.g. by setting the global `CLASSPATH` environment variable (which is not the recommended way to do this). + +Now comes the important part: **JPF is not a monolithic system**. It uses various configured components to do things such as + + * property implementation + * library modeling + * report generation + +and much more. Even if you don't specify anything when you run it, JPF will use a default configuration that pulls in a lot of components such as [listeners](../devel/listener), which do not have to be part of the [JPF core](../jpf-core/index), but can reside in their own JPF extension modules. + +If you do specify your own [configuration](../user/config), you can tell JPF to use components that live outside of the [JPF core](../jpf-core/index) distribution, either in one of the installed JPF extension modules, or in your own project. Either way, all these [listeners](../devel/listener), [native peers](../devel/mji), [publishers](../devel/report) and other components are at runtime part of the whole JPF system, so they need to be visible to the host VM. + +The last part is the most tricky one - your application is most probably using standard Java libraries (e.g. `System.out.println()`), as do the classes that constitute JPF. Some of the standard library classes have to be replaced by JPF specific versions when JPF executes the SUT (e.g. classes such as `java.lang.Class`that have native methods), and JPF has a special [MJI](../devel/mji) mechanism to do that. However, most standard library classes have pure Java implementations, and we take these straight from the host-JVM installation. This means, standard libraries end up in JPF's classpath *and* the host JVM CLASSPATH: and their code is executed by JPF *and* the host VM, but the corresponding instances are different (for instance, a `java.lang.String` object has very different representations in the host VM and JPF). + + +JPF keeps associated class paths separate. There are three different path settings in the JPF configuration: + + 1. `native_classpath` - this includes everything that has to be visible to the host VM, which includes mostly the classes of JPF itself, listeners, native peers and bytecode instruction sets. The `native_classpath` is dynamically constructed from your site.properties and jpf.properties [configuration files](../user/config) during JPF startup, and processed by the JPF classloader + 2. `classpath` - this includes the classes that are executed by JPF, which include your SUT, and all libraries that are used by it (*-classes.jar of installed JPF components). Note that some of the library classes (like `java.lang.Thread`) are replaced by JPF specific versions. Again, this is constructed by JPF during startup from all your configured jpf.properties files, but processed by JPFs internal classfile lookup mechanism. + 3. `sourcepath` - depending on the reports that have to be generated by JPF, it might have to find SUT and library sources for the executed classfiles (bytecodes). This is how you tell JPF where these sources reside. + +You can set these path lists explicitly from your application property file or the command line, but it is better to let JPF collect them when processing the jpf.properties files of your installed JPF components, which all include lines like + +~~~~~~~~ {/bash} +.native_classpath = .. +.classpath = .. +.sourcepath = .. +~~~~~~~~ + +A word of caution: if - during JPF startup - you encounter a message like + +~~~~~~~~ {.bash} +... +[SEVERE} error during VM runtime initialization: wrong model classes (check 'classpath') +~~~~~~~~ + +it means the `classpath` setting is wrong and JPF loads some of the standard library classes that have to be replaced with its own versions - they need to be *modeled* (like `java.lang.Thread`, `java.lang.Class` and others - all part of jpf-classes.jar within the jpf-core module). + +This can also happen later-on with less essential library classes that are not part of jpf-core, but should be loaded from one of the installed extensions. In this case, this usually shows up as an `UnsatisfiedLinkError` diff --git a/doc/user/config.md b/doc/user/config.md new file mode 100644 index 0000000..a57d07b --- /dev/null +++ b/doc/user/config.md @@ -0,0 +1,153 @@ +# Configuring JPF # + +JPF configuration can be intimidating. It is worth to think about why we need such a heavy mechanism before we dive into its details. Little in JPF is hardwired. Since JPF is such an open system that can be parameterized and extended in a variety of ways, there is a strong need for a general, uniform configuration mechanism. The challenge for this mechanism is that many of the parts which are subject to parameterization are configured themselves (i.e. options for optional JPF components like listeners). This effectively prohibits the use of a configuration object that contains concrete fields to hold configuration data, since this class would be a central "design bottleneck" for a potentially open number of JPF components like Searches, Instruction sets and Listeners. + +The goal is to have a configuration object that + + * is based on string values + * can be extended at will + * is passed down in a hierarchical initialization process so that every component extracts only its own parameters + +We achieve this by means of a central dictionary object (`gov.nasa.jpf.Config`) which is initialized through a hierarchical set of Java property files that target three different initialization layers: + + 1. site: optionally installed JPF components + 2. project: settings for each installed JPF module and (optionally) systems under test + 3. application: the class and program properties JPF should check (this is part of your system under test) + +Initialization happens in a prioritized order, which means you can override anything from later configuration stages, all the way up to command line parameters. Actually, this can be even overridden by using the `Verify` API from system under test code, but this is a developer topic. Here is the blueprint, which we will examine in order of execution: + +![Figure: Configuring JPF](../graphics/properties.svg){align=center width=800} + + +## Property Types ## + +Property specifications are processed in a hierarchical order: site properties, project properties, application properties and command line properties. Later stages can override previous stages. Each property is a `=` pair, but we do support some special notations (see below) for key/value expansion, value extension, and pseudo properties that act as directives. + +### Site Properties ### +The site.properties file is machine specific and not part of any JPF project, which means you have to create a [ site.properties](wiki:install/site-properties) file as part of the install process. A sample site.properties might look like: + +~~~~~~~~ +jpf-core = ${user.home}/projects/jpf/jpf-core +jpf-shell = ${user.home}/projects/jpf/jpf-shell +jpf-awt = ${user.home}/projects/jpf/jpf-awt +... +extensions=${jpf-core},${jpf-shell} +~~~~~~~~ + +Each module is listed as a `=` pair, and optionally added to the comma separated list of `extensions`. The order in which modules are added to `extensions` does matter, since it will determine the order in which each of these components is initialized, which basically maps to an ordered list of classpath entries (both for the host VM and JPF itself - paths are kept separate). + +Note that we do **not** require all modules being added to `extensions`, **but** jpf-core needs to be in there. Dependencies on modules not listed in `extensions` can be specified later-on with the `@using` directive. It is a good idea to keep the `extensions` list small to avoid conflicts, and to improve class load times (shorter classpaths). + +Note also that the `extensions` entries are of the form `${}`, which tells JPF to replace these expressions with the value that is associated to . + +Site properties have to be stored in the directory from where you start JPF, one of its parent directories, or a global `${user.home}/.jpf/site.properties`. We recommend a to keep it in a common root directory that contains all your JPF projects and modules. + + +### Project Properties ### +Each JPF module contains a jpf.properties file in its root directory, no matter if this is the jpf-core or an extension. System under test projects can contain a jpf.properties file to factor out common settings (such as class paths) for all JPF applications within this project. + +A project property file defines the JPF specific paths that need to be set for the module or system under test to work properly + + 1. `.`**`native_classpath`**: the host VM classpath (i.e. the classes that constitute JPF itself) + 1. `.`**`classpath`**: the classpath JPF uses to execute the system under test + 1. `.`**`test_classpath`**: host VM and JPF classpath for regression tests + 1. `.`**`sourcepath`**: the path entries JPF uses to locate sources in case it needs to create program traces + +Additionally, `jpf.properties` should contain default values for all module or project specific settings (e.g. report options). + +An example project properties file might look like: + +~~~~~~~~ {.bash} +jpf-aprop = ${config_path} + +#--- path specifications +jpf-aprop.native_classpath = build/jpf-aprop.jar;lib/antlr-runtime-3.1.3.jar +jpf-aprop.classpath = build/examples +jpf-aprop.test_classpath = build/tests +jpf-aprop.sourcepath = src/examples + +#--- other project specific settings +listener.autoload=${listener.autoload},javax.annotation.Nonnull,... +listener.javax.annotation.Nonnull=gov.nasa.jpf.aprop.listener.NonnullChecker +... +~~~~~~~~ + + + +The first entry (`=${config_path}`) in a jpf.properties should always define the module name. JPF automatically expands `${config_path}` with the pathname of the directory in which this jpf.properties file resides. + +jpf.properties are executed in order of definition within site.properties, with one caveat: if you start JPF from within a directory that contains a jpf.properties file, this one will always take precedence, i.e. will be loaded last (overriding previous settings except of the command line). This way, we ensure that JPF developers can enforce priority of the component they are working on. + +Both site.properties and jpf.properties can define or override any key/value pairs they want, but keep in mind that you might end up with different system behavior depending on where you start JPF - avoid configuration force fights by keeping jpf.properties settings disjunct wherever you can. + +Please note that site and project properties have to be consistent, i.e. the module names (e.g. jpf-awt) in site.properties and jpf.properties need to be the same. This is also true for the build.xml Ant project names. + +It is perfectly fine to have a jpf.properties in a SUT that only uses JPF for verification. You need at least to set up the `classpath` so that JPF knows where to find the SUT classes. + + +### Application Properties ### +In order to run JPF, you need to tell it what main class it should start to execute. This is the minimal purpose of the *.jpf application properties files, which are part of your systems under test (SUT). Besides the `target` setting that defines the main class of your SUT, you can also define a list of `target_args` and any number of JPF properties that define how you want your application to be checked (listeners, search policy, bytecode factories etc.). A typical example looks like + +~~~~~~~~ {.bash} +#--- dependencies on other JPF modules +@using = jpf-awt +@using = jpf-shell + +#--- what JPF should run +target = RobotManager + +#--- other stuff that defines how to run JPF +listener+=,.listener.OverlappingMethodAnalyzer + +shell=.shell.basicshell.BasicShell +awt.script=${config_path}/RobotManager-thread.es +cg.enumerate_random=true +... +~~~~~~~~ + +The `@using = ` directive tells JPF to load the `jpf.properties` of the specified projects (defined in `site.properties`). This is the way to ensure proper path initialization of projects that are not listed in `extensions`. + +### Command Line Properties ### +Last not least, you can override or extend any of the previous settings by providing "**+**=" pairs as command line options. This is convenient for experiments if you have to determine the right settings values empirically + + +## Special Property Syntax ## +JPF supports a number of special notations that are valid Java properties syntax, but are only processed by JPF (and - to a certain extend - by Ant): + + * **`key=...${x}..`** - replaces `"${x}"` with whatever is currently stored under the key "`x`". This also works recursively, as in "`classpath = mypath;${classpath}`". Note that while Apache Ant does also support value expansion, but not recursively. In addition, JPF also supports expansion in the key part (i.e. left of the "`=`") + + * **`key+=val`** - appends val to whatever is currently stored under "`key`". Note that there can be no blank between key and "`+=`", which would not be parsed by Java. This expansion only works in JPF + + * **`+key=val`** - in a properties file adds "`val`" in front of what is currently stored under "`key`". Note that if you want to use this from the command line, you have to use two "`++`", since command line options start with "+" + + * **`${config_path}`** - is automatically set to the directory pathname of the currently parsed property file. This can be useful to specify relative pathnames (e.g. input scripts for the jpf-awt extension) + + * **`${config}`** - is set to the file pathname of the currently parsed file + + * **`@requires=`** - can be used to short-circuit loading of a properties file. This is a simple mechanism to control loading of jpf.properties file sections that are incompatible with other modules, and compares to `#ifdef` preprocessor directives. The respective keys are usually set from application properties (*.jpf) files. +Note this does not throw an exception if the required key is not defined, it just bails out of loading the properties file that contains the @requires directive + + * **`@include=`** - recursively loads the properties file with the specified pathname. You can use the automatically defined `${config_path}` property to specify path names that are relative to where the file containing the `@include` directive is, or use `${}` for paths that are relative to the specified module. + + * **`@using=`** - is similar to `@include`, but loads the jpf.properties of the specified module name (which has to be defined in site.properties). Note that there is no `${..}` around the module name - otherwise it would be replaced. The `@using` directive is the preferred way to specify dependencies on modules that are not in the `extensions` list (i.e. automatically initialized). + + * **`@include_if = ??`** - is a conditional `@include` that only loads the properties file if the specified `` is defined + + * **`@include_unless = ??`** - likewise loads the file only if `` is not defined. Both of these directives are used rarely. + + * Omitting the "`=..`" part in command line settings defaults to a "`true`" value for the corresponding key + + * Setting an empty value (`key=`) removes the key from the config dictionary + +## Debugging ## +Depending on the number of installed and loaded projects, you can easily end up with hundreds of settings. There are two command line options you can use if you assume there is a configuration error: + + * **`-show`** - prints all Config entries after the initialization is complete + + * **`-log`** - lists the order in which properties files got loaded by JPF + +## Details on various options ## + +* [Randomization](config/random) + +* Error Reporting diff --git a/doc/user/config/random.md b/doc/user/config/random.md new file mode 100644 index 0000000..4fae737 --- /dev/null +++ b/doc/user/config/random.md @@ -0,0 +1,15 @@ +## Randomization Options in JPF ## + +The randomization options in JPF allow the user to experiment in randomizing the order of choices explored. + +`cg.randomize_choices` can have three possible values: random, path, def. + + * `random`: It explores random choices during program execution with **varying results among different trials**. The default seed used to generate different results is the **system time in milliseconds** + + * `path`: It explores random choices during program execution with **reproducible results among different trials**. The default seed used to generate reproducible results is **42**. The value of the seed can be changed by setting the seed config option. + + * `def`: No randomization, choices are explored using the default search order imposed by the model checker. + +`cg.seed (_INT_)`: The user can specify a particular seed for the random number generator in order to obtain reproducible results in the presence of randomization. Note that this is effective only when the `path` option of `randomize_choices` is selected. + + diff --git a/doc/user/index.md b/doc/user/index.md new file mode 100644 index 0000000..6626007 --- /dev/null +++ b/doc/user/index.md @@ -0,0 +1,19 @@ +# How to Use JPF # + +This section is where the real fun starts. Here you learn about + + - [Different applications of JPF](application_types) + - [JPF's runtime components](components) + - [Starting JPF](run) + - [Configuring JPF](config) + - [Understanding JPF output](output) + - [Using JPF's Verify API in the system under test](api) + +All this assumes you are more interested in running JPF than in developing with/for it, so we will leave most of the JPF internals for the [developer section](../devel/index) of this wiki. + +We do have to bother you with some basic concepts though. Keep in mind that JPF is usually not a black-box tool (such as a compiler). Most probably you have to configure it according to your needs because + + * you have specific verification goals (properties) + * your application has a huge state space that is challenging for a model checker + +On the other hand, JPF is also not a "works-or-fails" tool. Depending on how much time you want to invest, you can adapt it to almost all application types and verification goals. And since JPF is open sourced, chances are somebody has already done that diff --git a/doc/user/output.md b/doc/user/output.md new file mode 100644 index 0000000..349242d --- /dev/null +++ b/doc/user/output.md @@ -0,0 +1,98 @@ +# Understanding JPF Output # + +There are three different ways a JPF run can produce output, each of them with a different purpose, but all controlled by the [general JPF configuration mechanism](config): + + 1. System under test output - what is the SUT doing?\ + + 2. JPF logging - what is JPF doing?\ + + 3. JPF reporting system - what is the result of the JPF run?\ + + + +## System Under Test Output ## + +This is the most simple form of output, which usually just consists of `System.out.println(..)` calls embedded in the application code. There is only one caveat - since this is executed by JPF as part of the application, the same print statement might be executed several times: + +~~~~~~~~ {.java} +public class MyApplication ..{ + ... + boolean cond = Verify.getBoolean(); + System.out.println("and the cond is: " + cond); + ... +} +~~~~~~~~ + +will produce + +~~~~~~~~ +... +and the cond is: true +... +and the cond is: false +... +~~~~~~~~ + +The second execution of the print statement is of course preceded by a backtrack operation of JPF (the `Verify.getBoolean()` statement has two choices `{true,false}`), but the backtracking might not be visible, e.g. when running without the `ExecTracker` or `ChoiceTracker` listeners. + +Since it can be sometimes confusing to see the same output twice without knowing if there is an iteration in the application, or JPF did backtrack between executions, there are two configuration options to control the output behavior: + +`vm.tree_output = {true|false}` - means output is shown on the console each time a print statement is executed. This corresponds to the above example, and is the default behavior. + +`vm.path_output = {true|false}` - will not immediately print the output on the console, but store in the path for subsequent processing once JPF terminates (if the *output* topic is specified - see below). This should produce the same output as running the test application on a normal JVM. + +## Logging ## + +This is a more interesting form of JPF output, primarily intended to show what JPF does internally. For this purpose, it has to support various levels of details, ranging from severe errors to fine grained logging of JPF operations. + +JPF's logging mechanism does not reinvent the wheel, it piggybacks on the standard java.util.logging infrastructure. While this means it would be possible to use customized LogHandlers and Formatters (e.g. to log in XML format), there are specialized JPF incarnations of these classes, mainly to enable logging configuration via the standard JPF configuration mechanism rather than system properties. + +Using the JPF Logging involves two aspects: (1) controlling log output destination, and (2) setting log levels. Both are done with JPF property files. + +To set the default log level, use the `log.level` property (the supported levels being *severe,warning,info,fine,finer,finest*) + +If you want to log to a different console that possibly even runs on a remote machine, use the gov.nasa.jpf.tools.LogConsole on the machine that should display the log messages: + +~~~~~~~~ {.bash} +$ java gov.nasa.jpf.tools.LogConsole +~~~~~~~~ + +Then start JPF on the test machine, specifying where the log output should go: + +~~~~~~~~ {.bash} +$ jpf +log.output=: ... MyTestApp +~~~~~~~~ + +The default host is "localhost", default port is 20000. If these are suitable settings, you can start the `LogConsole` without parameters, and just specify `+log.output=socket` when running JPF. + + +If you develop your own JPF classes, please also check the [JPF logging API](../devel/logging) page. + +## Reports ## + +The JPF reporting system is used to show the outcome of a JPF run, to report property violations, print traces, show statistics and much more. This is in a way the most important part of the JPF user interface, and might involve various different output formats (text, XML, API calls) and targets (console, IDE). Depending on application and project, users might also need control over what items are displayed in which order. It is also obvious this needs to be an extensible mechanism, to adapt to new tools and properties. The JPF report system provides all this, again controlled by JPF's general configuration mechanism. + +The basic concept is that reporting depends on a predefined set of output phases, each of them with a configured, ordered list of topics. The output phases supported by the current system are: + + * start - processed when JPF starts + * transition - processed after each transition + * property_violation - processed when JPF finds a property violation + * finished - processed when JPF terminates + +There is no standard transition topic yet (but it could be implemented in `PublisherExtensions`). The standard `property_violation` topics include: + + * error - shows the type and details of the property violation found + * trace - shows the program trace leading to this property violation + * snapshot - lists each threads status at the time of the violation + * output - shows the program output for the trace (see above) + * statistics - shows property statistics information + +Last not least, the finished list of topics that usually summarizes the JPF run: + + * result - reports if property violations were found, and shows a short list of them + * statistics - shows overall statistics information + +The system consists of three major components: (1) the Reporter, (2) any number of format specific Publisher objects, and (3) any number of tool-, property- and Publisher-specific PublisherExtension objects. Here is the blueprint: + + +Again, there is separate [report system API](../devel/report) documentation if you are interested in JPF development. diff --git a/doc/user/run.md b/doc/user/run.md new file mode 100644 index 0000000..ce3b515 --- /dev/null +++ b/doc/user/run.md @@ -0,0 +1,258 @@ +# Running JPF # +There are five general ways to run JPF, depending on your execution environment (command prompt or IDE) and desired level of configuration support. This page has to cover quite some ground, so bear with us + + 1. [from a command prompt (operating system shell)](#command-line) + 2. [from an IDE (NetBeans, Eclipse) without using JPF plugins](#running-jpf-from-within-ide-without-plugins) + 3. [from an IDE with JPF plugins installed](#running-jpf-from-within-ide-with-plugins) + 4. [from within a JUnit test class](#launching-jpf-from-junit-tests) + 5. [single tests from command line](#explicitly-running-tests-from-the-command-line) + 6. [explicitly from an arbitrary Java program](#explicitly-launching-jpf-from-a-java-program) + +## Command Line ## + +There are several ways to run JPF from the command line, using varying degrees of its runtime infrastructure. The most simple way is to use the provided `bin/jpf` script of the jpf-core distribution. Go to the directory where your system under test (SUT) classes reside, and do a + +~~~~~~~~ {.bash} +> /bin/jpf +classpath=. +~~~~~~~~ + +or preferably + +~~~~~~~~ {.bash} +> /bin/jpf .jpf +~~~~~~~~ + +(see target specification below). If you want to avoid platform specific scripts, you only have to slightly expand this to + +~~~~~~~~ {.bash} +> java -jar /build/RunJPF.jar +classpath=. +~~~~~~~~ + +This makes use of the small RunJPF.jar startup jar that is part of the jpf-core distribution, which only includes the classes that are required to start the JPF bootstrapping process (esp. the JPF classloader). These classes automatically process the various [JPF configuration files](config). If your SUT is not trivial, it is also recommended to add a "-Xmx1024m" host VM option, to avoid running out of memory. + +Last (and probably most rarely), you can directly start JPF and give it an explicit classpath. This amounts to something like + +~~~~~~~~ {.bash} +> java -classpath /build/jpf.jar gov.nasa.jpf.JPF +classpath=. +~~~~~~~~ + +Of course, this gets quickly more complicated if you use JPF extensions, which require to add to both the host VM and the JPF classpath, which is completely automated if you use the RunJPF.jar method. Explicitly setting paths is only for rare occasions if you develop JPF components yourself. + +There are three different argument groups that are processed by JPF: + +#### (1) JPF command line options #### + +These options should come first (after RunJPF.jar), and all start with a hyphen ("-"). The set of currently supported options is: + + * -help : show usage information and exit + * -log : print the configuration steps + * -show : print the configuration dictionary after configuration is complete + +The last two options are mostly used to debug if the JPF configuration does not work as expected. Usually you start with `-show`, and if you don't see the values you expect, continue with `-log` to find out how the values got set. + + +#### (2) JPF properties #### + +This is the second group of options, which all start with a plus ("+") marker, and consist of "`+=`" pairs like + +~~~~~~~~ {.bash} +.. +cg.enumerate_random=true +~~~~~~~~ + +All properties from the various JPF properties [configuration files](config) can be overridden from the command-line, which means there is no limit regarding number and values of options. If you want to extend an existing value, you can use any of the following notations + + * `++=` - which appends + * `++=` - which prepends + * `+=..${}..` - which gives explicit control over extension positions + +Normal JPF properties `${}` expansion is supported. + +If the `=` part is omitted, a default value of `true` is assumed. If you want to set a value to null (i.e. remove a key), just skip the `` part, as in `+=` + +#### (3) target specification #### + +There are two ways to specify what application JPF should analyze + + * explicit classname and arguments + +~~~~~~~~ {.bash} +> jpf ... x.y.MyApplication arg1 arg2 .. +~~~~~~~~ + + * application property file (*.jpf) + +~~~~~~~~ {.bash} +> jpf ... MyApplication.jpf +~~~~~~~~ + +We recommend using the second way, since it enables you to store all required settings in a text file that can be kept together with the SUT sources, and also allows you to start JPF from within !NetBeans or Eclipse just by selecting the *.jpf file (this is mainly what the IDE plugins are for). Please note that application property files require a "`target`" entry, as in + +~~~~~~~~ {.bash} +# JPF application property file to verify x.y.MyApplication +target = x.y.MyApplication +target.args = arg1,arg2 +# Note that target_args in JPF 6 changed to target.args in JPF 7. +... +~~~~~~~~ + +## Running JPF from within IDE without plugins ## + +You can start JPF from within !NetBeans or Eclipse without having the IDE specific JPF plugins installed. In this case, JPF uses the standard IDE consoles to report verification results. For details, please refer to the following pages: + + * [Running JPF from within NetBeans without plugin](run_nb) + * [Running JPF from Eclipse without plugin](run_eclipse) + +Note that this is **not** the recommended way to run JPF from within an IDE, unless you want to debug JPF or your classes. + +## Running JPF from within IDE with plugins ## + +You can simplify launching JPF from within !NetBeans or Eclipse by using the respective plugins that are available from this server. In this case, you just have to create/select an application property (*.jpf) file within your test project, and use the IDE context menu to start a graphical JPF user interface. These so called "JPF shells" are separate applications (that can be configured through normal JPF properties), i.e. appear in a separate window, but can still communicate with the IDE, e.g. to position editor windows. You can find more details on + + * [Running JPF from within NetBeans with netbeans-jpf plugin](run_nb_plugin) + * [Running JPF from Eclipse with eclipse-jpf plugin](run_eclipse_plugin) + +This is becoming the primary method of running JPF. The benefits are twofold: (1) this is executed outside of the IDE process, i.e. it doesn't crash the IDE if JPF runs out of memory, and (2) it makes use of all your standard JPF configuration (site.properties and jpf.properties), in the same way like running JPF from a command-line. + +## Launching JPF from JUnit tests ## + +JPF comes with [JUnit](http://www.junit.org) based testing infrastructure that is used for its own regression test suite. This mechanism can also be used to create your own test drivers that are executed by JUnit, e.g. through an [Ant](http://ant.apache.org) build script. The source structure of your tests is quite simple + +~~~~~~~~ {.java} +import gov.nasa.jpf.util.test.JPFTestSuite; +import org.junit.Test; + +public class MyTest extends TestJPF { + + @Test + public void testSomeFunction() { + if (verifyNoPropertyViolation(jpfOptions)) { // specifies the test goal, "jpfOptions" are optional + someFuntction(); .. // this section is verified by JPF + } + } + + //.. more @Test methods +~~~~~~~~ + +From a JUnit perspective, this is a completely normal test class. You can therefore execute such a test with the standard `` [Ant](http://ant.apache.org) task, like + +~~~~~~~~ {.xml} + + + ... + + ... + + ... + + + + + + ... + + + + + ... +~~~~~~~~ + +Only jpf.jar needs to be in the host VM classpath when compiling and running the test, since `gov.nasa.jpf.util.test.TestJPF` will use the normal JPF configuration (site.properties and configured jpf.properties) to set up the required `native_classpath`, `classpath`, 'test_classpath` and `sourcepath` settings at runtime. Please refer to the [JPF configuration](config) page for details. + +If you don't have control over the build.xml because of the IDE specific project type (e.g. if your SUT is configured as a NetBeans "Class Library Project"), you have to add jpf.jar as an external jar to your IDE project configuration. + +In addition to adding jpf.jar to your build.xml or your IDE project configuration, you might want to add a jpf.properties file to the root directory of your project, to set up things like where JPF finds classes and sources it should analyze (i.e. settings that should be common for all your tests). A generic example could be + +~~~~~~~~ {.bash} + # example of JPF project properties file to set project specific paths + + # no native classpath required if this is not a JPF project itself + myproject.native_classpath=... + + # where does JPF find the classfiles to execute + myproject.classpath=build/classes + + # where do test classes reside + myproject.test_classpath=build/test/classes + + # other project common JPF settings like autoloaders etc. + listener.autoload+=,javax.annotation.Nonnull + listener.javax.annotation.Nonnull=.aprop.listener.NonnullChecker + ... +~~~~~~~~ + +You can find project examples here + + * [standard NetBeans project](../projects/standardnbproject) ("Java Class Library" or "Java Application") + * Freeform NetBeans project (with user supplied build.xml) + * standard Eclipse project (with user supplied build.xml) + +Please refer to the [Verify API](api) and the [JPF tests](../devel/jpf_tests) pages for details about JPF APIs (like `verifyNoPropertyViolation(..)` or `Verify.getInt(min,max)`) you can use within your test classes. + +Since JPF projects use the same infrastructure for their regression tests, you can find a wealth of examples under the `src/tests` directories of your installed JPF projects. + +## Explicitly Running Tests from the command line ## + +You can also run your `TestJPF` derived test drivers by using the `bin/test` script (which in turn just a short for "`java -jar tools/RunTest.jar`", i.e. is platform independent): + +~~~~~~~~ {.bash} +bin/test [] +~~~~~~~~ + +Note that each `verify..(jpfArgs)` uses its own `Config` instance in this case. If you want to specify temporary JPF options from the command-line when running `RunTest`, prefix them with `test` like in the following example + +~~~~~~~~ {.bash} +bin/test +test.listener=.listener.ExecTracker gov.nasa.jpf.test.mc.basic.AttrsTest +~~~~~~~~ + +## Explicitly Launching JPF from a Java Program ## +Since JPF is a pure Java application, you can also run it from your own application. The corresponding pattern looks like this: + +~~~~~~~~ {.java} +public class MyJPFLauncher { + ... + public static void main(String[] args){ + .. + try { + + // this initializes the JPF configuration from default.properties, site.properties + // configured extensions (jpf.properties), current directory (jpf.properies) and + // command line args ("+=" options and *.jpf) + Config conf = JPF.createConfig(args); + + // ... modify config according to your needs + conf.setProperty("my.property", "whatever"); + + // ... explicitly create listeners (could be reused over multiple JPF runs) + MyListener myListener = ... + + JPF jpf = new JPF(conf); + + // ... set your listeners + jpf.addListener(myListener); + + jpf.run(); + if (jpf.foundErrors()){ + // ... process property violations discovered by JPF + } + } catch (JPFConfigException cx){ + // ... handle configuration exception + // ... can happen before running JPF and indicates inconsistent configuration data + } catch (JPFException jx){ + // ... handle exception while executing JPF, can be further differentiated into + // ... JPFListenerException - occurred from within configured listener + // ... JPFNativePeerException - occurred from within MJI method/native peer + // ... all others indicate JPF internal errors + } + ... +~~~~~~~~ + +Please refer to the [Embedding JPF](../devel/embedded) developers documentation for details. If you start JPF through your own launcher application, you have to take care of setting up the required `CLASSPATH` entries so that it finds your (and JPFs) classes, or you can use the generic `gov.nasa.jpf.Main` to load and start your launcher class, which makes use of all the path settings you have in your [site.properties](../install/site-properties) and the directories holding project properties (jpf.properties) referenced therein (details on [how to configure JPF](../user/config). This brings us back to the command line at the top of this page, only that you specify which class should be loaded through `Main`: + +~~~~~~~~ {.bash} +> java -jar .../RunJPF.jar -a MyJPFLauncher ... +~~~~~~~~ + +(note that `gov.nasa.jpf.Main` is the `Main-Class` entry of the executable RunJPF.jar, which also holds the `JPFClassLoader`). + +Just for the sake of completeness, there is another way to start JPF explicitly through a `gov.nasa.jpf.JPFShell` implementation, which is using the normal `JPF.main()` to load your shell, which in turn instantiates and runs a `JPF` object. This is specified in your application property (*.jpf) file with the `shell=` option. Use this if your way to start JPF is optional, i.e. JPF could also be run normally with your *.jpf. \ No newline at end of file diff --git a/doc/user/run_eclipse.md b/doc/user/run_eclipse.md new file mode 100644 index 0000000..72a8e3a --- /dev/null +++ b/doc/user/run_eclipse.md @@ -0,0 +1,20 @@ +## Running JPF within eclipse ## + +To run JPF in eclipse after building + +* JPF click "Run"-->"Run" or click "Play"-->"Run As Dialog". + +* Select Java Application and click "New". + +* Click on the "Main" tab. Ensure the project selected is jpf-core and the in the Main Class pick `gov.nasa.jpf.JPF`. + +* Click on the "Arguments" tab. Specify the `` in the Program Arguments. Any additional configuration properties can be specified. For example, + +~~~~~~~~ {.bash} ++cg.randomize_choices=true +oldclassic +~~~~~~~~ + +* Click on "Run" to verify the application in JPF. The output of the program and the results will be displayed on the eclipse console window. + +Alternatively you pick the run-jpf-core launch configuration and add the `` of the system under test. The eclipse IDE detects the various launch configurations. When you click on the Run button they appear on the left column, pick "run-jpf-core". It is, however, recommended you run the application with the eclipse plugin for better performance and ease of usability. \ No newline at end of file diff --git a/doc/user/run_eclipse_plugin.md b/doc/user/run_eclipse_plugin.md new file mode 100644 index 0000000..a2f40e8 --- /dev/null +++ b/doc/user/run_eclipse_plugin.md @@ -0,0 +1,12 @@ +# Running JPF from within Eclipse using eclipse-jpf # + +eclipse-jpf can be easily configured to run JPF from within Eclipse + + 1. Install eclipse-jpf (see [Installing Eclipse JPF plugin](../install/eclipse-plugin)) + 2. Make sure that the correct site.properties file is being used for JPF (The default is usually correct) + To see which site.properties file is being used: + 3. From the Eclipse top menu go to **Window**->**Preferences** + 4. Select **JPF Preferences** + 5. Make sure that "Path to site.properties" is defined properly. + 6. From either the **Package Explorer** view (On the left of the main Eclipse screen by default) right-click on the *.jpf with the JPF configuration wanted and select **Verify...** + 7. Make sure that the **Console view** (Usually at the bottom of the main Eclipse screen) is opened to view the results from JPF \ No newline at end of file diff --git a/doc/user/run_nb.md b/doc/user/run_nb.md new file mode 100644 index 0000000..b6e60d9 --- /dev/null +++ b/doc/user/run_nb.md @@ -0,0 +1,92 @@ +# Running JPF from within NetBeans without JPF plugin # + +Please Note that the following description assumes NetBeans "freeform projects". In general, it is much better to use the JPF plugins, which not only make the configuration steps described below obsolete, but also work with other NetBeans project types. + +Since the NetBeans build process is Ant based, and Ant can read a subset of JPF configuration files, integration is fairly straight forward. Every JPF project comes with its own build.xml, and a `.../nbproject` directory that holds a NetBeans specific project.xml and ide-file-target.xml file, which can serve as templates for your own projects. + +Once everything is configured correctly, you can run JPF by selecting application property (*.jpf) files in the "project view", and do a "Run"->"Run File" from the NetBeans main menu (without the plugin, there will be no "run" item in the project view context menu, but hotkeys should still work). + +To make this work, you have to configure two NetBeans specific files: + +### nbproject/project.xml ### + +If you want to use JPF specific classes (like annotations), you have to make sure the NetBeans source checker will see them. You can achieve this by re-using the JPF property files to set the required classpaths, like + +~~~~~~~~ {.xml} +... + + ... + + ${user.home}/.jpf/site.properties + ${jpf-core}/jpf.properties + ... + + ... + + + ... + ...;${jpf-core.native_classpath} + + ... +~~~~~~~~ + +This works for two reasons: + + * Ant supports `${key}` expansion from properties (as long as they are not self-recursive) + * Ant properties are single-assignment, i.e. subsequent definitions of the same property name will be ignored + +The next step is required no matter if you use JPF types or not - you have to define file actions, which will link to the ide-file-targets.xml + +~~~~~~~~ {.xml} + ... + + ... + + + run-selected-jpf + + jpf.config + ... + \.jpf$ + absolute-path + + + + + + ... +~~~~~~~~ + +It seems this has to be defined for each source folder, which can require a number of redundant XML elements + +### nbproject/ide-file-targets.xml ### + +Within this file, you have to provide the scripts to run the actions defined in the project.xml. This can also make use of the JPF configuration files: + +~~~~~~~~ {.xml} + + + + + + + ... + + + ... + + Must set property 'jpf.config' + + + + + + + ... + + + + + ... +~~~~~~~~ + diff --git a/doc/user/run_nb_plugin.md b/doc/user/run_nb_plugin.md new file mode 100644 index 0000000..134634e --- /dev/null +++ b/doc/user/run_nb_plugin.md @@ -0,0 +1,12 @@ +# Running JPF from within NetBeans with netbeans-jpf plugin # +netbeans-jpf can be easily configured to run JPF at the click of a mouse. + + 1. Install netbeans-jpf (see: [Installing the NetBeans JPF plugin](../install/netbeans-plugin)) + 2. Make sure the correct `site.properties` file is being used for JPF (The default is usually correct)\ + To see which `site.properties` file is being used: + 3. From the NetBeans top menu go to "Tools"->"Options" (Alt+T followed by Alt+O) + 4. Select "Miscellaneous" from the top of the Options Window + 5. Select the "Java Pathfinder" tab + 6. Make sure that "Path to `site.properties`" is defined properly, uncheck "Use default `site.properties` location" to change the path + 7. From either the "Projects" or "Files" view (on the left of the main NetBeans screen by default,) select the JPF properties file (i.e., a file with a `.jpf` extension) you would like to run. Right click on this file and select the "Verify..." menu item to run JPF. + 8. To view the results, make sure that the "Output" View is open (On the bottom of the main NetBeans screen by default) \ No newline at end of file diff --git a/eclipse/AntBuilder.launch b/eclipse/AntBuilder.launch new file mode 100644 index 0000000..f66e685 --- /dev/null +++ b/eclipse/AntBuilder.launch @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/eclipse/run-JPF.launch b/eclipse/run-JPF.launch new file mode 100644 index 0000000..e599ce9 --- /dev/null +++ b/eclipse/run-JPF.launch @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse/test-JPF.launch b/eclipse/test-JPF.launch new file mode 100644 index 0000000..e7e33e9 --- /dev/null +++ b/eclipse/test-JPF.launch @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse/update-JPF-siteproperties.launch b/eclipse/update-JPF-siteproperties.launch new file mode 100644 index 0000000..65d3b94 --- /dev/null +++ b/eclipse/update-JPF-siteproperties.launch @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/jpf.properties b/jpf.properties new file mode 100644 index 0000000..0bdb036 --- /dev/null +++ b/jpf.properties @@ -0,0 +1,427 @@ +# JPF configuration for "jpf-core" component + +# path elements can either be relative to the property file location, or +# use the JPF component name (e.g. "jpf-core") as a variable prefix +# (e.g. "jpf-core.sourcepath=${jpf-core}/src/examples"). +# If a jpf.properties is to be used within NB, it has to use the variable prefix +# (prepending the project root is only done during JPF init) + +# we use the ';' separator here because it is recognized by NetBeans (as opposed +# to ',') + +# 'config_path' is set automatically by gov.nasa.jpf.Config during JPF init. +# If used from within an Ant build system, 'jpf-core' has to be set explicitly +# (ant does ${..} property expansion, but ignores property redefinition, so the +# following line will be ignored) + +jpf-core = ${config_path} + +jpf-core.native_classpath=\ + ${jpf-core}/build/jpf.jar;\ + ${jpf-core}/build/jpf-annotations.jar + +jpf-core.classpath=\ + ${jpf-core}/build/jpf-classes.jar;\ + ${jpf-core}/build/examples + +jpf-core.sourcepath=\ + ${jpf-core}/src/examples + +jpf-core.test_classpath=\ + ${jpf-core}/build/tests + +jpf-core.peer_packages = gov.nasa.jpf.vm,, + + + +# the default jpf-core properties file with keys for which we need mandatory defaults + +########################### 0. global part ############################### + +# instances that are both search and VM listeners +#listener = .. + +# do we want JPF exceptions to print their stack traces (that's only for +# debugging) +jpf.print_exception_stack = true + + +# this is where we can specify additional classpath entries that are +# not in the system property class.path (e.g. when running JPF from +# an environment that uses it's own loaders, like Eclipse plugins etc.) +#jpf.native_classpath = .. + + +########################### 1. Search part ############################### +search.class = gov.nasa.jpf.search.DFSearch + + +# This flag indicates whether state matching will only be done when a state +# is revisited at a lower depth. By default this is false. If it is set to +# true and no error is found in a limited-depth search then it is guaranteed +# not to have such error below that depth. Note that for traditional +# depth limited search this does not hold +search.match_depth = false + +# This flag indicates whether JPF should produce more than one error +# or stop at the first one +search.multiple_errors = false + +# the minimum free memory bounds. If we fall below that threshold, we +# stop the search +search.min_free = 1M + +# name of the file in which we store error paths. If not set, we don't store +#search.error_path = error.xml + +# the standard properties we want to check for +search.properties=\ +gov.nasa.jpf.vm.NotDeadlockedProperty,\ +gov.nasa.jpf.vm.NoUncaughtExceptionsProperty + + +# various heuristic parameters + +# This number specifies the maximum number of states to keep on the queue +# during a heuristic search. By default it is set to -1 +search.heuristic.queue_limit = -1 + +# This flag indicates whether branches with counts less than branch-start +# are to be ranked according to how many times they have been taken. +# It is set to true by default. If it is set to false, they are all valued +# the same +search.heuristic.branch.count_early = true + +# This number determines at what point branches are heuristically valued as worse +# than non-branching transitions. By default this value is 1. +branch_start = 1 + + +# This number if greater than 0 is returned as the heuristic value for +# non-branching transitions. By default it is set to -1 in which case the +# value of branch-start is returned instead +search.heuristic.branch.no_branch_return = -1 + +# exclusive search listeners +# search.listener = + + +############################### 2. VM part ############################### + + +# this is an ordered list of packages from which we try to locate native peers. +# "" means JPF tries the same package like the model class +# "" means no package at all +# (this is going to be extended by jpf.properties files) +#peer_packages = , + + +vm.class = gov.nasa.jpf.vm.SingleProcessVM + +# the ClassLoaderInfo class used for startup +vm.classloader.class = gov.nasa.jpf.jvm.JVMSystemClassLoaderInfo + +# class used to hash/store states (if not set, states are not matched) +vm.storage.class = gov.nasa.jpf.vm.JenkinsStateSet + +# class used to maintain the backtrack stack +vm.backtracker.class = gov.nasa.jpf.vm.DefaultBacktracker + +# serializer to be used by state set (vm.storage.class) +vm.serializer.class = gov.nasa.jpf.vm.serialize.CFSerializer +#vm.serializer.class = gov.nasa.jpf.vm.serialize.AdaptiveSerializer +#vm.serializer.class = gov.nasa.jpf.vm.serialize.FilteringSerializer + +# the class that models static fields and classes +vm.statics.class = gov.nasa.jpf.vm.OVStatics + +# the class that models the heap +#vm.heap.class = gov.nasa.jpf.vm.PSIMHeap +vm.heap.class = gov.nasa.jpf.vm.OVHeap + +# the class representing the list of all threads +vm.threadlist.class = gov.nasa.jpf.vm.ThreadList + +# restorer to be used by backtracker such as DefaultBacktracker UNLESS a +# serializer that is also a restorer (such as CollapsingSerializer) is used. +# I.e. this is only read if serializer is not used or it's not a StateRestorer +vm.restorer.class = .vm.DefaultMementoRestorer + +# where do we get the standard libraries from? +# "" is replaced by the host VM sun.boot.class.path setting +vm.boot_classpath = + +# instruction factory +jvm.insn_factory.class = gov.nasa.jpf.jvm.bytecode.InstructionFactory + +# fields factory +vm.fields_factory.class = gov.nasa.jpf.vm.DefaultFieldsFactory + +# pattern list for assertion enabled/disabled classes +#vm.enable_assertions = * +#vm.disable_assertions= + +# do we support the Verify.ignorePath() API (to imperatively ignore paths in modeled/instrumented programs)? +vm.verify.ignore_path = true + + +vm.scheduler.class = gov.nasa.jpf.vm.DelegatingScheduler +vm.scheduler.sync.class = gov.nasa.jpf.vm.AllRunnablesSyncPolicy +vm.scheduler.sharedness.class = gov.nasa.jpf.vm.PathSharednessPolicy + +# the following properties can be used to set filters for GenericSharednessPolicy instances + +# never break on exposure or shared field access from matching methods. +# NOTE - this is transitive and hence should only include a minimal set of trusted methods +vm.shared.never_break_methods=\ + java.util.concurrent.ThreadPoolExecutor.processWorkerExit,\ + java.util.concurrent.locks.Abstract*Synchronizer.*,\ + java.util.concurrent.ThreadPoolExecutor.getTask,\ + java.util.concurrent.atomic.Atomic*.*,\ + java.util.concurrent.Exchanger.doExchange,\ + java.util.concurrent.ThreadPoolExecutor.interruptIdleWorkers,\ + java.util.concurrent.TimeUnit.* + +vm.shared.never_break_types=\ + java.util.concurrent.TimeUnit + +# never break on shared access of the following fields. While this is less prone to +# masking defects than never_break_methods, it should also be used sparingly. +# NOTE - java.lang.Thread* fields should not be excluded if the SUT explicitly uses +# Thread or ThreadGroup objects +vm.shared.never_break_fields=\ + java.lang.Thread*.*,\ + java.lang.System.*,\ + java.lang.Runtime.*,\ + java.lang.Boolean.*,\ + java.lang.String.*,\ + java.lang.*.TYPE,\ + java.util.HashMap.EMPTY_TABLE,\ + java.util.HashSet.PRESENT,\ + java.util.concurrent.ThreadPoolExecutor*.*,\ + java.util.concurrent.ThreadPoolExecutor*.*,\ + java.util.concurrent.TimeUnit.*,\ + java.util.concurrent.Exchanger.CANCEL,\ + java.util.concurrent.Exchanger.NULL_ITEM,\ + java.util.concurrent.Executors$DefaultThreadFactory.*,\ + sun.misc.VM.*,\ + sun.misc.SharedSecrets.*,\ + sun.misc.Unsafe.theUnsafe,\ + gov.nasa.jpf.util.test.TestJPF.* + + +# do we also break transitions on reference field puts that could make the +# referenced objects shared +vm.shared.break_on_exposure = true + +# do we try to deduce if a field is supposed to be protected by a lock? In this +# case, we stop to treat this field as a boundary step, but only if we see the lock +vm.shared.sync_detection = true + +# do we assume final fields to be race-safe (not really true, esp. for +# instance fields with references leaking from a ctor, but a good starting point) +vm.shared.skip_finals=true + +# ClassLoaders synchronize the loading of a class. +# Thus, static final fields can never be included in a race condition since only 1 thread is allowed to access the class while it is loading. +# Defaulted to false to maintain backward compatibility in JPF +vm.shared.skip_static_finals=false + +# When an object's constructor has returned, then the final fields can not be changed. +# Thus, instance final fields can never be included in a race condition (unless the this reference is leaked from a constructor) +# Defaulted to false to maintain backward compatibility in JPF +vm.shared.skip_constructed_finals=false + + +# do we ignore explicitly set Thread.UncaughtHandlers +vm.ignore_uncaught_handler=false + +# do we treat returned Thread.UncaughtHandler.uncaughtException() calls as normal thread termination +vm.pass_uncaught_handler=true + +# do we reclaim unused memory (run garbage collection) +vm.gc = true + +# threshold after which number of allocations to perform a garbage collection +# (even within the same transition, to avoid lots of short living objects) +# -1 means never +vm.max_alloc_gc = -1 + +# do we run finalizers on collected objects (only makes sense with garbage collection) +vm.finalize = false + +# this is a preemption boundary specifying the max number of instructions after which we +# break the current transition if there are other runnable threads +vm.max_transition_length = 50000 + +# are thread ids of terminated threads with recycled thread objects reused when creating new +# threads. This is required for programs that sequentially create many short living threads +vm.reuse_tid = false + +# do we want to halt execution on each throw of an exception that matches +# one of the given classname wildcard patterns w/o looking for exception handlers? +# (useful for empty handler blocks, over-permissive catches or generally +# misused exceptions) +#vm.halt_on_throw = * + +# class that is used to create scheduling relevant choice generators. +# this will replace the scheduler +vm.scheduler_factory.class = gov.nasa.jpf.vm.DefaultSchedulerFactory + +# print output as it is generated during the search (for all paths) +vm.tree_output = true + +# collect output inside the stored path (to create program trace outout) +vm.path_output = false + +# do we want to store the whole path no matter if we report them +vm.store_steps=false + +# untracked property +vm.untracked = true + +# from where do we initialize the system properties +# SELECTED - keys specified as vm.system.properties, values from host +# FILE - Java properties file (key=value pairs) +# HOST - all system properties from underlying host VM +vm.sysprop.source = SELECTED + +# pathname of property file with system properties +#vm.sysprop.file = + +# list of key names to load from host VM +#vm.sysprop.keys = + +# class we use to model execution time +vm.time.class = gov.nasa.jpf.vm.SystemTime + +# if this is set to true, we throw an exception if we encounter any orphan native peer methods +vm.no_orphan_methods = false + +# if this is set to true, overriden finalize() methods execute upon objects garbage collections +vm.process_finalizers = false + + +### jvm specifics + +# di=o we model nested locks during class init (to detect possible hotspot dealocks during init) +# (off by default since it can cause state explosion) +jvm.nested_init=false + +# if so, for which classes (default is to exclude system classes) +jvm.nested_init.exclude=java.*,javax.*,sun.misc.* + + +############################### 3. CG part ############################### + +# choice randomization policy in effect: +# "NONE" - choice sets are not randomized +# "FIXED_SEED" - choice sets are randomized using a fixed seed for each JPF run (reproducible) +# "VAR_SEED" - choice sets are randomized using a variable seed for each JPF run +cg.randomize_choices = NONE + +# the standard seed value used for the FIXED_SEED policy +cg.seed = 42 + + +# if this is set, we create choice generators even if there is only a single +# choice. This is to ensure state storage/matching at all locations where a +# choice generator *could* be created. The default should be to turn it off though, +# since this can produce a lot of additional states (esp. with threads) +cg.break_single_choice = false + + +# default BooleanChoiceGenerator sequence: do we start with 'false' +cg.boolean.false_first = true + +# do we want java.util.Random. nextXX() enumerate choices, or just return a single value? +# (isn't implemented for all types yet) +cg.enumerate_random=false + +# maximum number of processors returned by Runtime.availableProcessors(). If this is +# greater than 1, the call represents a ChoiceGenerator +cg.max_processors=1 + +# creates a CG upon Thread.start, i.e. breaks the starting transition. Note this is +# required for data race detection (which depends on detecting access of shared objects) +cg.threads.break_start=true + +# if this option is set we break the transition on Thread.yield() +cg.threads.break_yield=true + +# if this option is set we break the transition on Thread.sleep() +cg.threads.break_sleep=true + +# set if we shold also break on array instructions, e.g. to detect races +# for array elements. This is off by default because it can cause serious +# state explosion +cg.threads.break_arrays=false + +# do we support atomic sections. If set to false, Verify.beginAtomic()/endAtomic() +# will not do anything +cg.enable_atomic=true + +############################### 3. Report Part ############################### +log.handler.class=gov.nasa.jpf.util.LogHandler + +# Windows seem to have a different default +log.level=warning + +report.class=gov.nasa.jpf.report.Reporter +report.publisher=console + +report.console.class=gov.nasa.jpf.report.ConsolePublisher + +# this prints out repository information if the 'jpf' topic is set (for debugging) +#jpf.report.show_repository=true + +#property violation reporting is configured separately +report.console.start=jpf,sut + +report.console.transition= +report.console.constraint=constraint,snapshot + +report.console.probe=statistics + +report.console.property_violation=error,snapshot +report.console.show_steps=true +report.console.show_method=true +report.console.show_code=false + +report.console.finished=result,statistics + +#jpf.report.console.show_steps=true +#jpf.report.console.show_method=true +#jpf.report.console.show_code=true + +report.xml.class=gov.nasa.jpf.report.XMLPublisher + +report.html.class=gov.nasa.jpf.report.HTMLPublisher +report.html.start=jpf,sut,platform,user,dtg,config +report.html.constraint=constraint +report.html.property_violation= +report.html.finished=result,statistics,error,snapshot,output + + +############################### 4. Listener part ############################# + +# imperative list of listeners +#listener= + +listener.autoload=\ + gov.nasa.jpf.NonNull,\ + gov.nasa.jpf.Const + +listener.gov.nasa.jpf.NonNull=gov.nasa.jpf.tools.NonNullChecker +listener.gov.nasa.jpf.Const=gov.nasa.jpf.tools.ConstChecker + + +### PreciseRaceDetector + +# we don't check for races in standard libraries +race.exclude=java.*,javax.* + + +############################### 5. test part ############################# + +test.report.console.finished=result diff --git a/nbproject/ide-file-targets.xml b/nbproject/ide-file-targets.xml new file mode 100644 index 0000000..255a0d1 --- /dev/null +++ b/nbproject/ide-file-targets.xml @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set property 'run.class' + + + + + + + + + + + + + Must set property 'debug.class' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set property 'run.class' + + + + + + + + + + + + + + Must set property 'debug.class' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set property 'jpf.config' + + + + + + + + + + + + + Must set property 'jpf.config' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set property 'run.class' + + + + + + + + + + + + + + + Must set property 'debug.class' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set property 'jpf.config' + + + + + + + + + + + + + Must set property 'jpf.config' + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..69ebf85 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,325 @@ + + + org.netbeans.modules.ant.freeform + + + jpf-core + + + + jpf-core + + + + + . + UTF-8 + + + + java + src/main + UTF-8 + + + + java + src/peers + UTF-8 + + + + java + src/annotations + UTF-8 + + + + java + src/classes + UTF-8 + + + + java + src/tests + UTF-8 + + + + java + src/examples + UTF-8 + + + + + build + + + clean + + + + test-project + + + clean + build + + + + + + run-selected-main + + run.class + src/main + \.java$ + java-name + + + + + + + + debug-selected-main + + debug.class + src/main + \.java$ + java-name + + + + + + + + + run-selected-example + + run.class + src/examples + \.java$ + java-name + + + + + + + + debug-selected-example + + debug.class + src/examples + \.java$ + java-name + + + + + + + + run-selected-example-jpf + + jpf.config + src/examples + \.jpf$ + absolute-path + + + + + + + + debug-selected-example-jpf + + jpf.config + src/examples + \.jpf$ + absolute-path + + + + + + + + + run-selected-test + + run.class + src/tests + \.java$ + java-name + + + + + + + + debug-selected-test + + debug.class + src/tests + \.java$ + java-name + + + + + + + + run-selected-test-jpf + + jpf.config + src/tests + \.jpf$ + absolute-path + + + + + + + + debug-selected-test-jpf + + jpf.config + src/tests + \.jpf$ + absolute-path + + + + + + + + folder + build/main + build + + + folder + build/peers + build + + + folder + build/classes + build + + + folder + build/examples + build + + + folder + build/annotations + build + + + folder + build/tests + build + + + + + + src/main + + + + src/peers + + + + src/annotations + + + + src/classes + + + + src/tests + + + + src/examples + + + build.xml + + + + + + + + + + + + + + src/main + build/annotations + build/main + 1.8 + + + src/peers + build/annotations;build/main + build/peers + 1.8 + + + src/classes + build/annotations;build/main + build/classes + 1.8 + + + src/examples + + build/main + build/examples + 1.8 + + + src/annotations + build/annotations + 1.8 + + + src/tests + + build/main:build/annotations:build/peers:build/classes + build/tests + 1.8 + + + + + + + + + + + + + + + diff --git a/src/annotations/gov/nasa/jpf/annotation/FilterField.java b/src/annotations/gov/nasa/jpf/annotation/FilterField.java new file mode 100644 index 0000000..a94b57c --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/FilterField.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that a field in the model should not be considered during + * state matching. + * @author peterd + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface FilterField { + /** + * If not the empty string, specifies a property that must be "true" to + * activate this filter--unless invert is set. + */ + String condition() default ""; + + /** + * If set to true, property must be "false" to activate filter. + * Does nothing if condition is empty string. + */ + boolean invert() default false; +} \ No newline at end of file diff --git a/src/annotations/gov/nasa/jpf/annotation/FilterFrame.java b/src/annotations/gov/nasa/jpf/annotation/FilterFrame.java new file mode 100644 index 0000000..d659ddc --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/FilterFrame.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * USE CAREFULLY - Indicates that the stack frame of a method should not, + * in specified ways, be considered during state matching. + * + * This can easily cause the search to be cut off even though the VM has made + * progress, so USE WISELY! + * + * @author peterd + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface FilterFrame { + /** + * True means locals (incl. parameters) and operand stack will be filtered. + */ + boolean filterData() default true; + + /** + * True means the location of the next instruction will be filtered. + */ + boolean filterPC() default true; + + /** + * True means frames below this one will not appear at all in the abstracted + * state. + */ + boolean filterSubframes() default true; +} \ No newline at end of file diff --git a/src/annotations/gov/nasa/jpf/annotation/JPFAttribute.java b/src/annotations/gov/nasa/jpf/annotation/JPFAttribute.java new file mode 100644 index 0000000..f33b568 --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/JPFAttribute.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * a model annotation that causes JPF to automatically set a corresponding + * attribute for the target construct upon class loading + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface JPFAttribute { + String[] value(); +} diff --git a/src/annotations/gov/nasa/jpf/annotation/JPFConfig.java b/src/annotations/gov/nasa/jpf/annotation/JPFConfig.java new file mode 100644 index 0000000..dd09a87 --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/JPFConfig.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * annotation that can be used to change JPF config properties + * from within the SuT + * using such annotations should NOT make the SuT JPF dependent + */ +@Retention(RetentionPolicy.CLASS) +public @interface JPFConfig { + String[] value(); // each element is a "key[+]=val" pair +} diff --git a/src/annotations/gov/nasa/jpf/annotation/JPFOption.java b/src/annotations/gov/nasa/jpf/annotation/JPFOption.java new file mode 100644 index 0000000..0380011 --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/JPFOption.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + +public @interface JPFOption { + String type(); + String key(); + String defaultValue(); + String comment(); + +} diff --git a/src/annotations/gov/nasa/jpf/annotation/JPFOptions.java b/src/annotations/gov/nasa/jpf/annotation/JPFOptions.java new file mode 100644 index 0000000..4f8ecb4 --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/JPFOptions.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + +public @interface JPFOptions { + + JPFOption[] value(); + +} diff --git a/src/annotations/gov/nasa/jpf/annotation/MJI.java b/src/annotations/gov/nasa/jpf/annotation/MJI.java new file mode 100644 index 0000000..e87f5cf --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/MJI.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author Nastaran Shafiei + * + * An annotation used to specify native peer methods + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface MJI { + boolean noOrphanWarning() default false; +} \ No newline at end of file diff --git a/src/annotations/gov/nasa/jpf/annotation/NeverBreak.java b/src/annotations/gov/nasa/jpf/annotation/NeverBreak.java new file mode 100644 index 0000000..207b5cb --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/NeverBreak.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * annotation that is used to mark fields or types which should not + * have shared field access CGs + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface NeverBreak { +} diff --git a/src/annotations/gov/nasa/jpf/annotation/NoJPFExecution.java b/src/annotations/gov/nasa/jpf/annotation/NoJPFExecution.java new file mode 100644 index 0000000..d04d2ec --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/NoJPFExecution.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * annotation used to specify that a method is only supposed to be + * executed when running outside JPF + * + * This is useful for model classes that have methods which are intercepted + * or cut off by native peers, and we want to ensure that we never execute + * these when running under JPF. The standard case for such assertions is + * if we refer to JPF itself, and we don't want to get recursive when already + * executing under JPF + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface NoJPFExecution { +} diff --git a/src/annotations/gov/nasa/jpf/annotation/NonShared.java b/src/annotations/gov/nasa/jpf/annotation/NonShared.java new file mode 100644 index 0000000..b53739b --- /dev/null +++ b/src/annotations/gov/nasa/jpf/annotation/NonShared.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * instances of @NonShared classes are not allowed to be referenced from + * more than one thread (but do allow hand-over) + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface NonShared { + +} diff --git a/src/classes/gov/nasa/jpf/AnnotationProxyBase.java b/src/classes/gov/nasa/jpf/AnnotationProxyBase.java new file mode 100644 index 0000000..43d84e4 --- /dev/null +++ b/src/classes/gov/nasa/jpf/AnnotationProxyBase.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + + +/** + * common stuff used by all Annotation Proxies + */ +public class AnnotationProxyBase { + + public native Class annotationType(); + + // this is just here to be intercepted by the native peer + @Override + public native String toString(); + + /*** + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('@'); + + Class cls = getClass(); + String clsName = cls.getName(); + int idx = clsName.lastIndexOf('$'); + sb.append(clsName.substring(0, idx)); + + Field[] fields = cls.getDeclaredFields(); + if (fields.length > 0){ + sb.append('('); + for (int i=0; i0){ + sb.append(','); + } + sb.append(fields[i].getName()); + sb.append('='); + + try { + Object v = fields[i].get(this); + Class vcls = v.getClass(); + + if (vcls.isArray()){ + sb.append('['); + int n = Array.getLength(v); + for (int j=0; j0){ + sb.append(','); + } + sb.append(Array.get(v,j)); + } + sb.append(']'); + } else { + sb.append(fields[i].get(this)); + } + } catch (IllegalAccessException iax){} + } + sb.append(')'); + } + + return sb.toString(); + } + ***/ +} diff --git a/src/classes/gov/nasa/jpf/BoxObjectCaches.java b/src/classes/gov/nasa/jpf/BoxObjectCaches.java new file mode 100644 index 0000000..ea5076d --- /dev/null +++ b/src/classes/gov/nasa/jpf/BoxObjectCaches.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +/** + * @author Nastaran Shafiei + * + * Refereces to the caches for the types Byte, Character, Short, Integer, + * Long. + * + * This class is added to the startup class list in VM.initialize, to be + * loaded before the valueOf()s are called. + */ +public class BoxObjectCaches { + // Byte cache + static Byte byteCache[]; + + // Character cache + static Character charCache[]; + + // Short + static Short shortCache[]; + + // Integer cache + static Integer intCache[]; + + // Long cache + static Long longCache[]; +} \ No newline at end of file diff --git a/src/classes/gov/nasa/jpf/CachedROHttpConnection.java b/src/classes/gov/nasa/jpf/CachedROHttpConnection.java new file mode 100644 index 0000000..38f9e96 --- /dev/null +++ b/src/classes/gov/nasa/jpf/CachedROHttpConnection.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.Proxy; +import java.net.URL; + +import sun.net.www.protocol.http.Handler; + +/** + * this is just a very rough abstraction at this point, which only supports + * reading static URL contents. The data is cached for subsequent + * access, to avoid DOS by means of model checking + */ +public class CachedROHttpConnection extends java.net.HttpURLConnection { + + @Override + public void disconnect() { + //throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean usingProxy() { + return false; + } + + @Override + public void connect() throws IOException { + //throw new UnsupportedOperationException("Not supported yet."); + } + + String host; + int port; + + public CachedROHttpConnection(URL u, String host, int port){ + super(u); + + this.host = host; + this.port = port; + } + + public CachedROHttpConnection(URL u, Proxy p, Handler handler){ + super(u); + } + + public CachedROHttpConnection(URL u, Proxy p) { + this (u, p, new Handler()); + } + + protected CachedROHttpConnection(URL u, Handler handler) throws IOException { + this(u, null, handler); + } + + + + private native byte[] getContents(String url); + + @Override + public synchronized InputStream getInputStream() throws IOException { + byte[] data = getContents(url.toString()); + return new ByteArrayInputStream(data); + } + + +} diff --git a/src/classes/gov/nasa/jpf/ConsoleOutputStream.java b/src/classes/gov/nasa/jpf/ConsoleOutputStream.java new file mode 100644 index 0000000..43a770d --- /dev/null +++ b/src/classes/gov/nasa/jpf/ConsoleOutputStream.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import java.io.OutputStream; +import java.io.PrintStream; + +/** + * this is what we use for System.out and System.err, hence we go native + * as quickly as possible, hence we don't need an underlying stream. + * It's already slow enough as it is + * + * NOTE - we have to intercept *everything* that might go to our base class, since + * it is not initialized properly (we want to avoid costly PrinStream init unless + * we really need it + */ +public class ConsoleOutputStream extends PrintStream { + + + public ConsoleOutputStream() { + // that's a hack - it only works because we intercept the ctor in the native peer + // otherwise it would throw an exception + super((OutputStream)null); + } + + @Override + public void flush() { + // we are not buffered anyways + } + + @Override + public void close() { + // nothing to close + } + + @Override + public native void print (boolean b); + public native void print (byte b); + @Override + public native void print (char c); + public native void print (short s); + @Override + public native void print (int i); + @Override + public native void print (long l); + @Override + public native void print (float f); + @Override + public native void print (double d); + @Override + public native void print (String s); + + @Override + public void print (Object o){ + if (o == null) { + print("null"); + } else { + print(o.toString()); + } + } + + @Override + public native void println (boolean b); + public native void println (byte b); + @Override + public native void println (char c); + public native void println (short s); + @Override + public native void println (int i); + @Override + public native void println (long l); + @Override + public native void println (float f); + @Override + public native void println (double d); + @Override + public native void println (String s); + + @Override + public void println (Object o){ + if (o == null) { + println("null"); + } else { + println(o.toString()); + } + } + + @Override + public native void println(); + + @Override + public native PrintStream printf (String fmt, Object... args); + @Override + public PrintStream format (String fmt, Object... args){ + return printf(fmt,args); + } + + @Override + public native void write (int b); + @Override + public native void write (byte[] buf, int off, int len); +} diff --git a/src/classes/gov/nasa/jpf/EventProducer.java b/src/classes/gov/nasa/jpf/EventProducer.java new file mode 100644 index 0000000..7b891b7 --- /dev/null +++ b/src/classes/gov/nasa/jpf/EventProducer.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +/** + * a model class that produces events based on native specs + */ +public class EventProducer { + + /** + * the main interface to be used from clients (test drivers) + * @return false if there was no next event (i.e. this is the end of a trace) + */ + public native boolean processNextEvent(); + + public native String getEventName(); + + //--- for testing and debugging purposes + public native boolean checkPath(); + public native boolean isCompletelyCovered(); +} diff --git a/src/classes/gov/nasa/jpf/FinalizerThread.java b/src/classes/gov/nasa/jpf/FinalizerThread.java new file mode 100644 index 0000000..af1951f --- /dev/null +++ b/src/classes/gov/nasa/jpf/FinalizerThread.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +/** + * @author Nastaran Shafiei + * + * Represents the finalizer thread which runs finalize() methods upon + * garbage collection of finalizable objects, i.e. the class of a finalizable + * object overrides the Object.finalize() method. + * + * Note that, by default, we don't process finalizers. To run finalizers one + * needs to set the property "vm.process_finalizers" to true. + */ +public class FinalizerThread extends Thread { + + // upon their garbage collection, finalizable objects are added into this list instead + // of being removed by gc().sweep() + private Object[] finalizeQueue; + + private Object semaphore; + private boolean done; + + + private void runAllFinalizers() { + while(!isEmpty()) { + try { + // runFinalizer processes and removes the first element in the list + runFinalizer(finalizeQueue[0]); + } catch (Throwable e) { + // FinalizerThread ignores exceptions thrown by finalizers. + } + } + } + + boolean isEmpty() { + return (finalizeQueue.length == 0); + } + + // invoke finalize() on the give object + private native void runFinalizer(Object o); + + private native void manageState(); + + private void processFinalizers() { + runAllFinalizers(); + manageState(); + } + + @Override + public void run() { + while (!done){ + processFinalizers(); + } + } +} diff --git a/src/classes/gov/nasa/jpf/SerializationConstructor.java b/src/classes/gov/nasa/jpf/SerializationConstructor.java new file mode 100644 index 0000000..012b25b --- /dev/null +++ b/src/classes/gov/nasa/jpf/SerializationConstructor.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +import java.lang.reflect.Constructor; + +public class SerializationConstructor extends Constructor { + + // those are set by the the sun.reflect.ReflectionFactory + Class mdc; + Constructor firstNonSerializableCtor; + + @Override + public Class getDeclaringClass() { + return mdc; + } + + // this has to be native because we need to create a new object of the + // mdc without initializing it + @Override + public native T newInstance (Object... args); + + @Override + public boolean isSynthetic () { + return true; + } + +} diff --git a/src/classes/java/io/File.java b/src/classes/java/io/File.java new file mode 100644 index 0000000..6d57bde --- /dev/null +++ b/src/classes/java/io/File.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.io; + +import gov.nasa.jpf.annotation.FilterField; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + + +/** + * MJI model class for java.io.File + * + * NOTE - a number of methods are only stubbed out here to make Eclipse compile + * JPF code that uses java.io.File (there is no way to tell Eclipse to exclude the + * model classes from ths build-path) + * + * @author Owen O'Malley + */ +public class File +{ + public static final String separator = System.getProperty("file.separator"); + public static final char separatorChar = separator.charAt(0); + public static final String pathSeparator = System.getProperty("path.separator"); + public static final char pathSeparatorChar = pathSeparator.charAt(0); + + @FilterField int id; // link to the real File object + private String filename; + + public File(String filename) { + if (filename == null){ + throw new NullPointerException(); + } + + this.filename = filename; + } + + public File (String parent, String child) { + filename = parent + separator + child; + } + + public File (File parent, String child) { + filename = parent.filename + separator + child; + } + + public File(java.net.URI uri) { throw new UnsupportedOperationException(); } + + public String getName() { + int idx = filename.lastIndexOf(separatorChar); + if (idx >= 0){ + return filename.substring(idx+1); + } else { + return filename; + } + } + + public String getParent() { + int idx = filename.lastIndexOf(separatorChar); + if (idx >= 0){ + return filename.substring(0,idx); + } else { + return null; + } + } + + public int compareTo(File that) { + return this.filename.compareTo(that.filename); + } + + @Override + public boolean equals(Object o) { + if (o instanceof File){ + File otherFile = (File) o; + return filename.equals(otherFile.filename); + } else { + return false; + } + } + + @Override + public int hashCode() { + return filename.hashCode(); + } + + @Override + public String toString() { + return filename; + } + + + //--- native peer intercepted (hopefully) + + int getPrefixLength() { return 0; } + public native File getParentFile(); + + public String getPath() { + return filename; + } + + public native boolean isAbsolute(); + public native String getAbsolutePath(); + public native File getAbsoluteFile(); + public native String getCanonicalPath() throws java.io.IOException; + + public native File getCanonicalFile() throws java.io.IOException; + + private native String getURLSpec(); + public java.net.URL toURL() throws java.net.MalformedURLException { + return new URL(getURLSpec()); + } + + private native String getURISpec(); + public java.net.URI toURI() { + try { + return new URI(getURISpec()); + } catch (URISyntaxException x){ + return null; + } + } + + public native boolean canRead(); + public native boolean canWrite(); + public native boolean exists(); + public boolean isDirectory() { return false; } + public boolean isFile() { return false; } + public boolean isHidden() { return false; } + public long lastModified() { return -1L; } + public long length() { return -1; } + public native boolean createNewFile() throws java.io.IOException; + public boolean delete() { return false; } + public void deleteOnExit() {} + public String[] list() { return null; } + public String[] list(FilenameFilter fnf) { return null; } + public File[] listFiles() { return null; } + public File[] listFiles(FilenameFilter fnf) { return null; } + public File[] listFiles(FileFilter ff) { return null; } + public boolean mkdir() { return false; } + public boolean mkdirs() { return false; } + public boolean renameTo(File f) { return false; } + public boolean setLastModified(long t) { return false; } + public boolean setReadOnly() { return false; } + + public static native File[] listRoots(); + + public static File createTempFile(String prefix, String suffix, File dir) throws IOException { + if (prefix == null){ + throw new NullPointerException(); + } + + String tmpDir; + if (dir == null){ + tmpDir = System.getProperty("java.io.tmpdir"); + if (tmpDir == null){ + tmpDir = "."; + } + if (tmpDir.charAt(tmpDir.length()-1) != separatorChar){ + tmpDir += separatorChar; + } + + if (suffix == null){ + suffix = ".tmp"; + } + } else { + tmpDir = dir.getPath(); + } + + return new File(tmpDir + prefix + suffix); + } + + public static File createTempFile(String prefix, String suffix) throws IOException { + return createTempFile(prefix, suffix, null); + } +} diff --git a/src/classes/java/io/FileDescriptor.java b/src/classes/java/io/FileDescriptor.java new file mode 100644 index 0000000..2e5523d --- /dev/null +++ b/src/classes/java/io/FileDescriptor.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +import gov.nasa.jpf.annotation.FilterField; + +/** + * a simple abstraction for a file descriptor, which for us is little more + * than just an id for a native data buffer (we don't want to keep the + * data itself in the JPF space) + * + * <2do> still needs the standard descriptors + */ +public class FileDescriptor { + @FilterField int fd; // to be set from the native side + + static final int FD_READ = 0; + static final int FD_WRITE = 1; + + static final int FD_NEW = 0; + static final int FD_OPENED = 1; + static final int FD_CLOSED = 2; + + String fileName; + int mode; // no use to turn it into an Enum - it's accessed from the native peer + + // we can't use the 'fd' field for it, because we need to keep that in + // case we have to automatically reopen after a backtrack + int state = FD_NEW; + + long off; // we need to keep this on the model side to make it backtrackable + + public FileDescriptor () { + fd = -1; + } + + FileDescriptor (String fname, int mode) throws IOException, FileNotFoundException { + fileName = fname; + this.mode = mode; + + fd = open(fname, mode); + + if (fd != -1){ + state = FD_OPENED; + } else { + throw new FileNotFoundException(fname); + } + } + + public boolean valid () { + return (fd != -1); + } + + public void close () throws IOException { + close0(); + state = FD_CLOSED; + } + + //--- those are the real work horses + native int open (String fname, int mode) throws IOException; + public native void sync(); + native int read () throws IOException; + public native int read (byte[] buf, int off, int len); + native long skip(long n) throws IOException; + native int available () throws IOException; + native void close0 () throws IOException; + + native void write (int b) throws IOException; + public native void write (byte[] buf, int off, int len); +} diff --git a/src/classes/java/io/FileInputStream.java b/src/classes/java/io/FileInputStream.java new file mode 100644 index 0000000..98c2454 --- /dev/null +++ b/src/classes/java/io/FileInputStream.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +import java.nio.channels.FileChannel; + +/** + * a simple model to read data w/o dragging the file system content into + * the JPF memory + */ +public class FileInputStream extends InputStream { + + FileDescriptor fd; + private FileChannel fc = null; + + public FileInputStream (String fname) throws FileNotFoundException { + try { + fd = new FileDescriptor(fname, FileDescriptor.FD_READ); + } catch (IOException iox){ + throw new FileNotFoundException(fname); + } + } + + public FileInputStream (File file) throws FileNotFoundException { + this( file.getAbsolutePath()); + } + + public FileInputStream (FileDescriptor fd) { + this.fd = fd; + } + + @Override + public int read(byte b[]) throws IOException { + return read(b,0,b.length); + } + + public FileChannel getChannel() { + if(this.fc ==null){ + this.fc = new FileChannel(fd); + } + return this.fc; + } + + //--- our native peer methods + + boolean open (String fname) { + // this sets the FileDescriptor from the peer side + return false; + } + + @Override + public int read() throws IOException { + return fd.read(); + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + return fd.read(b,off,len); + } + + @Override + public long skip(long n) throws IOException { + return fd.skip(n); + } + + @Override + public int available () throws IOException { + return fd.available(); + } + + @Override + public void close () throws IOException { + fd.close(); + } + + +} diff --git a/src/classes/java/io/FileOutputStream.java b/src/classes/java/io/FileOutputStream.java new file mode 100644 index 0000000..169837d --- /dev/null +++ b/src/classes/java/io/FileOutputStream.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.io; + +import java.nio.channels.FileChannel; + +public class FileOutputStream extends OutputStream { + + FileDescriptor fd; + private FileChannel fc = null; + + public FileOutputStream (String fname) throws FileNotFoundException { + try { + fd = new FileDescriptor(fname, FileDescriptor.FD_WRITE); + } catch (IOException iox){ + throw new FileNotFoundException(fname); + } + } + + public FileOutputStream (File file) throws FileNotFoundException { + this( file.getAbsolutePath()); + } + + public FileOutputStream (FileDescriptor fd) { + this.fd = fd; + } + + public FileChannel getChannel() { + if(this.fc ==null){ + this.fc = new FileChannel(fd); + } + return this.fc; + } + + public FileDescriptor getFD() { + return fd; + } + + //--- our native peer methods + + boolean open (String fname) { + // this sets the FileDescriptor from the peer side + return false; + } + + @Override + public void write (int b) throws IOException { + fd.write(b); + } + + @Override + public void write (byte[] buf, int off, int len) throws IOException { + fd.write(buf, off, len); + } + + @Override + public void close () throws IOException { + fd.close(); + } + + @Override + public void flush () throws IOException { + fd.sync(); + } +} diff --git a/src/classes/java/io/InputStreamReader.java b/src/classes/java/io/InputStreamReader.java new file mode 100644 index 0000000..f235a10 --- /dev/null +++ b/src/classes/java/io/InputStreamReader.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + + +/** + * how hard can it be to transform byte(s) into a char? I hate Unicode + */ +public class InputStreamReader extends Reader { + + static final int BUF_SIZE=128; + private static Object lock = new Object(); // our peer has state + + InputStream in; + byte[] bbuf = new byte[BUF_SIZE]; + String charSetName=null; + + public InputStreamReader (InputStream in){ + this.in = in; + } + + public InputStreamReader (InputStream in,String charSetName){ + this.in = in; + this.charSetName = charSetName; + } + + @Override + public void close () throws IOException { + in.close(); + } + + private native int decode (int b, boolean endOfInput); + + @Override + public boolean ready() { + try { + return (in.available() > 0); + } catch (IOException iox){ + return false; + } + } + + @Override + public int read () throws IOException { + synchronized (lock){ + while (true){ + + int b = in.read(); + if (b < 0){ + return -1; + } + + int c = decode(b, (in.available() == 0)); + if (c >= 0 ) { + return c; + } + } + } + } + + + + native int decode (byte[] inBuf,int len, + char[] outBuf, int off, + boolean endOfInput); + + + @Override + public int read (char[] cbuf, int off, int len) throws IOException { + int r = 0; + boolean available = true; + + synchronized (lock){ + while (available && r < len){ + // <2do> - so what if that backtracks? the peer might have + // iteration-specific state that gets lost. see native peer comments + int b = in.read(bbuf, 0, Math.min(len-r,bbuf.length)); + if (b < 0){ + return (r == 0) ? -1 : r; + } + + // true if we have not reach the end of the input stream "in" + // and there are still more bytes available to be read + available = (in.available() > 0); + + r += decode(bbuf,b, cbuf,off+r, !available); + } + } + + return r; + } + +} diff --git a/src/classes/java/io/OutputStreamWriter.java b/src/classes/java/io/OutputStreamWriter.java new file mode 100644 index 0000000..070165f --- /dev/null +++ b/src/classes/java/io/OutputStreamWriter.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.io; + +import gov.nasa.jpf.vm.Verify; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +/** + * natively convert char output into byte output + * + * <2do> - this needs to be reworked. It trades locks for saving heap objects, + * and that is a choice between a rock and a hard place. We shouldn't call + * write() from within the native encode() (which we would have to since this + * could be any OutputStream). We shouldn't create a very short + * living JPF byte[] object per write() call, since that kills the heap. We + * shouldn't use an explicit lock since that blows up the state space. That + * leaves us with atomic sections, but it's not really safe since clients + * might use their own OutputStream classes with synchronized write() methods. + * At least this would not go unnoticed + */ +public class OutputStreamWriter extends Writer { + + static final int BUF_SIZE=128; + //private static Object lock = new Object(); + + OutputStream out; + + byte[] buf = new byte[BUF_SIZE*6]; // worst case UTF-8 + + public OutputStreamWriter(OutputStream os) { + out = os; + } + + public OutputStreamWriter(OutputStream os, Charset cs) { + out = os; + throw new UnsupportedOperationException("OutputStreamWriter model does not fully implement this constructor"); + } + + public OutputStreamWriter(OutputStream os, CharsetEncoder end) { + out = os; + throw new UnsupportedOperationException("OutputStreamWriter model does not fully implement this constructor"); + } + + public OutputStreamWriter(OutputStream os, String charsetName) { + out = os; + throw new UnsupportedOperationException("OutputStreamWriter model does not fully implement this constructor"); + } + + @Override + public void close() throws IOException { + out.close(); + } + + @Override + public void flush() { + // nothing + } + + void flushBuffer() { + // nothing + } + + public native String getEncoding(); + + native int encode (char[] cbuf, int off, int len, byte[] buf); + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + int w=0; + + //synchronized(lock){ + Verify.beginAtomic(); + while (w < len){ + int n = encode(cbuf, off+w, len-w, buf); + out.write(buf, 0, n); + w += n; + } + Verify.endAtomic(); + //} + } + + private native int encode (char c, byte[] buf); + + @Override + public void write (int c) throws IOException { + //synchronized(lock){ + Verify.beginAtomic(); + int n = encode((char)c, buf); + out.write(buf,0,n); + Verify.endAtomic(); + //} + } + + private native int encode (String s, int off, int len, byte[] buf); + + @Override + public void write(String s, int off, int len) throws IOException { + int w=0; + + //synchronized(lock){ + Verify.beginAtomic(); + while (w < len){ + int n = encode(s, off+w, len-w, buf); + out.write(buf, 0, n); + w += n; + } + Verify.endAtomic(); + //} + } +} diff --git a/src/classes/java/io/RandomAccessFile.java b/src/classes/java/io/RandomAccessFile.java new file mode 100644 index 0000000..39f2f97 --- /dev/null +++ b/src/classes/java/io/RandomAccessFile.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.io; + +import java.nio.channels.FileChannel; + +import java.io.FileDescriptor; +/** + * MJI model class for java.io.RandomAccessFile + * This class cannot yet handle File I/O correctly + * Some work about the use of RandomAccessFile can be + * found here : https://bitbucket.org/pfjeau/jpf_for_nanohttpd/src/8f880ee27410026c69cf37f1904b159965d1576e/?at=raf-progress + * Another way to implement all the missing features is to fix the jpf-bfs project in order to handle file I/O + * + * @author Owen O'Malley + */ +@SuppressWarnings("unused") +public class RandomAccessFile { + public RandomAccessFile(File name, String permissions + ) throws FileNotFoundException { + filename = name; + isOpen = true; + isReadOnly = "r".equals(permissions); + setDataMap(); + } + + public RandomAccessFile(String name, String permissions + ) throws FileNotFoundException { + this(new File(name), permissions); + } + + public void seek(long posn) throws IOException { + currentPosition = posn; + } + + public long length() throws IOException { + return currentLength; + } + + public native void setDataMap(); + + public native void writeByte(int data) throws IOException; + + public native void write(byte[] data, int start, int len + ) throws IOException; + + + public native void setLength(long len) throws IOException; + + public native int read(byte[] data, int start, int len + ) throws IOException; + + public native byte readByte() throws IOException; + + public void close() throws IOException { + isOpen = false; + } + + public FileChannel getChannel(){ + return null;//TODO + } + + public FileDescriptor getFD(){ + return null;//TODO + } + + private static class DataRepresentation { + DataRepresentation next; + long chunk_index; + int[] data; + } + + private final static void printList(DataRepresentation node) { + DataRepresentation cur = node; + System.out.print("Chunks:"); + while (cur != null) { + System.out.print(" " + cur.chunk_index); + cur = cur.next; + } + System.out.println(); + } + + private static final int CHUNK_SIZE = 256; + private File filename; + private boolean isOpen; + private boolean isReadOnly; + private long currentLength; + private long currentPosition; + private DataRepresentation data_root = null; +} + diff --git a/src/classes/java/lang/Class.java b/src/classes/java/lang/Class.java new file mode 100644 index 0000000..379b60a --- /dev/null +++ b/src/classes/java/lang/Class.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import sun.reflect.ConstantPool; +import sun.reflect.annotation.AnnotationType; + +/** + * MJI model class for java.lang.Class library abstraction + * + * This is a JPF specific version of a system class because we can't use the real, + * platform VM specific version (it's native all over the place, its field + * structure isn't documented, most of its methods are private, hence we can't + * even instantiate it properly). + * + * Note that this class never gets seen by the real VM - it's for JPF's eyes only. + * + * For now, it's only a fragment to test the mechanism, and provide basic + * class.getName() / Class.ForName() support (which is (almost) enough for + * Java assertion support + */ +@SuppressWarnings("unused") // native peer uses +public final class Class implements Serializable, GenericDeclaration, Type, AnnotatedElement { + + /** don't use serialVersionUID from JDK 1.1 for interoperability */ + private static final long serialVersionUID = 3206093459760846163L + 1; + + // we init this on demand (from MJIEnv) since it's not used too often + private static Annotation[] emptyAnnotations; // = new Annotation[0]; + + private String name; + + private ClassLoader classLoader; + + /** + * search global id of the corresponding ClassInfo, which factors in the classloader + */ + private int nativeId; + + /** + * to be set during of the corresponding class + */ + private boolean isPrimitive; + + private Class() {} + + public native boolean isArray (); + + @Override + public native Annotation[] getAnnotations(); + + @Override + public native A getAnnotation( Class annotationCls); + + // those are from Java 6 + public native boolean isAnnotation (); + @Override + public native boolean isAnnotationPresent(Class annotationClass); + + public native Class getComponentType (); + + public native Field[] getFields() throws SecurityException; + + public native Field getDeclaredField (String fieldName) throws NoSuchFieldException, + SecurityException; + + public native Field[] getDeclaredFields () throws SecurityException; + + public native Method getDeclaredMethod (String mthName, Class... paramTypes) + throws NoSuchMethodException, SecurityException; + + public native Method getMethod (String mthName, Class... paramTypes) + throws NoSuchMethodException, SecurityException; + + public native Method[] getDeclaredMethods () throws SecurityException; + + public native Method[] getMethods () throws SecurityException; + + public native Constructor[] getDeclaredConstructors() throws SecurityException; + + public native Constructor[] getConstructors() throws SecurityException; + + private native byte[] getByteArrayFromResourceStream(String name); + + public InputStream getResourceAsStream (String name) { + byte[] byteArray = getByteArrayFromResourceStream(name); + if (byteArray == null) return null; + return new ByteArrayInputStream(byteArray); + } + + private native String getResolvedName (String rname); + + public URL getResource (String rname) { + String resolvedName = getResolvedName(rname); + return getClassLoader().getResource(resolvedName); + } + + public Package getPackage() { + // very very crude version for now, only supports the package name + String pkgName = null; + + int idx = name.lastIndexOf('.'); + if (idx >=0){ + pkgName = name.substring(0,idx); + + Package pkg = new Package(pkgName, + "spectitle", "specversion", "specvendor", + "impltitle", "implversion", "implvendor", + null, getClassLoader()); + return pkg; + + } else { // weird, but there is no Package object for the default package + return null; + } + + } + + //--- enum support () + // Java 1.5 + public native T[] getEnumConstants(); + + // Java 6 + T[] getEnumConstantsShared() { + return getEnumConstants(); + } + + // lazy initialized map for field name -> Enum constants + // <2do> we should move this to the native side, since Enum constants don't change + private transient Map enumConstantDirectory = null; + + // package private helper for Enum.valueOf() + Map enumConstantDirectory() { + if (enumConstantDirectory == null) { + Map map = new HashMap(); + + T[] ae = getEnumConstants(); + for (T e: ae) { + map.put(((Enum)e).name(), e); + } + + enumConstantDirectory = map; + } + return enumConstantDirectory; + } + + + public native Constructor getDeclaredConstructor (Class... paramTypes) + throws NoSuchMethodException, SecurityException; + + public native Field getField (String fieldName) throws NoSuchFieldException, + SecurityException; + + public native boolean isInstance (Object o); + + public native boolean isAssignableFrom (Class clazz); + + public native boolean isInterface(); + + public native Constructor getConstructor (Class... argTypes) throws NoSuchMethodException, SecurityException; + + public native int getModifiers(); + + public native Class[] getInterfaces(); + + // no use to have a ctor, we can't call it + public String getName () { + return name; + } + + public String getSimpleName () { + int idx; // <2do> not really - inner classes? + Class enclosingClass = getEnclosingClass(); + + if(enclosingClass!=null){ + idx = enclosingClass.getName().length(); + } else{ + idx = name.lastIndexOf('.'); + } + + return name.substring(idx+1); + } + + static native Class getPrimitiveClass (String clsName); + + /** + * this one is in JPF reflection land, it's 'native' for us + */ + public static native Class forName (String clsName) throws ClassNotFoundException; + + public static Class forName (String clsName, boolean initialize, ClassLoader loader) throws ClassNotFoundException { + Class cls; + if (loader == null){ + cls = forName(clsName); + } else { + cls = loader.loadClass(clsName); + } + + if (initialize) { + cls.initialize0(); + } + return cls; + } + + /** + * forces clinit without explicit field or method access + */ + private native void initialize0 (); + + public boolean isPrimitive () { + return isPrimitive; + } + + public native Class getSuperclass (); + + public native T newInstance () throws InstantiationException, + IllegalAccessException; + + @Override + public String toString () { + return (isInterface() ? "interface " : "class ") + name; + } + + @SuppressWarnings("unchecked") + public T cast(Object o) { + if (o != null && !isInstance(o)) throw new ClassCastException(); + return (T) o; + } + + @SuppressWarnings("unchecked") + public Class asSubclass(Class clazz) { + if (clazz.isAssignableFrom(this)) { + return (Class) this; + } else { + throw new ClassCastException("" + this + " is not a " + clazz); + } + } + + native public boolean desiredAssertionStatus (); + + public ClassLoader getClassLoader() { + return classLoader; + } + + native ConstantPool getConstantPool(); + + native void setAnnotationType (AnnotationType at); + + native AnnotationType getAnnotationType(); + + @Override + public TypeVariable>[] getTypeParameters() { + throw new UnsupportedOperationException(); + } + + public Type getGenericSuperclass() { + throw new UnsupportedOperationException(); + } + + public Type[] getGenericInterfaces() { + throw new UnsupportedOperationException(); + } + + public Object[] getSigners() { + throw new UnsupportedOperationException(); + } + + void setSigners(Object[] signers) { + signers = null; // Get rid of IDE warning + throw new UnsupportedOperationException(); + } + + public Method getEnclosingMethod() { + throw new UnsupportedOperationException(); + } + + public Constructor getEnclosingConstructor() { + throw new UnsupportedOperationException(); + } + + public Class getDeclaringClass() { + throw new UnsupportedOperationException(); + } + + public native Class getEnclosingClass(); + + public String getCanonicalName() { + throw new UnsupportedOperationException(); + } + + public boolean isAnonymousClass() { + throw new UnsupportedOperationException(); + } + + public boolean isLocalClass() { + throw new UnsupportedOperationException(); + } + + public boolean isMemberClass() { + throw new UnsupportedOperationException(); + } + + public Class[] getClasses() { + throw new UnsupportedOperationException(); + } + + public Class[] getDeclaredClasses() throws SecurityException { + throw new UnsupportedOperationException(); + } + + public java.security.ProtectionDomain getProtectionDomain() { + throw new UnsupportedOperationException(); + } + + void setProtectionDomain0(java.security.ProtectionDomain pd) { + pd = null; // Get rid of IDE warning + throw new UnsupportedOperationException(); + } + + public boolean isEnum() { + throw new UnsupportedOperationException(); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + throw new UnsupportedOperationException(); + } + + public boolean isSynthetic (){ + final int SYNTHETIC = 0x00001000; + return (getModifiers() & SYNTHETIC) != 0; + } +} diff --git a/src/classes/java/lang/ClassLoader.java b/src/classes/java/lang/ClassLoader.java new file mode 100644 index 0000000..6bc56aa --- /dev/null +++ b/src/classes/java/lang/ClassLoader.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.Vector; + +import sun.misc.CompoundEnumeration; + +/** + * @author Nastaran Shafiei + * + * Model class for java.lang.ClassLoader + */ +public abstract class ClassLoader { + + private ClassLoader parent; + + // This is JPF internal identifier which set to the globalId of the classLoader + private int nativeId; + + //--- internals + + protected ClassLoader() { + // constructed on the native side + } + + protected ClassLoader (ClassLoader parent){ + // constructed on the native side + } + + private native String getResource0 (String rname); + + public URL getResource(String name) { + URL url = null; + + if(parent == null) { + String resourcePath = getSystemClassLoader().getResource0(name); + try { + url = new URL(resourcePath); + } catch (MalformedURLException x){ + url = null; + } + } else { + url = parent.getResource(name); + } + + if (url == null) { + url = findResource(name); + } + return url; + } + + /** + * Finds the resource with the given name. Class loader implementations + * should override this method to specify where to find resources. + */ + protected URL findResource(String name) { + return null; + } + + private native String[] getResources0 (String rname); + + /** + * Returns an array of URL including all resources with the given name + * found in the classpath of this classloader. + */ + private Enumeration getResourcesURL(String name) { + String[] urls = getResources0(name); + Vector list = new Vector(0); + for(String url: urls) { + try { + list.add(new URL(url)); + } catch (MalformedURLException x){ + // process the rest + } + } + + return list.elements(); + } + + @SuppressWarnings({"unchecked","rawtypes"}) + public Enumeration getResources(String name) throws IOException { + Enumeration[] resEnum = new Enumeration[2]; + + if(parent == null) { + resEnum[0] = getSystemClassLoader().getResourcesURL(name); + } else{ + resEnum[0] = parent.getResources(name); + } + resEnum[1] = findResources(name); + + return new CompoundEnumeration(resEnum); + } + + /** + * Returns an enumeration representing all the resources with the given + * name. Class loader implementations should override this method to + * specify where to load resources from. + */ + protected Enumeration findResources(String name) throws IOException { + return (new Vector()).elements(); + } + + public InputStream getResourceAsStream (String name){ + URL foundResource = getResource(name); + if (foundResource != null) { + try { + return foundResource.openStream(); + } catch (IOException e) { + System.err.println("cannot open resource " + name); + } + } + return null; + } + + public native static ClassLoader getSystemClassLoader (); + + public static URL getSystemResource(String name){ + return getSystemClassLoader().getResource(name); + } + + public static InputStream getSystemResourceAsStream(String name) { + return getSystemClassLoader().getResourceAsStream(name); + } + + public static Enumeration getSystemResources(String name) throws IOException { + return getSystemClassLoader().getResources(name); + } + + public ClassLoader getParent() { + return parent; + } + + /** + * If the class with the given name has been already defined, it is returned. OW, it + * returns null. + */ + protected native final Class findLoadedClass(String name); + + protected native final Class findSystemClass(String name) throws ClassNotFoundException; + + public Class loadClass(String name) throws ClassNotFoundException { + Class c = findLoadedClass(name); + + if(c == null) { + try { + if (parent != null && parent != getSystemClassLoader()) { + c = parent.loadClass(name, false); + } else { + c = findSystemClass(name); + } + } catch (ClassNotFoundException e) { + c = findClass(name); + } + } + + return c; + } + + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + return loadClass(name); + } + + /** + * Finds the class with a given name. This method should be overridden by + * ClassLoader subclasses, and it will be used by loadClass(). + */ + protected Class findClass(String name) throws ClassNotFoundException { + throw new ClassNotFoundException(name); + } + + /** + * All the class objects are resolved internally by JPF. So this method + * does nothing. + */ + protected final void resolveClass(Class c) { + } + + private native Class defineClass0(String name, byte[] b, int off, int len); + + protected final Class defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { + return defineClass0(name, b, off, len); + } + + protected final Class defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError { + return defineClass(name, b, off, len); + } + + protected String findLibrary(String libname) { + return null; + } + + protected native Package getPackage(String name); + + protected native Package[] getPackages(); + + public native void setDefaultAssertionStatus(boolean enabled); + + public native void setClassAssertionStatus(String className, boolean enabled); + + public native void setPackageAssertionStatus(String packageName, boolean enabled); + + public native void clearAssertionStatus(); + + //--- unsupported methods + + protected static boolean registerAsParallelCapable() { + return true; // dummy, in prep for jdk7 + } + + protected Object getClassLoadingLock(String className) { + throw new UnsupportedOperationException(); + } + + protected final Class defineClass(byte[] b, int off, int len) + throws ClassFormatError { + throw new UnsupportedOperationException(); + } + + protected final Class defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain) + throws ClassFormatError { + throw new UnsupportedOperationException(); + } + + protected final void setSigners(Class c, Object[] signers) { + throw new UnsupportedOperationException(); + } + + protected Package definePackage(String name, String specTitle, String specVersion, + String specVendor, String implTitle, String implVersion, + String implVendor, URL sealBase) + throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/classes/java/lang/InheritableThreadLocal.java b/src/classes/java/lang/InheritableThreadLocal.java new file mode 100644 index 0000000..496efe9 --- /dev/null +++ b/src/classes/java/lang/InheritableThreadLocal.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + +/** + * model of java.lang.InheritableThreadLocal + * + * since we model ThreadLocal, we also need to model this one + */ +public class InheritableThreadLocal extends ThreadLocal { + + public InheritableThreadLocal (){ + // nothing here + } + + // watch out - this can be overridden + protected T childValue (T parentVal){ + return parentVal; + } + +} diff --git a/src/classes/java/lang/Object.java b/src/classes/java/lang/Object.java new file mode 100644 index 0000000..67269c5 --- /dev/null +++ b/src/classes/java/lang/Object.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +/** + * modeled root class of all Java objects. This is modeled because we already have a peer because of + * the synchronization methods and have to cut off the registerNatives() call + */ +public class Object { + public Object() { + // nothing here + } + + public final native Class getClass(); + public native int hashCode(); + + /** + * default implementation is just an identity check + */ + public boolean equals (Object o) { + return o == this; + } + + + public String toString() { + // intercepted by peer + return null; + } + + protected native Object clone() throws java.lang.CloneNotSupportedException; + + public final native void notify(); + public final native void notifyAll(); + + public final native void wait (long timeout) throws java.lang.InterruptedException; + + public final void wait (long timeout, int nanos) throws java.lang.InterruptedException{ + // intercepted by peer + } + + public final void wait() throws java.lang.InterruptedException { + // intercepted by peer + } + + protected void finalize() throws java.lang.Throwable { + + } +} diff --git a/src/classes/java/lang/StackTraceElement.java b/src/classes/java/lang/StackTraceElement.java new file mode 100644 index 0000000..0f4e452 --- /dev/null +++ b/src/classes/java/lang/StackTraceElement.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +import java.io.File; + +/** + * MJI model class for java.lang.StackTraceElement + */ +public class StackTraceElement { + + String clsName; + String fileName; + String mthName; + int line; + + public StackTraceElement() { + // nothing to do + } + + public StackTraceElement (String clsName, String mthName, String fileName, int line) { + if (clsName == null) { + throw new NullPointerException("Declaring class is null"); + } + + if (mthName == null) { + throw new NullPointerException("Method name is null"); + } + + this.clsName = clsName; + this.mthName = mthName; + this.fileName = fileName; + this.line = line; + } + + public String getClassName () { + return clsName; + } + + public String getFileName () { + return fileName; + } + + public int getLineNumber () { + return line; + } + + public String getMethodName () { + return mthName; + } + + public boolean isNativeMethod () { + return false; + } + + /** + public int hashCode () { + return 0; + } + **/ + + @Override + public String toString () { + StringBuilder sb = new StringBuilder(); + sb.append(clsName); + sb.append('.'); + sb.append(mthName); + sb.append("("); + + sb.append(new File(fileName).getName()); + + if (line >= 0){ + sb.append(':'); + sb.append(line); + } + sb.append(')'); + return sb.toString(); + } +} diff --git a/src/classes/java/lang/String.java b/src/classes/java/lang/String.java new file mode 100644 index 0000000..a37c6fa --- /dev/null +++ b/src/classes/java/lang/String.java @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + +import java.io.ObjectStreamField; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * MJI adapter for java.lang.String, based on jdk 1.7.0_07 source. + * Adapted by frank. + * + * We have to model java.lang.String since it changed its implementation between + * Java 1.6 and Java 1.7, and JPF is initializing string objects internally without + * doing roundtrips (for performance reasons), i.e. we need to be able to rely + * on fields of the String implementation. + * + * The silver lining is that most methods are now native and don't appear in + * traces anymore. Spending a lot of JPF cycles (instruction.execute()) on + * String is just not worth it in terms of potential properties. + */ + +public final class String +implements java.io.Serializable, Comparable, CharSequence { + + /** The value is used for character storage. */ + private final char value[]; + + /** Cache the hash code for the string */ + private int hash; // Default to 0 + + private static final long serialVersionUID = -6849794470754667710L; + + + private static final ObjectStreamField[] serialPersistentFields = + new ObjectStreamField[0]; + + public String() { + this.value = new char[0]; + } + + public String(String original) { + this.value = original.value; + this.hash = original.hash; + } + + public String(char value[]) { + this.value = Arrays.copyOf(value, value.length); + } + + public String(char value[], boolean share) { + this.value = Arrays.copyOf(value, value.length); + } + + public String(char value[], int offset, int count) { + String proxy=init(value,offset,count); + this.value=proxy.value; + this.hash=proxy.hash; + } + + private native String init(char[] value, int offset, int count); + + public String(int[] codePoints, int offset, int count) { + String proxy=init(codePoints,offset,count); + this.value=proxy.value; + this.hash=proxy.hash; + } + + private native String init(int[] codePoints, int offset, int count); + + @Deprecated + public String(byte ascii[], int hibyte, int offset, int count) { + String proxy=init(ascii,hibyte,offset,count); + this.value=proxy.value; + this.hash=proxy.hash; + } + + private native String init(byte ascii[], int hibyte, int offset, int count); + + @Deprecated + public String(byte ascii[], int hibyte) { + this(ascii, hibyte, 0, ascii.length); + } + + + + public String(byte bytes[], int offset, int length, String charsetName){ + String proxy=init(bytes,offset,length,charsetName); + this.value=proxy.value; + this.hash=proxy.hash; + } + + private native String init(byte bytes[], int offset, int length, String charsetName); + + + public String(byte x[], int offset, int length, Charset cset) { + // no Charset model + if (cset == null){ + throw new NullPointerException("cset"); + } + if (length < 0){ + throw new StringIndexOutOfBoundsException(length); + } + if (offset < 0){ + throw new StringIndexOutOfBoundsException(offset); + } + if (offset > x.length - length){ + throw new StringIndexOutOfBoundsException(offset + length); + } + + this.value = StringCoding.decode(cset, x, offset, length); + } + + public String(byte bytes[], String charsetName) + throws UnsupportedEncodingException { + this(bytes, 0, bytes.length, charsetName); + } + + public String(byte bytes[], Charset charset) { + this(bytes, 0, bytes.length, charset); + } + + public String(byte bytes[], int offset, int length) { + String proxy=init(bytes,offset,length); + this.value=proxy.value; + this.hash=proxy.hash; + } + + + private native String init(byte bytes[], int offset, int length); + + public String(byte bytes[]) { + this(bytes, 0, bytes.length); + } + + + public String(StringBuffer x) { + synchronized(x) { + this.value = Arrays.copyOf(x.getValue(), x.length()); + } + } + + + public String(StringBuilder x) { + this.value = Arrays.copyOf(x.getValue(), x.length()); + } + + @Deprecated + String(int offset, int count, char[] value) { + this(value, offset, count); + } + @Override + public int length() { + return value.length; + } + public boolean isEmpty() { + return value.length == 0; + } + @Override + public char charAt(int index) { + if ((index < 0) || (index >= value.length)) { + throw new StringIndexOutOfBoundsException(index); + } + return value[index]; + } + + native public int codePointAt(int index); + native public int codePointBefore(int index); + native public int codePointCount(int beginIndex, int endIndex); + native public int offsetByCodePoints(int index, int codePointOffset); + native public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin); + native void getChars(char dst[], int dstBegin); + + @Deprecated + native public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin); + native public byte[] getBytes(String charsetName) + throws UnsupportedEncodingException; + + public byte[] getBytes(Charset x){ + // No Charset model. + if (x == null){ + throw new NullPointerException(); + } + return StringCoding.encode(x, value, 0, value.length); + } + + native public byte[] getBytes(); + @Override + native public boolean equals(Object anObject); + public boolean contentEquals(StringBuffer stringBuffer){ + // No StringBuffer model. + synchronized (stringBuffer) { + return contentEquals((CharSequence) stringBuffer); + } + } + + native static boolean equals0 (char[] a, char[] b, int len); + + /** + * we can't turn this into a native method at top level since it would require a bunch + * of round trips + */ + public boolean contentEquals (CharSequence charSequence){ + if (value.length != charSequence.length()){ + return false; + } + + // that should be the common case (String) + if (charSequence.equals(this)){ + return true; + } + + // we can do that natively, too + if (charSequence instanceof AbstractStringBuilder) { + return equals0( value, ((AbstractStringBuilder) charSequence).getValue(), value.length); + } + + // generic CharSequence - expensive + char v[] = value; + for (int n=value.length, i=0; n >= 0; n--,i++){ + if (v[i] != charSequence.charAt(i)){ + return false; + } + } + return true; + } + + native public boolean equalsIgnoreCase(String anotherString); + @Override + native public int compareTo(String anotherString); + + public static final Comparator CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); + private static class CaseInsensitiveComparator implements Comparator, java.io.Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 8575799808933029326L; + + @Override + public int compare(String s1, String s2) { + return MJIcompare(s1,s2); + } + } + + native private static int MJIcompare(String s1,String s2); + public int compareToIgnoreCase(String str) { + return CASE_INSENSITIVE_ORDER.compare(this, str); + } + + native public boolean regionMatches(int toffset, String other, int ooffset, int len); + native public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len); + native public boolean startsWith(String prefix, int toffset); + public boolean startsWith(String prefix) { + return startsWith(prefix, 0); + } + + public boolean endsWith(String suffix) { + return startsWith(suffix, value.length - suffix.value.length); + } + + @Override + native public int hashCode(); + public int indexOf(int ch) { + return indexOf(ch, 0); + } + native public int indexOf(int ch, int fromIndex); + native public int lastIndexOf(int ch); + native public int lastIndexOf(int ch, int fromIndex); + native public int indexOf(String str); + native public int indexOf(String str, int fromIndex); + + public int lastIndexOf(String str) { + return lastIndexOf(str, value.length); + } + native public int lastIndexOf(String str, int fromIndex); + native public String substring(int beginIndex); + native public String substring(int beginIndex, int endIndex); + @Override + public CharSequence subSequence(int beginIndex, int endIndex) { + return this.substring(beginIndex, endIndex); + } + native public String concat(String str); + native public String replace(char oldChar, char newChar); + native public boolean matches(String regex); + public boolean contains(CharSequence charSequence) { + // No CharSequence model + return indexOf(charSequence.toString()) > -1; + } + native public String replaceFirst(String regex, String replacement); + native public String replaceAll(String regex, String replacement); + public String replace(CharSequence target, CharSequence other) { + // No CharSequence model + int PATTERN= 0x10; + Matcher pattern=Pattern.compile(target.toString(), PATTERN).matcher(this); + return pattern.replaceAll(Matcher.quoteReplacement(other.toString())); + } + native public String[] split(String regex, int limit); + native public String[] split(String regex); + native public String toLowerCase(Locale locale); + native public String toLowerCase(); + native public String toUpperCase(Locale locale); + native public String toUpperCase(); + native public String trim(); + @Override + public String toString() { + return this; + } + native public char[] toCharArray(); + native public static String format(String format, Object... args); + native public static String format(Locale l, String format, Object... args); + public static String valueOf(Object x){ + // can't translate arbitrary object + return (x == null) ? "null" : x.toString(); + } + public static String valueOf(char values[]) { + return new String(values); + } + public static String valueOf(char values[], int offset, int count) { + return new String(values, offset, count); + } + public static String copyValueOf(char values[], int offset, int count) { + return new String(values, offset, count); + } + public static String copyValueOf(char values[]) { + return new String(values); + } + public static String valueOf(boolean bool) { + return bool ? "true" : "false"; + } + public static String valueOf(char character) { + char data[] = {character}; + return new String(data); + } + native public static String valueOf(int i); + native public static String valueOf(long l); + native public static String valueOf(float f); + native public static String valueOf(double d); + public native String intern(); + + + /* + * methods to be compatible with Harmony/Android, which now has modified + * versions of the old (offset based) String + * + * NOTE - if the changes get too large we have to create Android specific + * models and peers + */ + + // used internally by Android's java.lang.AbstractStringBuffer + void _getChars(int start, int end, char[] buffer, int index) { + System.arraycopy(value, start, buffer, index, end - start); + } +} diff --git a/src/classes/java/lang/System.java b/src/classes/java/lang/System.java new file mode 100644 index 0000000..e18ee64 --- /dev/null +++ b/src/classes/java/lang/System.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.channels.Channel; +import java.util.Map; +import java.util.Properties; + +import sun.misc.JavaLangAccess; +import sun.misc.SharedSecrets; +import sun.nio.ch.Interruptible; +import sun.reflect.ConstantPool; +import sun.reflect.annotation.AnnotationType; + + +public class System { + + static Properties properties; + + public static InputStream in; // new BufferedInputStream(...); // <2do> not yet + public static PrintStream out; + public static PrintStream err; + + static { + + out = createSystemOut(); + err = createSystemErr(); + + properties = new Properties(); + + String[] kv = getKeyValuePairs(); + for (int i=0; i - most if this isn't supported yet + SharedSecrets.setJavaLangAccess( createJavaLangAccess()); + + // <2do> this is an approximation that isn't particularly safe since we don't + // initialize sun.misc.VM + //sun.misc.VM.booted(); + } + + static JavaLangAccess createJavaLangAccess () { + return new JavaLangAccess(){ + @Override + public ConstantPool getConstantPool(Class cls) { + throw new UnsupportedOperationException("JavaLangAccess.getConstantPool() not supported yet"); + //return cls.getConstantPool(); + } + @Override + public void setAnnotationType(Class cls, AnnotationType type) { + throw new UnsupportedOperationException("JavaLangAccess.setAnnotationType() not supported yet"); + //cls.setAnnotationType(type); + } + @Override + public AnnotationType getAnnotationType(Class cls) { + throw new UnsupportedOperationException("JavaLangAccess.getAnnotationType() not supported yet"); + //return cls.getAnnotationType(); + } + @Override + public > E[] getEnumConstantsShared(Class cls) { + return cls.getEnumConstantsShared(); + } + @Override + public void blockedOn(Thread t, Interruptible b) { + throw new UnsupportedOperationException("JavaLangAccess.blockedOn() not supported yet"); + //t.blockedOn(b); + } + @Override + public void registerShutdownHook(int slot, Runnable r) { + throw new UnsupportedOperationException("JavaLangAccess.registerShutdownHook() not supported yet"); + } + @Override + public int getStackTraceDepth(Throwable t) { + return t.getStackTraceDepth(); + } + @Override + public StackTraceElement getStackTraceElement(Throwable t, int i) { + StackTraceElement[] st = t.getStackTrace(); + return st[i]; + } + }; + } + + static private native String[] getKeyValuePairs(); + + static private native PrintStream createSystemOut(); + static private native PrintStream createSystemErr(); + + //--- standard streams + public static void setIn (InputStream newIn) { + in = newIn; + } + + public static void setOut (PrintStream newOut){ + out = newOut; + } + + public static void setErr (PrintStream newErr) { + err = newErr; + } + + public static Channel inheritedChannel() { + throw new UnsupportedOperationException("inheritedChannel() not yet supported"); + } + + //--- misc + public static native void exit (int rc); + public static native void arraycopy (Object src, int srcPos, + Object dst, int dstPos, int len); + public static native void gc(); + public static native void runFinalization(); + public static native void runFinalizersOnExit(boolean cond); + static native Class getCallerClass(); + public static native int identityHashCode (Object o); + + + //--- time management + public static native long currentTimeMillis(); + public static native long nanoTime(); + + //--- environment + public static native String getenv (String key); + public static Map getenv() { + throw new UnsupportedOperationException("getenv() not yet supported"); + } + + //--- security manager + static SecurityManager securityManager; + + public static void setSecurityManager (SecurityManager newManager) { + securityManager = newManager; + } + + public static SecurityManager getSecurityManager() { + return securityManager; + } + + //--- system properties + + public static Properties getProperties() { + return properties; + } + public static void setProperties(Properties newProps){ + properties = newProps; + } + + public static String getProperty (String key) { + return properties.getProperty(key); + } + + public static String getProperty (String key, String def){ + String v = properties.getProperty(key); + if (v == null){ + return def; + } else { + return v; + } + } + + public static String setProperty (String key, String value){ + String oldVal = properties.getProperty(key); + properties.put(key,value); + return oldVal; + } + + public static String clearProperty (String key) { + String oldVal = properties.getProperty(key); + properties.remove(key); + return oldVal; + } + + //--- native libs + public static void load (String pathName) { + // nothing, we don't have native libs + // (maybe we could on-demand load peers?) + } + + public static void loadLibrary (String libName){ + // nothing yet + } + + public static String mapLibraryName (String libName){ + // just a placeholder (Unix flavor) + return "lib" + libName + ".so"; + } + +} diff --git a/src/classes/java/lang/Thread.java b/src/classes/java/lang/Thread.java new file mode 100644 index 0000000..8c538f5 --- /dev/null +++ b/src/classes/java/lang/Thread.java @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +import gov.nasa.jpf.annotation.NeverBreak; +import sun.nio.ch.Interruptible; + +/** + * MJI model class for java.lang.Thread library abstraction + * + * <2do> this should not require the JPF ThreadList to retrieve corresponding ThreadInfos + * (the ThreadList might not store terminated threads) + */ +public class Thread implements Runnable { + + public interface UncaughtExceptionHandler { + // note this doesn't stop the thread from being terminated + void uncaughtException (Thread t, Throwable x); + } + + static int nameThreadNum; // to construct the default thread name + + public static final int MIN_PRIORITY = 1; + public static final int NORM_PRIORITY = 5; + public static final int MAX_PRIORITY = 10; + + // don't rename this - it's used by ThreadGoup.uncaughtException() + private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler; // null by default + + // initialized in init(), except of the main thread (which gets explicitly initialized by the VM) + ThreadGroup group; + Runnable target; + String name; + int priority; + boolean isDaemon; + + // this is an explicit thread state that gets set on a call of interrupt(), but + // only if the thread is not blocked. If it is, we only change the status. + // this gets cleared by calling interrupted() + boolean interrupted; + + // those are only accessed from peers since thread obects are per se shared + @NeverBreak + ThreadLocal.Entry[] threadLocals; + + // this is what we use for sun.misc.Unsafe.park()/unpark() + // this is accessed from the native peer, VM.createMainThread() and sun.misc.Unsafe + static class Permit { + boolean blockPark = true; // this is used to remember unpark() calls before park() (they don't accumulate) + } + Permit permit; // the object is used for wait/notify + + // referenced by java.util.concurrent.locks.LockSupport via sun.misc.Unsafe + // DON'T CHANGE THIS NAME + volatile Object parkBlocker; + + // used to store Thread.stop() exceptions + Throwable stopException; + + private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // null by default + + + public enum State { BLOCKED, NEW, RUNNABLE, TERMINATED, TIMED_WAITING, WAITING } + + + public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler xh) { + defaultUncaughtExceptionHandler = xh; + } + + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){ + return defaultUncaughtExceptionHandler; + } + + + public Thread () { + this(null, null, null, 0L); + } + + public Thread (Runnable target) { + this(null, target, null, 0L); + } + + public Thread (Runnable target, String name) { + this(null, target, name, 0L); + } + + public Thread (String name) { + this(null, null, name, 0L); + } + + public Thread (ThreadGroup group, String name) { + this(group, null, name, 0L); + } + + public Thread (ThreadGroup group, Runnable target) { + this(group, target, null, 0L); + } + + public Thread (ThreadGroup group, Runnable target, String name) { + this(group, target, name, 0L); + } + + public Thread (ThreadGroup group, Runnable target, String name, long stackSize) { + Thread cur = currentThread(); + + if (group == null) { + this.group = cur.getThreadGroup(); + } else { + this.group = group; + } + + this.group.add(this); + + if (name == null) { + this.name = "Thread-" + ++nameThreadNum; + } else { + this.name = name; + } + + this.permit = new Permit(); + + // those are always inherited from the current thread + this.priority = cur.getPriority(); + this.isDaemon = cur.isDaemon(); + + this.target = target; + + // do our associated native init + init0(this.group, target, this.name, stackSize); + + initThreadLocals(cur); + } + + // this takes care of ThreadInfo initialization + native void init0 (ThreadGroup group, Runnable target, String name, long stackSize); + + // this is here since InheritableThreadLocals would require childValue(parentVal) roundtrips. + // Unfortunately we can't defer this until the ThreadLocal is actually accessed since + // we have to capture the value at the point of child creation + // Note this executes in the parent thread + private void initThreadLocals (Thread parent){ + ThreadLocal.Entry[] tl = parent.threadLocals; + if (tl != null){ + int len = tl.length; + ThreadLocal.Entry[] inherited = null; + int j=0; + + for (int i=0; i e = tl[i]; + ThreadLocal.Entry ec = e.getChildEntry(); + if (ec != null){ + if (inherited == null){ + inherited = new ThreadLocal.Entry[len]; + } + inherited[j++] = ec; + } + } + + if (inherited != null){ + ThreadLocal.Entry[] a = new ThreadLocal.Entry[j]; + System.arraycopy(inherited,0,a,0,j); + threadLocals = a; + } + } + } + + public static int activeCount () { + return 0; + } + + public void setUncaughtExceptionHandler(UncaughtExceptionHandler xh) { + uncaughtExceptionHandler = xh; + } + + public UncaughtExceptionHandler getUncaughtExceptionHandler(){ + if (uncaughtExceptionHandler != null){ + return uncaughtExceptionHandler; + } else { + return group; + } + } + + public void setContextClassLoader (ClassLoader cl) { + } + + public ClassLoader getContextClassLoader () { + // + return null; + } + + public synchronized void setDaemon (boolean isDaemon) { + this.isDaemon = isDaemon; + setDaemon0(isDaemon); + } + + public boolean isDaemon () { + return isDaemon; + } + + public native long getId(); + + public StackTraceElement[] getStackTrace() { + return null; // not yet implemented + } + + public native int getState0(); + + public Thread.State getState() { + int i = getState0(); + switch (i) { + case 0: return State.BLOCKED; + case 1: return State.NEW; + case 2: return State.RUNNABLE; + case 3: return State.TERMINATED; + case 4: return State.TIMED_WAITING; + case 5: return State.WAITING; + } + + return null; // shoudl be intercepted by a getState0 assertion + } + + public synchronized void setName (String name) { + if (name == null) { + throw new IllegalArgumentException("thread name can't be null"); + } + + this.name = name; + setName0(name); + } + + public String getName () { + return name; + } + + public void setPriority (int priority) { + if ((priority < MIN_PRIORITY) || (priority > MAX_PRIORITY)) { + throw new IllegalArgumentException("thread priority out of range"); + } + + this.priority = priority; + setPriority0(priority); + } + + public int getPriority () { + return priority; + } + + public ThreadGroup getThreadGroup () { + return group; + } + + public void checkAccess () { + // + } + + public native int countStackFrames (); + + public static native Thread currentThread (); + + public void destroy () { + } + + public static void dumpStack () { + } + + public static int enumerate (Thread[] tarray) { + Thread cur = currentThread(); + + return cur.group.enumerate(tarray); + } + + public static native boolean holdsLock (Object obj); + + // this one needs to be native because it might change the thread status + public native void interrupt (); + + // those don't have to be native, but we keep it symmetric + public static native boolean interrupted (); + public native boolean isInterrupted (); + + public native boolean isAlive (); + + + /** + * note these are not synchronized anymore since they are intercepted by the + * native peer. The reason is that we don't want two CGs per join call (one for the + * sync call, and one for the wait) because this can cause serious + * performance degradation + */ + public void join () throws InterruptedException { + synchronized(this){ + + if (interrupted()) { + throw new InterruptedException(); + } + + while (isAlive()) { + // apparently, the JDK doesn't throw InterruptedExceptions if + // we get interrupted after waiting in the join + wait(); + } + } + } + + public void join (long millis) throws InterruptedException { + join(millis, 0); + } + + public void join (long millis, int nanos) throws InterruptedException { + + if (millis < 0){ + throw new java.lang.IllegalArgumentException("timeout value is negative"); + + } else if (millis == 0){ + join(); + + } else { + synchronized(this){ + if (interrupted()){ + throw new InterruptedException(); + } + + wait(millis); + } + } + } + + + + @Override + public void run () { + if (target != null) { + target.run(); + } + } + + public static void sleep (long millis) throws InterruptedException { + sleep(millis, 0); + } + + public static native void sleep (long millis, int nanos) + throws InterruptedException; + + public native void start(); + public native void stop(); + public native void stop(Throwable obj); + + public native void suspend(); + public native void resume(); + + + @Override + public String toString () { + return ("Thread[" + name + ',' + priority + ',' + (group == null ? "" : group.getName()) + ']'); + } + + public static native void yield (); + + native void setDaemon0 (boolean on); + + native void setName0 (String name); + + native void setPriority0 (int priority); + + + + /** + * automatically called by system upon thread termination to clean up + * references. + * + * NOTE - we clean up atomically during ThreadInfo.finish(), to avoid any + * additional states. This is important since group per se is a shared object + * We only include this method here as a specification for ThreadInfo + */ + private void exit () { + if (group != null){ + group.threadTerminated(this); + group = null; + } + + threadLocals = null; + parkBlocker = null; + uncaughtExceptionHandler = null; + } + + // some Java 6 mojo + // <2do> not implemented yet + native void blockedOn (Interruptible b); + + + // we probably will remove these fields once we modeled java.util.concurrent.ThreadLocalRandom + // to make it deterministic + long threadLocalRandomSeed; + int threadLocalRandomProbe; + int threadLocalRandomSecondarySeed; +} diff --git a/src/classes/java/lang/ThreadGroup.java b/src/classes/java/lang/ThreadGroup.java new file mode 100644 index 0000000..a4c8393 --- /dev/null +++ b/src/classes/java/lang/ThreadGroup.java @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + +import java.io.PrintStream; + +/** + * our model of java.lang.ThreadGroup, which we need since the VM relies on certain fields + * during bootstrapping + * + * Note that we don't have a native peer, which would help with atomic container updates, because + * most of these methods are called by the VM and we don't want to introduce a dependency from + * VM to the peers. This is esp. true since we would have to dig out & cast the peer, call it, + * and then go backwards extracting the *Info objects we already had in the calling context. + * + * If we ever want to introduce a peer, it could just delegate to the respective ThreadInfo methods. + */ +public class ThreadGroup implements Thread.UncaughtExceptionHandler { + private final ThreadGroup parent; + + //--- those are package visible, so we better keep names and access modifiers + + String name; + int maxPriority; + + int nthreads; + Thread[] threads; + + int ngroups; + ThreadGroup[] groups; + + int nUnstartedThreads; + + boolean destroyed; + boolean daemon; + + boolean vmAllowSuspension; + + public ThreadGroup (String name){ + this( Thread.currentThread().getThreadGroup(), name); + } + + public ThreadGroup (ThreadGroup parent, String name){ + this.parent = parent; + this.name = name; + + // those are inherited from the parent, which therefore can't be null + this.maxPriority = parent.maxPriority; + this.daemon = parent.daemon; + + parent.add(this); + } + + //--- the container updates + + // group updates are just class internal, whereas thread updates happen from java.lang.Thread and hence need + // package visibility + + private synchronized void add (ThreadGroup childGroup){ + if (destroyed){ + throw new IllegalThreadStateException(); + } + + if (groups == null){ + groups = new ThreadGroup[1]; + } else { + ThreadGroup[] ng = new ThreadGroup[ngroups+1]; + System.arraycopy(groups, 0, ng, 0, ngroups); + groups = ng; + } + + groups[ngroups++] = childGroup; + } + + private synchronized void remove (ThreadGroup childGroup){ + if (!destroyed){ + for (int i=0; i 1){ + int ngroups1 = ngroups - 1; + ThreadGroup[] ng = new ThreadGroup[ngroups1]; + if (i > 0) { + System.arraycopy(groups, 0, ng, 0, i); + } + if (i < ngroups1) { + System.arraycopy(groups, i + 1, ng, i, ngroups - i); + } + groups = ng; + ngroups = ngroups1; + + } else { + groups = null; + ngroups = 0; + } + + if (nthreads == 0){ + notifyAll(); + } + + // check if its time for a suicide in case we are a daemon group + if (daemon){ + if ((nthreads == 0) && (nUnstartedThreads == 0) && (ngroups == 0)){ + destroy(); + } + } + + break; + } + } + } + } + + + // thread add/remove happens from the native peer, to avoid additional CGs during creation/termination + // since the ThreadGroup is per se a shared object. We just include these methods here as a specification + // for ThreadInfo + + /** + * called from the Thread ctor, i.e. before it is started + * NOTE - this is implemented as a native method to avoid shared field CGs + */ + synchronized void addUnstarted (){ + if (destroyed){ + throw new IllegalThreadStateException(); + } + + nUnstartedThreads++; + } + + /** + * this is called during Thread.start() + * NOTE - this is implemented as a native method to avoid shared field CGs + */ + synchronized void add (Thread newThread){ + if (destroyed){ + throw new IllegalThreadStateException(); + } + + if (threads == null){ + threads = new Thread[1]; + } else { + Thread[] nt = new Thread[nthreads+1]; + System.arraycopy(threads, 0, nt, 0, nthreads); + threads = nt; + } + + threads[nthreads++] = newThread; + nUnstartedThreads--; + } + + /** + * this is called automatically upon thread termination + */ + synchronized void threadTerminated (Thread terminatedThread){ + if (!destroyed){ + for (int i=0; i 0) { + System.arraycopy(threads, 0, a, 0, i); + } + if (i < nthreads1) { + System.arraycopy(groups, i + 1, a, i, ngroups - i); + } + threads = a; + nthreads = nthreads1; + } + + // OpenJDK does this no matter if the group was destroyed, but that looks like a bug + // that could lead to multiple destroys and notifyAll() signals + if (nthreads == 0) { + notifyAll(); + } + if (daemon) { + if ((nthreads == 0) && (nUnstartedThreads == 0) && (ngroups == 0)) { + destroy(); + } + } + + break; + } + } + } + } + + //--- public getters and setters + public final String getName(){ + return name; + } + + public final ThreadGroup getParent(){ + return parent; + } + + public final int getMaxPriority(){ + return maxPriority; + } + + public final boolean isDaemon(){ + return daemon; + } + + public synchronized boolean isDestroyed(){ + return destroyed; + } + + public final void setDaemon (boolean daemon){ + this.daemon = daemon; + } + + /** + * this sets the maxPriority to the min of the argument and the parents maxPriority + * and raises maxPriority for all our threads that have a lower one + */ + public final synchronized void setMaxPriority (int newMaxPriority){ + // do nothing if newMaxPriority is outside limits + if (newMaxPriority >= Thread.MIN_PRIORITY && newMaxPriority <= Thread.MAX_PRIORITY){ + maxPriority = (parent != null) ? Math.min(parent.maxPriority, newMaxPriority) : newMaxPriority; + + for (int i=0; i 0){ + for (int i=0; i dst.length){ + len = dst.length - idx; + } + + for (int i = 0; i < len; i++) { + if (threads[i].isAlive()) { + dst[idx++] = threads[i]; + n++; + } + } + + if (recurse && (idx < dst.length)) { + for (int j = 0; j < ngroups; j++) { + n += groups[j].enumerate(dst, idx, true); + } + } + + return n; + } + + public synchronized int activeGroupCount() { + if (destroyed){ + return 0; + + } else { + int nActive = ngroups; + if (ngroups > 0){ + for (int i=0; i dst.length){ + len = dst.length - idx; + } + + for (int i = 0; i < len; i++) { + dst[idx++] = groups[i]; + n++; + } + + if (recurse && (idx < dst.length)) { + for (int j = 0; j < ngroups; j++) { + n += groups[j].enumerate(dst, idx, true); + } + } + + return n; + } + + static final int OP_STOP = 1; + static final int OP_INTERRUPT = 2; + static final int OP_SUSPEND = 3; + static final int OP_RESUME = 4; + + public final void stop(){ + if (doRecursively(OP_STOP)){ + Thread.currentThread().stop(); + } + } + public final void interrupt(){ + doRecursively(OP_INTERRUPT); + } + public final void suspend(){ + if (doRecursively(OP_SUSPEND)){ + Thread.currentThread().suspend(); + } + } + public final void resume(){ + doRecursively(OP_RESUME); + } + + private synchronized boolean doRecursively (int op){ + boolean suicide = false; + + for (int i=0; i 0)) { + throw new IllegalThreadStateException(); + } + + for (int i=0; i { + + static class Entry extends WeakReference> { + @NeverBreak + E val; + + Entry (ThreadLocal key, E val){ + super(key); + this.val = val; + } + + Entry getChildEntry (){ + ThreadLocal loc = get(); + if (loc instanceof InheritableThreadLocal){ + return new Entry( loc, ((InheritableThreadLocal)loc).childValue(val)); + } else { + return null; + } + } + } + + public ThreadLocal() { + } + + /** + * override to provide initial value + */ + protected T initialValue() { + return null; + } + + private native Entry getEntry(); + private native void addEntry (Entry e); + private native void removeEntry (Entry e); + + public T get() { + Entry e = getEntry(); + + if (e == null){ + T v = initialValue(); + e = new Entry(this, v); + addEntry(e); + } + + return e.val; + } + + public void set (T v){ + Entry e = getEntry(); + + if (e != null){ + e.val = v; + + } else { + e = new Entry(this, v); + addEntry(e); + } + } + + public void remove(){ + Entry e = getEntry(); + if (e != null){ + removeEntry(e); + } + } + + + // Java 8 provides this as an internal type to be used from lib classes + // ?? why is this not done with overridden initialValue() within the concrete ThreadLocal class + static final class SuppliedThreadLocal extends ThreadLocal { + + // we need to preserve the modifiers since this might introduce races (supplier could be shared) + private final Supplier sup; + + SuppliedThreadLocal(Supplier supplier) { + sup = Objects.requireNonNull(supplier); + } + + @Override + protected E initialValue() { + return sup.get(); + } + } +} diff --git a/src/classes/java/lang/Throwable.java b/src/classes/java/lang/Throwable.java new file mode 100644 index 0000000..ff19d97 --- /dev/null +++ b/src/classes/java/lang/Throwable.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * barebones model class for java.lang.Throwable + * + * the main reason for having one is to defer the stacktrace creation, which + * we don't want if all an application does is intercepting a gazillion of + * exceptions like NoSuchMethodException + */ +public class Throwable { + + int[] snapshot; // this is an internal array of { globalMethodId, pcOffset } pairs + + protected Throwable cause; // in case this is a wrapper exception (like InvocationTargetException) + + protected String detailMessage; // where we keep the context specific info + + protected StackTraceElement[] stackTrace; // only set on demand, if getStackTrace() is called + + public Throwable() { + try { // Use Class.forName() instead of new StackTraceElement() since the latter creates garbage. + Class.forName("java.lang.StackTraceElement"); // Force this class to load here instead of in createStackTrace(). + } catch (ClassNotFoundException e) { + throw new NoClassDefFoundError("java.lang.StackTraceElement"); + } + + fillInStackTrace(); + } + + public Throwable (String msg) { + this(); + detailMessage = msg; + cause = this; + } + + public Throwable (String msg, Throwable xCause) { + this(); + detailMessage = msg; + cause = xCause; + } + + public Throwable (Throwable xCause) { + this(); + + cause = xCause; + if (cause != null){ + detailMessage = xCause.toString(); + } + } + + public String getMessage() { + return detailMessage; + } + + public String getLocalizedMessage() { + return detailMessage; + } + + public Throwable getCause() { + if (cause == this){ + return null; // quirky + } else { + return cause; + } + } + + // this sets 'snapshot' from the native side + public native Throwable fillInStackTrace(); + + // and this turns 'snapshot' into an array of StackTraceElement objects + private native StackTraceElement[] createStackTrace(); + + public StackTraceElement[] getStackTrace() { + if (stackTrace == null){ + stackTrace = createStackTrace(); + } + + return stackTrace; + } + + public void setStackTrace (StackTraceElement[] st) { + stackTrace = st; + } + + public synchronized Throwable initCause (Throwable xCause) { + if (xCause == this){ + throw new IllegalArgumentException("self-causation not permitted"); + } + + if (cause != this){ + throw new IllegalStateException("cannot overwrite cause"); + } + + cause = xCause; + + return this; + } + + @Override + public native String toString(); + + public native void printStackTrace (); + + // <2do> and lots more of printStackTraces.. + + private native String getStackTraceAsString(); + + public void printStackTrace (PrintStream ps){ + String s = getStackTraceAsString(); + ps.print(s); + } + + public void printStackTrace (PrintWriter pw){ + String s = getStackTraceAsString(); + pw.print(s); + } + + int getStackTraceDepth(){ + return (snapshot.length / 2); // snapshot stores the methodId and pc for each StackFrame + } +} diff --git a/src/classes/java/lang/annotation/Inherited.java b/src/classes/java/lang/annotation/Inherited.java new file mode 100644 index 0000000..45b97c4 --- /dev/null +++ b/src/classes/java/lang/annotation/Inherited.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang.annotation; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface Inherited { +} diff --git a/src/classes/java/lang/annotation/Retention.java b/src/classes/java/lang/annotation/Retention.java new file mode 100644 index 0000000..4077cd3 --- /dev/null +++ b/src/classes/java/lang/annotation/Retention.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang.annotation; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface Retention { + RetentionPolicy value(); +} diff --git a/src/classes/java/lang/ref/Reference.java b/src/classes/java/lang/ref/Reference.java new file mode 100644 index 0000000..f69f33d --- /dev/null +++ b/src/classes/java/lang/ref/Reference.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.ref; + +/** + * MJI model class for java.lang.ref.Reference library abstraction + * we model this so that we can rely on our WeakRefence implementation + */ +public abstract class Reference { + + /** + * the object we reference + * NOTE: this has to be the *first* field, or we break WeakReference handling in + * the garbage collection!! + */ + T ref; + + /** the optional queue for us */ + ReferenceQueue queue; + + /** link to enqueue w/o additional memory requirements */ + Reference next; + + Reference (T r) { + ref = r; + } + + Reference (T r, ReferenceQueue q) { + ref = r; + queue = q; + } + + /** is the referenced object enqueued */ + public boolean isEnqueued () { + // <2do> + return false; + } + + /** clear, but do not enqueue the referenced object */ + public void clear () { + ref = null; + } + + /** add the referenced object to its queue */ + public void enqueue () { + } + + /** return the referenced object */ + public T get () { + return ref; + } +} diff --git a/src/classes/java/lang/ref/ReferenceQueue.java b/src/classes/java/lang/ref/ReferenceQueue.java new file mode 100644 index 0000000..6085cba --- /dev/null +++ b/src/classes/java/lang/ref/ReferenceQueue.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.ref; + +/** + * MJI model class for java.lang.ref.ReferenceQueue library abstraction + */ +public class ReferenceQueue { + Reference head; + + public ReferenceQueue () { + } + + public Reference poll () { + // <2do> + return null; + } + + public Reference remove () { + // <2do> + return null; + } + + public Reference remove (long timeout) { + // <2do> + return null; + } +} diff --git a/src/classes/java/lang/ref/WeakReference.java b/src/classes/java/lang/ref/WeakReference.java new file mode 100644 index 0000000..8b8cd51 --- /dev/null +++ b/src/classes/java/lang/ref/WeakReference.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.ref; + +/** + * MJI model class for java.lang.ref.WeakReference library abstraction + */ +public class WeakReference extends Reference { + public WeakReference (T ref) { + super( ref); + } + + public WeakReference (T ref, ReferenceQueue queue) { + super( ref, queue); + } +} diff --git a/src/classes/java/lang/reflect/AccessibleObject.java b/src/classes/java/lang/reflect/AccessibleObject.java new file mode 100644 index 0000000..44e7044 --- /dev/null +++ b/src/classes/java/lang/reflect/AccessibleObject.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.reflect; + +import java.lang.annotation.Annotation; + +public class AccessibleObject { + boolean isAccessible = true; + + public void setAccessible (boolean flag) throws SecurityException { + isAccessible = flag; + } + + public static void setAccessible (AccessibleObject[] accessibles, boolean flag) throws SecurityException { + for (int i=0; i T getAnnotation (Class cls); // <2do> Implement in JPF_java_lang_reflect_Constructor + + public boolean isAnnotationPresent (Class cls) { + return getAnnotation(cls) != null; + } + + public native Annotation[] getAnnotations(); // <2do> Implement in JPF_java_lang_reflect_Constructor + + public native Annotation[] getDeclaredAnnotations(); // <2do> Implement in JPF_java_lang_reflect_Method, JPF_java_lang_reflect_Class and JPF_java_lang_reflect_Constructor +} diff --git a/src/classes/java/lang/reflect/Constructor.java b/src/classes/java/lang/reflect/Constructor.java new file mode 100644 index 0000000..0a663c0 --- /dev/null +++ b/src/classes/java/lang/reflect/Constructor.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.reflect; + +import java.lang.annotation.Annotation; + +/** + * (incomplete) support for consructor reflection + * + * pretty stupid - this is almost identical to Method, but we can't derive, + * and the delegation happens at the peer level anyways. + * + * NOTE: 'regIdx' and 'name' need to be like Method, or the peer delegation + * fails (this is the hack'ish part) + * + * NOTE: we ditch the 'final' modifier so that we can provide our + * own serialization ctor objects - that's probably going away + * once we replace ObjectStreamClass + */ +public /*final*/ class Constructor extends AccessibleObject implements Member { + + protected int regIdx; + protected String name; + + @Override + public native String getName(); + public native T newInstance (Object... args) + throws IllegalAccessException, InvocationTargetException, InstantiationException; + + @Override + public native int getModifiers(); + public native Class getReturnType(); + public native Class[] getParameterTypes(); + + @Override + public native Class getDeclaringClass(); + + @Override + public native Annotation[] getAnnotations(); + @Override + public native Annotation[] getDeclaredAnnotations(); + @Override + public native T getAnnotation( Class annotationCls); + public native Annotation[][] getParameterAnnotations(); + + @Override + public boolean isSynthetic () { + return false; + } + + @Override + public native String toString(); + + @Override + public native boolean equals (Object obj); + + public boolean isVarArgs (){ + return (getModifiers() & Modifier.VARARGS) != 0; + } + + @Override + public native int hashCode (); + + public native String toGenericString (); +} diff --git a/src/classes/java/lang/reflect/Field.java b/src/classes/java/lang/reflect/Field.java new file mode 100644 index 0000000..f53dfb9 --- /dev/null +++ b/src/classes/java/lang/reflect/Field.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.reflect; + +import java.lang.annotation.Annotation; + +public final class Field extends AccessibleObject implements Member { + int regIdx; // the link to the corresponding FieldInfo + String name; // deferred set by the NativePeer getName() + + public String toGenericString() { + // TODO: return real generic string + return toString(); + } + + public native boolean getBoolean (Object o) throws IllegalAccessException; + public native void setBoolean (Object o, boolean v) throws IllegalAccessException; + + public native byte getByte (Object o) throws IllegalAccessException; + public native void setByte (Object o, byte v) throws IllegalAccessException; + + public native short getShort (Object o) throws IllegalAccessException; + public native void setShort (Object o, short v) throws IllegalAccessException; + + public native char getChar (Object o) throws IllegalAccessException; + public native void setChar (Object o, char v) throws IllegalAccessException; + + public native int getInt (Object o) throws IllegalAccessException; + public native void setInt (Object o, int val) throws IllegalAccessException; + + public native long getLong (Object o) throws IllegalAccessException; + public native void setLong (Object o, long v) throws IllegalAccessException; + + public native float getFloat (Object o) throws IllegalAccessException; + public native void setFloat (Object o, float v) throws IllegalAccessException; + + public native double getDouble (Object o) throws IllegalAccessException; + public native void setDouble (Object o, double v) throws IllegalAccessException; + + public native Class getType (); + + public native Object get (Object o) throws IllegalAccessException; + + public native void set (Object o, Object v) throws IllegalArgumentException, IllegalAccessException; + // the member interface + @Override + public native String getName(); + + @Override + public native int getModifiers(); + + @Override + public native Annotation[] getAnnotations(); + + @Override + public native T getAnnotation( Class annotationCls); + + @Override + public native Class getDeclaringClass (); + + @Override + public native boolean isSynthetic (); + + @Override + public native boolean equals (Object obj); + + @Override + public native String toString (); + + public boolean isEnumConstant (){ + return (getModifiers() & Modifier.ENUM) != 0; + } + + @Override + public native int hashCode (); + + @Override + public native Annotation[] getDeclaredAnnotations (); +} diff --git a/src/classes/java/lang/reflect/InvocationTargetException.java b/src/classes/java/lang/reflect/InvocationTargetException.java new file mode 100644 index 0000000..83ec322 --- /dev/null +++ b/src/classes/java/lang/reflect/InvocationTargetException.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang.reflect; + +/** + * not really required to model, but the real thing does some funky + * things to override the cause, just making things a bit more complicated + * on our VM side (we still init Throwables explicitly from ThreadInfo) + */ +public class InvocationTargetException extends Exception { + + public InvocationTargetException (Throwable cause){ + super(cause); + } + + public Throwable getTargetException() { + return cause; + } +} diff --git a/src/classes/java/lang/reflect/Method.java b/src/classes/java/lang/reflect/Method.java new file mode 100644 index 0000000..e782d44 --- /dev/null +++ b/src/classes/java/lang/reflect/Method.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.reflect; + +import java.lang.annotation.Annotation; + +/** + * minimal Method reflection support. + * Note that we share peer code between Method and Constructor (which aren't + * really different on the JPF side), so don't change field names! + */ +public final class Method extends AccessibleObject implements Member { + int regIdx; // the link to the corresponding MethodInfo + String name; // deferred set by the NativePeer getName() + + @Override + public native String getName(); + public String toGenericString() { + // TODO: return real generic string + return toString(); + } + public native Object invoke (Object object, Object... args) + throws IllegalAccessException, InvocationTargetException; + + @Override + public native int getModifiers(); + public native Class getReturnType(); + public native Class[] getParameterTypes(); + public native Type[] getGenericParameterTypes(); + public native Class[] getExceptionTypes(); + + @Override + public native Class getDeclaringClass(); + + @Override + public native Annotation[] getAnnotations(); + @Override + public native Annotation[] getDeclaredAnnotations(); + @Override + public native T getAnnotation( Class annotationCls); + public native Annotation[][] getParameterAnnotations(); + + @Override + public boolean isSynthetic (){ + return Modifier.isSynthetic(getModifiers()); + } + + @Override + public native String toString(); + + // for Annotations - return the default value of the annotation member + // represented by this method + public Object getDefaultValue() { + throw new UnsupportedOperationException("Method.getDefaultValue() not supported yet"); + } + + @Override + public native boolean equals (Object obj); + + public boolean isVarArgs (){ + return (getModifiers() & Modifier.VARARGS) != 0; + } + + @Override + public native int hashCode (); + + public boolean isBridge (){ + return (getModifiers() & Modifier.BRIDGE) != 0; + } +} diff --git a/src/classes/java/net/URLClassLoader.java b/src/classes/java/net/URLClassLoader.java new file mode 100644 index 0000000..107d79d --- /dev/null +++ b/src/classes/java/net/URLClassLoader.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.net; + +import java.io.IOException; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.SecureClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Vector; +import java.util.jar.Manifest; + +/** + * @author Nastaran Shafiei + * + * Model class for java.net.URLClassLoader + */ +public class URLClassLoader extends SecureClassLoader { + + private ArrayList urls = new ArrayList(0); + + public URLClassLoader(URL[] urls) { + super(); + addURLs(urls); + } + + public URLClassLoader(URL[] urls, ClassLoader parent) { + super(parent); + addURLs(urls); + } + + private void addURLs(URL[] urls) { + for(URL url: urls) { + addURL(url); + } + } + + private native void addURL0(String url); + + protected void addURL(URL url) { + addURL0(url.toString()); + urls.add(url); + } + + @Override + protected native Class findClass(final String name) throws ClassNotFoundException; + + private native String findResource0 (String rname); + + @Override + public URL findResource(final String rname) { + URL url = null; + String path = findResource0(rname); + + try { + url = new URL(path); + } catch (MalformedURLException x){ + url = null; + } + + return url; + } + + private native String[] findResources0 (String rname); + + @Override + public Enumeration findResources(String name) throws IOException { + String[] urls = findResources0(name); + Vector list = new Vector(0); + for(String url: urls) { + try { + list.add(new URL(url)); + } catch (MalformedURLException x){ + // process the rest + } + } + + return list.elements(); + } + + public URL[] getURLs() { + return urls.toArray(new URL[urls.size()]); + } + + public static URLClassLoader newInstance(URL[] urls) { + return (new URLClassLoader(urls)); + } + + public static URLClassLoader newInstance(URL[] urls, ClassLoader parent) { + return (new URLClassLoader(urls, parent)); + } + + //--- unsupported methods + + public URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { + throw new UnsupportedOperationException(); + } + + public void close() throws IOException { + throw new UnsupportedOperationException(); + } + + protected Package definePackage(String name, Manifest man, URL url) + throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + protected PermissionCollection getPermissions(CodeSource codesource) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/classes/java/nio/Buffer.java b/src/classes/java/nio/Buffer.java new file mode 100644 index 0000000..0dadad7 --- /dev/null +++ b/src/classes/java/nio/Buffer.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.nio; + +public abstract class Buffer { + protected int position; + protected int capacity; + protected int limit; + + public final int capacity() { + return capacity; + } + + public final Buffer position(int newPosition) { + if ((newPosition<0)||(newPosition>limit)) { + throw new IllegalArgumentException("Illegal buffer position exception: "+newPosition); + } + this.position = newPosition; + return this; + } + + public final int position() { + return position; + } + + public final int limit() { + return this.limit; + } + + public final Buffer limit(int newLimit) { + if ((newLimit<0)||(newLimit>capacity)) { + throw new IllegalArgumentException("Illegal buffer limit exception: "+newLimit); + } + this.limit = newLimit; + return this; + } + + public final Buffer clear(){ + position = 0; + limit = capacity; + return this; + } + + public final Buffer flip() { + limit = position; + position = 0; + return this; + } + + public final Buffer rewind() { + position = 0; + return this; + } + + public final int remaining() { + return limit-position; + } + + public final boolean hasRemaining() { + return remaining()>0; + } + + public abstract boolean hasArray(); + + public abstract Object array(); +} diff --git a/src/classes/java/nio/BufferUnderflowException.java b/src/classes/java/nio/BufferUnderflowException.java new file mode 100644 index 0000000..cd48d0f --- /dev/null +++ b/src/classes/java/nio/BufferUnderflowException.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.nio; + +public class BufferUnderflowException extends RuntimeException { + public BufferUnderflowException() { } +} diff --git a/src/classes/java/nio/ByteBuffer.java b/src/classes/java/nio/ByteBuffer.java new file mode 100644 index 0000000..e0c99a7 --- /dev/null +++ b/src/classes/java/nio/ByteBuffer.java @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.nio; + +public class ByteBuffer extends Buffer { + byte[] array; + + public static ByteBuffer allocate(int i) { + if (i < 0) { + throw new IllegalArgumentException(); + } + ByteBuffer newBuffer = new ByteBuffer(i); + return newBuffer; + } + + public static ByteBuffer allocateDirect(int capacity) { + return allocate(capacity); + } + + protected ByteBuffer(int i) { + capacity = i; + this.clear(); + array = new byte[i]; + } + + public ByteBuffer duplicate() { + ByteBuffer copy = new ByteBuffer(capacity); + copy.array = array; + return copy; + } + + public ByteBuffer asReadOnlyBuffer() { + return duplicate(); + } + + public ByteBuffer slice() { + int remaining = limit - position; + ByteBuffer copy = new ByteBuffer(remaining); + copy.array = array; + return copy; + } + + public ByteBuffer put(byte b) { + if (position >= limit) { + throw new BufferOverflowException(); + } + array[position] = b; + position++; + return this; + } + + public ByteBuffer put(int i, byte b) { + if ((i < 0) || (i >= limit)) { + throw new IndexOutOfBoundsException(); + } + array[i] = b; + return this; + } + + public ByteBuffer put(ByteBuffer src) { + if (src == this) { + throw new IllegalArgumentException(); + } + + int srcRemaining = src.remaining(); + if (srcRemaining > remaining()) { + throw new BufferOverflowException(); + } + + System.arraycopy(src.array, src.position(), array, position, srcRemaining); + + src.position(src.position() + srcRemaining); + position(position + srcRemaining); + + return this; + } + + public ByteBuffer put(byte[] bytes, int offset, int length) { + if ((offset | length | (offset + length) | (bytes.length - (offset + length))) < 0) { + throw new IndexOutOfBoundsException(); + } + + if (length > remaining()) { + throw new BufferOverflowException(); + } + + System.arraycopy(bytes, offset, array, position, length); + position(position + length); + + return this; + } + + public ByteBuffer put(byte[] bytes) { + return put(bytes, 0, bytes.length); + } + + public byte get() { + if (position >= limit) { + throw new BufferUnderflowException(); + } + position++; + return array[position-1]; + } + + public byte get(int i) { + if ((i < 0) || (i >= limit)) { + throw new IndexOutOfBoundsException(); + } + return array[i]; + } + + public ByteBuffer get(byte[] bytes) { + return get(bytes, 0, bytes.length); + } + + public ByteBuffer get(byte[] bytes, int offset, int length) { + if ((offset | length | (offset + length) | (bytes.length - (offset + length))) < 0) { + throw new IndexOutOfBoundsException(); + } + + if (length > remaining()) { + throw new BufferUnderflowException(); + } + + int end = offset + length; + for (int i = offset; i < end; i++) { + bytes[i] = get(); + } + return this; + } + + public ByteBuffer order(ByteOrder order) { + return this; + } + + /*************************************************************** + * public char getChar() + * @return 16 bit (UTF-16) char of ByteBuffer at this.position + * Caution: 8 or 32 bit character encodings are not supported. + */ + public char getChar() { + char res=getChar(this.position); + this.position+=2; + return res; + } + + /*************************************************************** + * public char getChar(int pos) + * @return 16 bit (UTF-16) char of ByteBuffer at int pos + * Caution: 8 or 32 bit character encodings are not supported. + */ + public char getChar(int pos) { + if (limit - pos < 2) { + throw new BufferUnderflowException(); + } + int x1 = (array[pos] & 0xff) << 8; + int x0 = (array[pos+1] & 0xff); + + return (char) (x1 | x0); + } + + /*************************************************************** + * public ByteBuffer putChar(char c) + * @return insert 16 bit (UTF-16) char c at this.position + * Caution: 8 or 32 bit character encodings are not supported. + */ + public ByteBuffer putChar(char c) { + if (limit - position < 2) { + throw new BufferOverflowException(); + } + array[position] = (byte)(c >> 8); + array[position+1] = (byte)(c ); + position += 2; + + return this; + } + + public int getInt() { + if (limit - position < 4) { + throw new BufferUnderflowException(); + } + + int x3 = (array[position ] ) << 24; + int x2 = (array[position+1] & 0xff) << 16; + int x1 = (array[position+2] & 0xff) << 8; + int x0 = (array[position+3] & 0xff); + position += 4; + + return (x3 | x2 | x1 | x0); + } + + public ByteBuffer putInt(int x) { + if (limit - position < 4) { + throw new BufferOverflowException(); + } + + array[position ] = (byte)(x >> 24); + array[position+1] = (byte)(x >> 16); + array[position+2] = (byte)(x >> 8); + array[position+3] = (byte)(x ); + position += 4; + + return this; + } + + public long getLong() { + if (limit - position < 8) { + throw new BufferUnderflowException(); + } + + long x7 = ((long)(array[position ] ) << 56); + long x6 = ((long)(array[position+1] & 0xff) << 48); + long x5 = ((long)(array[position+2] & 0xff) << 40); + long x4 = ((long)(array[position+3] & 0xff) << 32); + long x3 = ((long)(array[position+4] & 0xff) << 24); + long x2 = ((long)(array[position+5] & 0xff) << 16); + long x1 = ((long)(array[position+6] & 0xff) << 8); + long x0 = (array[position+7] & 0xff ); + position += 8; + + return (x7 | x6 | x5 | x4 | x3 | x2 | x1 | x0); + } + + public ByteBuffer putLong(long x) { + if (limit - position < 8) { + throw new BufferOverflowException(); + } + + array[position ] = (byte)((x >> 56) ); + array[position+1] = (byte)((x >> 48) & 0xff); + array[position+2] = (byte)((x >> 40) & 0xff); + array[position+3] = (byte)((x >> 32) & 0xff); + array[position+4] = (byte)((x >> 24) & 0xff); + array[position+5] = (byte)((x >> 16) & 0xff); + array[position+6] = (byte)((x >> 8) & 0xff); + array[position+7] = (byte)((x ) & 0xff); + position += 8; + + return this; + } + + @Override + public byte[] array() { + return array; + } + + @Override + public boolean hasArray() { + return true; + } + + public ByteBuffer compact() { + int pos = position(); + int lim = limit(); + int cap = capacity(); + int rem = lim - pos; + + byte[] newArray = new byte[cap]; + System.arraycopy(array, pos, newArray, 0, rem); + array = newArray; + + position(rem); + limit(cap); + return this; + } + + public static ByteBuffer wrap(byte[] outMess) { + ByteBuffer byteBuffer = new ByteBuffer(outMess.length); + byteBuffer.clear(); + System.arraycopy(outMess, 0 , byteBuffer.array, 0, outMess.length); + return byteBuffer; + } +} diff --git a/src/classes/java/nio/ByteOrder.java b/src/classes/java/nio/ByteOrder.java new file mode 100644 index 0000000..bb0be5d --- /dev/null +++ b/src/classes/java/nio/ByteOrder.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.nio; + +public final class ByteOrder { + private String name; + + private ByteOrder(String name) { + this.name = name; + } + + public static final ByteOrder BIG_ENDIAN = new ByteOrder("BIG_ENDIAN"); + public static final ByteOrder LITTLE_ENDIAN = new ByteOrder("LITTLE_ENDIAN"); + + @Override + public String toString() { + return name; + } + + public static ByteOrder nativeOrder() { return null; } // stub for Eclipse +} diff --git a/src/classes/java/nio/channels/FileChannel.java b/src/classes/java/nio/channels/FileChannel.java new file mode 100644 index 0000000..1003393 --- /dev/null +++ b/src/classes/java/nio/channels/FileChannel.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.nio.channels; + +import java.io.IOException; +import java.io.FileDescriptor; + +import java.nio.ByteBuffer; + +//This class uses the methods from FileDescriptor in order to access files +public class FileChannel { + + public int read(ByteBuffer dst) throws IOException{ + return fd.read(dst.array(),0,dst.array().length); + } + + public int write(ByteBuffer src) throws IOException{ + fd.write(src.array(),0,src.array().length); + return src.array().length; + } + + public void close() throws IOException{ + fd.close(); + } + + public FileChannel(FileDescriptor fd){ + this.fd = fd; + } + + private FileDescriptor fd = null; + + public long position() { return 0; } // Stub for Eclipse + + public FileChannel position(long p) { return null; } // Stub for Eclipse +} diff --git a/src/classes/java/nio/package-info.java b/src/classes/java/nio/package-info.java new file mode 100644 index 0000000..81d8ca1 --- /dev/null +++ b/src/classes/java/nio/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains Byte* classes and exceptions. + * + * All of them are implemented straightforwardly but + * only few methods are tested. + */ +package java.nio; diff --git a/src/classes/java/security/AccessController.java b/src/classes/java/security/AccessController.java new file mode 100644 index 0000000..2f9a2c9 --- /dev/null +++ b/src/classes/java/security/AccessController.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.security; + + +/* + * MJI model class for java.security.AccessController library abstraction + */ +public class AccessController { + public static void checkPermission (Permission p) throws AccessControlException { + } + + public static T doPrivileged (PrivilegedAction action, + AccessControlContext context) { + return action.run(); + } + + public static T doPrivileged (PrivilegedAction action) { + return action.run(); + } + + public static T doPrivileged (PrivilegedExceptionAction action, + AccessControlContext context) + throws PrivilegedActionException { + + try { + return action.run(); + + } catch (RuntimeException rx){ + throw rx; // we have to let unchecked exceptions pass + } catch (Exception x) { + throw new PrivilegedActionException(x); + } + } + + public static T doPrivileged (PrivilegedExceptionAction action) + throws PrivilegedActionException { + + try { + return action.run(); + + } catch (RuntimeException rx){ + throw rx; // we have to let unchecked exceptions pass + } catch (Exception x) { + throw new PrivilegedActionException(x); + } + } + + public static AccessControlContext getContext() { + return null; + } + + @SuppressWarnings("unused") + private static AccessControlContext getStackAccessControlContext() { + return null; + } + + static AccessControlContext getInheritedAccessControlContext() { + return null; + } + +} + diff --git a/src/classes/java/security/MessageDigest.java b/src/classes/java/security/MessageDigest.java new file mode 100644 index 0000000..4b7a249 --- /dev/null +++ b/src/classes/java/security/MessageDigest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.security; + +/** + * forwarding implementation of MessageDigest. + * <2do> only partially implemented (as required by serialization) + */ +public class MessageDigest extends MessageDigestSpi { + + String algorithm; + int id; // set by native peer + + private native int init0 (String algorithm); + + protected MessageDigest (String algorithm) throws NoSuchAlgorithmException { + if (!algorithm.equalsIgnoreCase("SHA") && !algorithm.equalsIgnoreCase("MD5")){ + throw new NoSuchAlgorithmException("unknown algorithm: " + algorithm); + } + + this.algorithm = algorithm; + id = init0(algorithm); + } + + public static MessageDigest getInstance (String algorithm) throws NoSuchAlgorithmException { + return new MessageDigest(algorithm); // keep it simple + } + + public native byte[] digest (byte[] input); + + public native byte[] digest (); + + public native void update(byte[] input); + + @Override + protected native void finalize(); // to clean up + + // those are required by the compiler, but never used since we forward + // all public methods + @Override + protected native byte[] engineDigest (); + + @Override + protected native void engineReset (); + + @Override + protected native void engineUpdate (byte input); + + @Override + protected native void engineUpdate (byte[] input, int offset, int len); + +} diff --git a/src/classes/java/security/SecureClassLoader.java b/src/classes/java/security/SecureClassLoader.java new file mode 100644 index 0000000..3abae10 --- /dev/null +++ b/src/classes/java/security/SecureClassLoader.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.security; + +/** + * This is just a dummy implementation of java.security.SecureClassLoader + * @author Nastaran Shafiei + */ +public class SecureClassLoader extends ClassLoader { + + protected SecureClassLoader(ClassLoader parent) { + super(parent); + } + + protected SecureClassLoader() { + super(); + } +} diff --git a/src/classes/java/text/DecimalFormat.java b/src/classes/java/text/DecimalFormat.java new file mode 100644 index 0000000..2e783d0 --- /dev/null +++ b/src/classes/java/text/DecimalFormat.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.text; + +/** + * <2do> this class is a Q&D version to get some support for NumberFormats - + * something we aren't too interested in yet. The model side has to be extended + * to include all the delegation, but the real work should happen on the + * peer side by forwarding to the real classes + */ + +public class DecimalFormat extends NumberFormat implements Cloneable{ + private static final long serialVersionUID = 1L; + + /* + * NOTE: if we would directly intercept the ctors, we would have to + * explicitly call the superclass ctors from the native peer + * (the 'id' handle gets initialized in the java.text.Format ctor) + */ + private native void init0(); + private native void init0(String pattern); + private native void init0(int style); + + public DecimalFormat () { + init0(); + } + + public DecimalFormat (String pattern) { + init0(pattern); + } + + public DecimalFormat(String pattern, DecimalFormatSymbols symbols) { + // <2do> that's incomplete - has to delegate to the DecimalFormatSymbols + // object, but should do so here in the model not the peer + this(pattern); + } + + DecimalFormat (int style) { + init0(style); + } + // intercepted by native peer + + @Override + public StringBuffer format (Object obj, StringBuffer toAppendTo, FieldPosition pos) { + // works for use case where pos = new FieldPosition(0) + toAppendTo.append(obj.toString()); + return toAppendTo; + } + + @Override + public Number parse(String source, ParsePosition pos){ + // interceptted by native peer + return null; + } + + @Override + public void setMaximumFractionDigits (int newValue){ + // intercepted by native peer + } + @Override + public void setMaximumIntegerDigits (int newValue){ + // intercepted by native peer + } + @Override + public void setMinimumFractionDigits(int newValue){ + // intercepted by native peer + } + @Override + public void setMinimumIntegerDigits(int newValue){ + // intercepted by native peer + } + + @Override + public String format (long number) { + // intercepted by native peer + return null; + } + + @Override + public String format (double number) { + // intercepted by native peer + return null; + } + + public DecimalFormatSymbols getDecimalFormatSymbols() { + return new DecimalFormatSymbols(); + } + + public String getPositivePrefix() { + return ""; + } + + public String getNegativePrefix() { + return "-"; + } + + public String getPositiveSuffix() { + return ""; + } + + public String getNegativeSuffix() { + return ""; + } + + @Override + public boolean isGroupingUsed() { + return false; + } + + @Override + public void setGroupingUsed(boolean newValue) { + // intercepted by native peer + } + + @Override + public boolean isParseIntegerOnly() { + return false; + } + + @Override + public void setParseIntegerOnly(boolean value) { + // intercepted by native peer + } + // and probably a lot missing +} diff --git a/src/classes/java/text/Format.java b/src/classes/java/text/Format.java new file mode 100644 index 0000000..09ebc8c --- /dev/null +++ b/src/classes/java/text/Format.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.text; + +/** + * (incomplete) model class for java.text.Format + * the reason we model this is that we want to cut off all the inner + * workings by just delegating to real formatters stored in our + * native peer + */ +public abstract class Format { + + // how does that work with backtracking? my initial guess is that + // we can safely overwrite an index because after backtracking, the + // formatter will never be used. It's therefore sufficient if we keep the + // nInstances counter in the JPF space + // (just a reminder - we can't use the reference value because it might + // change -- the ElementInfo invariance sucks! + static int nInstances; + private int id = nInstances++; // just for peer implementation purposes + + public String format (Object o) { + StringBuffer sb = new StringBuffer(); + FieldPosition pos = new FieldPosition(0); + return format(o, sb, pos).toString(); + } + + public abstract StringBuffer format (Object o, StringBuffer sb, FieldPosition pos); + + public abstract Object parseObject (String source, ParsePosition pos); + + public Object parseObject(String source) throws ParseException { + ParsePosition pos = new ParsePosition(0); + Object result = parseObject(source, pos); + if (pos.index == 0) { + throw new ParseException("Format.parseObject(String) failed", + pos.errorIndex); + } + return result; + } +} diff --git a/src/classes/java/text/NumberFormat.java b/src/classes/java/text/NumberFormat.java new file mode 100644 index 0000000..1848723 --- /dev/null +++ b/src/classes/java/text/NumberFormat.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.text; + +public abstract class NumberFormat extends Format { + + static final int INTEGER_STYLE=0; + static final int NUMBER_STYLE=1; + + public static NumberFormat getIntegerInstance() { + return new DecimalFormat(INTEGER_STYLE); + } + + public static NumberFormat getNumberInstance() { + return new DecimalFormat(NUMBER_STYLE); + } + + public static NumberFormat getInstance() { + return new DecimalFormat(NUMBER_STYLE); + } + + public void setMaximumFractionDigits (int newValue){ + // intercepted by native peer + } + public void setMaximumIntegerDigits (int newValue){ + // intercepted by native peer + } + public void setMinimumFractionDigits(int newValue){ + // intercepted by native peer + } + public void setMinimumIntegerDigits(int newValue){ + // intercepted by native peer + } + + public String format (long number) { + // intercepted by native peer + return null; + } + + public String format (double d) { + // intercepted by native peer + return null; + } + + @Override + public final Object parseObject (String source, ParsePosition pos) { + return parse(source,pos); + } + + public void setParseIntegerOnly(boolean value) { + // intercepted by native peer + } + + public boolean isParseIntegerOnly() { + // intercepted by native peer + return false; + } + + public boolean isGroupingUsed() { + return false; + } + + public void setGroupingUsed(boolean newValue) { + // intercepted by native peer + } + + public abstract Number parse(String source,ParsePosition pos); + + // ..and probably a lot missing + +} diff --git a/src/classes/java/text/SimpleDateFormat.java b/src/classes/java/text/SimpleDateFormat.java new file mode 100644 index 0000000..9598e36 --- /dev/null +++ b/src/classes/java/text/SimpleDateFormat.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.text; + +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + * (incomplete) model class for java.text.SimpleDate. See Format for details + * about the native formatter delegation + */ +public class SimpleDateFormat extends DateFormat { + + // see DecimalFormat comments why we use explicit init0()'s + + private native void init0(); + private native void init0(String pattern); + private native void init0(int timeStyle, int dateStyle); + + public SimpleDateFormat () { + init0(); + initializeCalendar(); + } + + public SimpleDateFormat (String pattern) { + if(pattern == null) { + throw new NullPointerException(); + } + init0(pattern); + initializeCalendar(); + } + + public SimpleDateFormat (String pattern, Locale locale) { + // <2do> bluntly ignoring locale for now + this(pattern); + } + + SimpleDateFormat (int timeStyle, int dateStyle, Locale locale){ + init0(timeStyle, dateStyle); + initializeCalendar(); + } + + // unfortunately we can't override the DateFormat.format(String) because + // it is final, and hence the compiler can do a INVOKE_SPECIAL + native String format0 (long dateTime); + + @Override + public StringBuffer format (Date date, StringBuffer sb, FieldPosition pos) { + String s = format0(date.getTime()); + sb.append(s); + + // we don't do FieldPositions yet + + return sb; + } + + + @Override + public Date parse (String arg0, ParsePosition arg1) { + // TODO Auto-generated method stub + return null; + } + + private void initializeCalendar() { + if (calendar == null) { + calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()); + } + } + + native public void applyPattern(String pattern); + +} diff --git a/src/classes/java/util/Random.java b/src/classes/java/util/Random.java new file mode 100644 index 0000000..ca52926 --- /dev/null +++ b/src/classes/java/util/Random.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util; + +public class Random { + + // the state of this object + private long seed; + + public Random(){ + // intercepted by native peer to control seed initialization based on JPF configuration + } + + public Random(long seed) { + // intercepted by native peer to control seed initialization based on JPF configuration + } + + public synchronized void setSeed(long seed){ + // intercepted by native peer + } + + protected int next(int bits){ + return 42; // intercepted by peer + } + + public void nextBytes(byte[] data){ + // intercepted by peer + } + + public int nextInt(){ + return 42; // intercepted by peer + } + + public int nextInt(int n) { + return 42; // intercepted by peer + } + + public long nextLong() { + return 42; // intercepted by peer + } + + public boolean nextBoolean() { + return true; // intercepted by peer + } + + public float nextFloat() { + return 42f; // intercepted by peer + } + + public double nextDouble() { + return 42.0; // intercepted by peer + } + + public synchronized double nextGaussian() { + return 42.0; // intercepted by peer + } +} diff --git a/src/classes/java/util/TimeZone.java b/src/classes/java/util/TimeZone.java new file mode 100644 index 0000000..890a78c --- /dev/null +++ b/src/classes/java/util/TimeZone.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.util; + +import java.io.Serializable; +import java.util.Date; + +/** + * a concrete TimeZone that forwards to the host VM. This is required to avoid Java version compatibility + * problems + * Note that we drop the abstract modifier + */ +public class TimeZone implements Serializable, Cloneable { + + private static final long serialVersionUID = 1L; + + private int rawOffset; + private String ID; + + private static TimeZone defaultZone; + + // public styles + public static final int SHORT = 0; + public static final int LONG = 1; + + // we keep construction on the peer side + private static native TimeZone createDefaultZone(); + + // both are always cloned + public static native TimeZone getTimeZone (String ID); + public static TimeZone getDefault() { + return (TimeZone) (getDefaultRef().clone()); + } + + // called internally (e.g. by java.util.Date) - no clone here + static TimeZone getDefaultRef(){ + if (defaultZone == null){ + defaultZone = createDefaultZone(); + } + + return defaultZone; + } + + // clone handles CloneNotSupportedException + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + public static void setDefault (TimeZone tz) { + if (tz == null){ // that's a reset according to the API docs + defaultZone = createDefaultZone(); + } else { + defaultZone = tz; + } + + setDefaultValues(defaultZone); // remember on the native side + } + private static native void setDefaultValues (TimeZone tz); + + public static native String[] getAvailableIDs(); + public static native String[] getAvailableIDs(int rawOffset); + + // the public TimeZone() constructor of the original class can only be called from the + // concrete derived classes we want to skip anyways + + public TimeZone (String ID){ + setID(ID); + } + + // this will set ID and rawOffset + public native void setID (String ID); + + public String getID (){ + return ID; + } + + public native int getOffset (int era, int year, int month, int day, int dayOfWeek, int milliseconds); + + public native int getOffset (long date); + + // this is not public in Java 1.7 + native int getOffsets (long date, int[] offsets); + + public int getRawOffset (){ + return rawOffset; + } + public void setRawOffset (int offsetMillis){ + rawOffset = offsetMillis; + } + + public boolean inDaylightTime (Date date) { + return inDaylightTime(date.getTime()); + } + private native boolean inDaylightTime (long time); + + + public native boolean useDaylightTime(); + + public native boolean observesDaylightTime(); + + public native int getDSTSavings(); + + public String getDisplayName(){ + // <2do> should use Locale.Category.DISPLAY in Java 1.7 + return getDisplayName( false, LONG, Locale.getDefault()); + } + public String getDisplayName (Locale locale) { + return getDisplayName( false, LONG, locale); + } + public String getDisplayName (boolean daylight, int style){ + return getDisplayName( daylight, style, Locale.getDefault()); + } + public native String getDisplayName (boolean daylight, int style, Locale locale); +} diff --git a/src/classes/java/util/concurrent/BrokenBarrierException.java b/src/classes/java/util/concurrent/BrokenBarrierException.java new file mode 100644 index 0000000..49ab036 --- /dev/null +++ b/src/classes/java/util/concurrent/BrokenBarrierException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.util.concurrent; + +@SuppressWarnings("serial") +public class BrokenBarrierException extends Exception { + + public BrokenBarrierException () { + } + + public BrokenBarrierException (String details) { + super(details); + } +} diff --git a/src/classes/java/util/concurrent/CyclicBarrier.java b/src/classes/java/util/concurrent/CyclicBarrier.java new file mode 100644 index 0000000..1995db0 --- /dev/null +++ b/src/classes/java/util/concurrent/CyclicBarrier.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.util.concurrent; + +/** + * a simplistic CyclicBarrier implementation, required because the real one + * relies heavily on Sun infrastructure (including native methods) + */ +public class CyclicBarrier { + + private Runnable action; + private int parties; + private int count; + private boolean isBroken; + + // make sure nobody from the outside can interfere with our locking + private final Object lock = new Object(); + + + public CyclicBarrier (int parties) { + this(parties, null); + } + + public CyclicBarrier (int parties, Runnable action) { + this.parties = parties; + count = parties; + + this.action = action; + } + + public int await () throws InterruptedException, BrokenBarrierException { + synchronized (lock) { + int arrival = parties - count; + + if (--count == 0) { + if (action != null) { + action.run(); + } + count = parties; // reset barrier + lock.notifyAll(); + } else { + try { + lock.wait(); + if (isBroken) { + throw new BrokenBarrierException(); + } + } catch (InterruptedException ix) { + if (count > 0) { + isBroken = true; + lock.notifyAll(); + } + + throw ix; + } + } + + return arrival; + } + } + + public int getParties () { + return parties; + } + + public void reset () { + synchronized (lock) { + if ((count != parties) && (count != 0)) { + // there are waiters + isBroken = true; + lock.notifyAll(); + } else { + count = parties; + isBroken = false; + } + } + } + + public boolean isBroken () { + // true if one of the parties got out of an await by being + // interrupted + return isBroken; + } + + public int getNumberWaiting () { + synchronized (lock) { + return (parties - count); + } + } +} diff --git a/src/classes/java/util/concurrent/Exchanger.java b/src/classes/java/util/concurrent/Exchanger.java new file mode 100644 index 0000000..03801d2 --- /dev/null +++ b/src/classes/java/util/concurrent/Exchanger.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent; + +/** + * model class for java.util.concurrent.Exchanger + * We model because the original class goes to great lengths implementing + * memory based synchronization, using execution time and spins + * + * Exchangers are also per se shared objects, so we want to minimize field + * access from bytecode + */ +public class Exchanger { + + // created on native side and pinned down until transaction is complete + static class Exchange { + Thread waiterThread; + boolean waiterTimedOut; + + T waiterData; + T responderData; + } + + //-- only accessed from native methods + private Exchange exchange; + + + public native V exchange(V value) throws InterruptedException; + + private native V exchange0 (V value, long timeoutMillis) throws InterruptedException, TimeoutException; + + // unfortunately we can't directly go native here without duplicating the TimeUnit conversion in the peer + public V exchange(V value, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { + long to = unit.convert(timeout,TimeUnit.MILLISECONDS); + return exchange0( value, to); + } +} diff --git a/src/classes/java/util/concurrent/atomic/AtomicIntegerArray.java b/src/classes/java/util/concurrent/atomic/AtomicIntegerArray.java new file mode 100644 index 0000000..fcc2125 --- /dev/null +++ b/src/classes/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * model class for AtomicIntegerArray + */ +public class AtomicIntegerArray implements Serializable { + private static final long serialVersionUID = 2862133569453604235L; + + private final int[] array; + + public AtomicIntegerArray(int length) { + array = new int[length]; + // <2do> need a volatile write in order to conform to JMM // Does this really matter in JPF? + } + + public AtomicIntegerArray(int[] array) { + if (array == null) + throw new NullPointerException(); + + int length = array.length; + this.array = new int[length]; + + for (int i = 0; i < length; ++i) + this.array[i] = array[i]; + + // <2do> need a volatile write in order to conform to JMM // Does this really matter in JPF? + } + + public final int length() { + return(array.length); + } + + public final int get(int i) { + checkIndex(i); + return(getNative(i)); + } + + private final native int getNative(int i); + + public final boolean compareAndSet(int i, int expect, int update) { + checkIndex(i); + return(compareAndSetNative(i, expect, update)); + } + + private final native boolean compareAndSetNative(int i, int expect, int update); + + public final boolean weakCompareAndSet(int i, int expect, int update) { + return(compareAndSet(i, expect, update)); + } + + public final int getAndSet(int i, int newValue) { + while (true) { + int current = get(i); + if (compareAndSet(i, current, newValue)) + return(current); + } + } + + public final void set(int i, int newValue) { + getAndSet(i, newValue); + } + + public final void lazySet(int i, int newValue) { + set(i, newValue); + } + + public final int getAndIncrement(int i) { + return(getAndAdd(i, 1)); + } + + public final int getAndDecrement(int i) { + return(getAndAdd(i, -1)); + } + + public final int getAndAdd(int i, int delta) { + while (true) { + int current = get(i); + int next = current + delta; + if (compareAndSet(i, current, next)) + return(current); + } + } + + public final int incrementAndGet(int i) { + return(getAndIncrement(i) + 1); + } + + public final int decrementAndGet(int i) { + return(getAndDecrement(i) - 1); + } + + public final int addAndGet(int i, int delta) { + return(getAndAdd(i, delta) + delta); + } + + @Override + public String toString() { + // <2do> need a volatile read in order to conform to JMM // Does this really matter in JPF? + return(Arrays.toString(array)); + } + + private void checkIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + } +} diff --git a/src/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/src/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java new file mode 100644 index 0000000..4c5725e --- /dev/null +++ b/src/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +/** + * model class for the AtomicIntegerFieldUpdater + * in reality it's an abstract class, but this here is merely a stub anyways + */ +public class AtomicIntegerFieldUpdater { + + int fieldId; + + public static AtomicIntegerFieldUpdater newUpdater (Class objClass, String fieldName) { + return new AtomicIntegerFieldUpdater(objClass, fieldName); + } + + protected AtomicIntegerFieldUpdater(Class objClass, String fieldName){ + // direct Object subclass, so we can directly intercept the ctor + // w/o having to call a parent ctor + } + + public native boolean compareAndSet(T obj, int expect, int update); + public native int get(T obj); + public native int getAndAdd(T obj, int delta); + public native int getAndSet(T obj, int newValue); + public native void lazySet(T obj, int newValue); + public native void set(T obj, int newValue); + public native boolean weakCompareAndSet(T obj, int expect, int update); + + public int addAndGet(T obj, int delta) {return(getAndAdd(obj, delta) + delta);} + public int decrementAndGet(T obj) {return(addAndGet(obj, -1));} + public int getAndDecrement(T obj) {return(getAndAdd(obj, -1));} + public int getAndIncrement(T obj) {return(getAndAdd(obj, 1));} + public int incrementAndGet(T obj) {return(addAndGet(obj, 1));} +} diff --git a/src/classes/java/util/concurrent/atomic/AtomicLongArray.java b/src/classes/java/util/concurrent/atomic/AtomicLongArray.java new file mode 100644 index 0000000..1df393d --- /dev/null +++ b/src/classes/java/util/concurrent/atomic/AtomicLongArray.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * model class for AtomicLongArray + */ +public class AtomicLongArray implements Serializable { + private static final long serialVersionUID = -2308431214976778248L; + + private final long[] array; + + public AtomicLongArray(int length) { + array = new long[length]; + // <2do> need a volatile write in order to conform to JMM // Does this really matter in JPF? + } + + public AtomicLongArray(long[] array) { + if (array == null) + throw new NullPointerException(); + + int length = array.length; + this.array = new long[length]; + + for (int i = 0; i < length; ++i) + this.array[i] = array[i]; + + // <2do> need a volatile write in order to conform to JMM // Does this really matter in JPF? + } + + public final int length() { + return(array.length); + } + + public final long get(int i) { + checkIndex(i); + return(getNative(i)); + } + + private final native long getNative(int i); + + public final boolean compareAndSet(int i, long expect, long update) { + checkIndex(i); + return(compareAndSetNative(i, expect, update)); + } + + private final native boolean compareAndSetNative(int i, long expect, long update); + + public final boolean weakCompareAndSet(int i, long expect, long update) { + return(compareAndSet(i, expect, update)); + } + + public final long getAndSet(int i, long newValue) { + while (true) { + long current = get(i); + if (compareAndSet(i, current, newValue)) + return(current); + } + } + + public final void set(int i, long newValue) { + getAndSet(i, newValue); + } + + public final void lazySet(int i, long newValue) { + set(i, newValue); + } + + public final long getAndIncrement(int i) { + return(getAndAdd(i, 1)); + } + + public final long getAndDecrement(int i) { + return(getAndAdd(i, -1)); + } + + public final long getAndAdd(int i, long delta) { + while (true) { + long current = get(i); + long next = current + delta; + if (compareAndSet(i, current, next)) + return(current); + } + } + + public final long incrementAndGet(int i) { + return(getAndIncrement(i) + 1); + } + + public final long decrementAndGet(int i) { + return(getAndDecrement(i) - 1); + } + + public final long addAndGet(int i, long delta) { + return(getAndAdd(i, delta) + delta); + } + + @Override + public String toString() { + // <2do> need a volatile read in order to conform to JMM // Does this really matter in JPF? + return(Arrays.toString(array)); + } + + private void checkIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + } +} diff --git a/src/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/src/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java new file mode 100644 index 0000000..aa2534d --- /dev/null +++ b/src/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +/** + * model class for the AtomicLongFieldUpdater + * in reality it's an abstract class, but this here is merely a stub anyways + */ +public class AtomicLongFieldUpdater { + + int fieldId; + + public static AtomicLongFieldUpdater newUpdater (Class objClass, String fieldName) { + return new AtomicLongFieldUpdater(objClass, fieldName); + } + + protected AtomicLongFieldUpdater(Class objClass, String fieldName){ + // direct Object subclass, so we can directly intercept the ctor + // w/o having to call a parent ctor + } + + public native boolean compareAndSet(T obj, long expect, long update); + public native long get(T obj); + public native long getAndAdd(T obj, long delta); + public native long getAndSet(T obj, long newValue); + public native void lazySet(T obj, long newValue); + public native void set(T obj, long newValue); + public native boolean weakCompareAndSet(T obj, long expect, long update); + + public long addAndGet(T obj, long delta) {return(getAndAdd(obj, delta) + delta);} + public long decrementAndGet(T obj) {return(addAndGet(obj, -1));} + public long getAndDecrement(T obj) {return(getAndAdd(obj, -1));} + public long getAndIncrement(T obj) {return(getAndAdd(obj, 1));} + public long incrementAndGet(T obj) {return(addAndGet(obj, 1));} +} diff --git a/src/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/src/classes/java/util/concurrent/atomic/AtomicReferenceArray.java new file mode 100644 index 0000000..6ae4b07 --- /dev/null +++ b/src/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * model class for AtomicReferenceArray + */ +public class AtomicReferenceArray implements Serializable { + private static final long serialVersionUID = -6209656149925076980L; + + private final Object[] array; + + public AtomicReferenceArray(int length) { + array = new Object[length]; + // <2do> need a volatile write in order to conform to JMM // Does this really matter in JPF? + } + + public AtomicReferenceArray(E[] array) { + if (array == null) + throw new NullPointerException(); + + int length = array.length; + this.array = new Object[length]; + + for (int i = 0; i < length; ++i) + this.array[i] = array[i]; + + // <2do> need a volatile write in order to conform to JMM // Does this really matter in JPF? + } + + public final int length() { + return(array.length); + } + + public final E get(int i) { + checkIndex(i); + return(getNative(i)); + } + + private final native E getNative(int i); + + public final boolean compareAndSet(int i, E expect, E update) { + checkIndex(i); + return(compareAndSetNative(i, expect, update)); + } + + private final native boolean compareAndSetNative(int i, E expect, E update); + + public final boolean weakCompareAndSet(int i, E expect, E update) { + return(compareAndSet(i, expect, update)); + } + + public final E getAndSet(int i, E newValue) { + while (true) { + E current = get(i); + if (compareAndSet(i, current, newValue)) + return(current); + } + } + + public final void set(int i, E newValue) { + getAndSet(i, newValue); + } + + public final void lazySet(int i, E newValue) { + set(i, newValue); + } + + @Override + public String toString() { + // <2do> need a volatile read in order to conform to JMM // Does this really matter in JPF? + return(Arrays.toString(array)); + } + + private void checkIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + } +} diff --git a/src/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java new file mode 100644 index 0000000..845ea46 --- /dev/null +++ b/src/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.concurrent.atomic; + +/** + * model class for the AtomicReferenceFieldUpdater + * in reality it's an abstract class, but this here is merely a stub anyways + */ +public class AtomicReferenceFieldUpdater { + + int fieldId; + + public static AtomicReferenceFieldUpdater newUpdater (Class objClass, Class fieldClass, + String fieldName) { + return new AtomicReferenceFieldUpdater(objClass, fieldClass, fieldName); + } + + protected AtomicReferenceFieldUpdater(Class objClass, Class fieldClass, String fieldName){ + // direct Object subclass, so we can directly intercept the ctor + // w/o having to call a parent ctor + } + + public native boolean compareAndSet(T obj, V expect, V update); + public native V get(T obj); + public native V getAndSet(T obj, V newValue); + public native void lazySet(T obj, V newValue); + public native void set(T obj, V newValue); + public native boolean weakCompareAndSet(T obj, V expect, V update); +} diff --git a/src/classes/java/util/function/Supplier.java b/src/classes/java/util/function/Supplier.java new file mode 100644 index 0000000..e885b3e --- /dev/null +++ b/src/classes/java/util/function/Supplier.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.util.function; + +/** + * Java7 doesn't have it, but we need it to model ThreadLocal + */ +public interface Supplier { + T get(); +} diff --git a/src/classes/java/util/logging/FileHandler.java b/src/classes/java/util/logging/FileHandler.java new file mode 100644 index 0000000..7f60e80 --- /dev/null +++ b/src/classes/java/util/logging/FileHandler.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.logging; + +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * simple stub to avoid execptions when using basic logging + */ +public class FileHandler extends StreamHandler { + public FileHandler() throws IOException { + this("log.log"); + } + + public FileHandler(String pattern) throws IOException { + super(); + setOutputStream(new FileOutputStream(pattern)); + } +} diff --git a/src/classes/java/util/regex/Matcher.java b/src/classes/java/util/regex/Matcher.java new file mode 100644 index 0000000..8b1aac4 --- /dev/null +++ b/src/classes/java/util/regex/Matcher.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.regex; + +/** + * model of a regular expression matcher, to save memory and execution time + */ +public class Matcher { + + // this is the same trick like java.text.Format - avoiding a native + // memory leak by means of overwriting a JPF state tracked index value + // (well, it's still a leak since it never gets recycled unless we add a + // finalizer, but it should be much less serious) + static int nInstances; + private int id = nInstances++; // just for peer implementation purposes + + Pattern pattern; + String input; // that's an approximation (don't use CharSequence on the native side) + + Matcher() { + } + + Matcher (Pattern pattern, CharSequence inp){ + this.pattern = pattern; + this.input = inp.toString(); + + register(); + } + + public Pattern pattern() { + return pattern; + } + + native void register(); + + public native Matcher reset(); + + public String group() { + return group(0); + } + + public native String group(int group); + + public native int groupCount(); + + public Matcher reset(CharSequence inp) { + this.input = inp.toString(); + return reset(); + } + + public native boolean matches(); + + public native boolean find(); + + public native boolean lookingAt(); + + public int start() { + return start(0); + } + + public native int start(int group); + + public int end() { + return end(0); + } + + public native int end(int group); + + public native boolean hasTransparentBounds(); + + public native Matcher useTransparentBounds(boolean b); + + public native boolean hasAnchoringBounds(); + + public native Matcher useAnchoringBounds(boolean b); + + public native int regionStart(); + + public native int regionEnd(); + + public native Matcher region(int start, int end); + + public static native String quoteReplacement(String abc); + + public native String replaceAll(String replacement); + + public native String replaceFirst(String replacement); + + @Override + public native String toString(); + + public native boolean hitEnd(); + + public native boolean requireEnd(); + + // TODO public native MatchResult toMatchResult(); + // TODO public native StringBuffer appendTail(StringBuffer sb); + // TODO public native Matcher appendReplacement(StringBuffer sb, String replacement); +} diff --git a/src/classes/java/util/regex/Pattern.java b/src/classes/java/util/regex/Pattern.java new file mode 100644 index 0000000..7f00c44 --- /dev/null +++ b/src/classes/java/util/regex/Pattern.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util.regex; + +/** + * simplified model of java.util.refex.Pattern, which otherwise + * is very expensive in terms of state memory and execution costs + */ +public class Pattern { + + String regex; + int flags; + + public static Pattern compile (String regex) { + return new Pattern(regex, 0); + } + + public static Pattern compile (String regex, int flags){ + return new Pattern(regex, flags); + } + + private Pattern (String regex, int flags){ + this.regex = regex; + this.flags = flags; + } + + public Matcher matcher (CharSequence input){ + return new Matcher(this, input); + } + + public String pattern() { + return regex; + } + + public String[] split (CharSequence input){ + return split(input,0); + } + + public String[] split (CharSequence input, int limit){ + return split0(input.toString(), limit); // just to avoid the CharSequence charAt() hassle on the native side + } + + private native String[] split0(String input, int limit); + + @Override + public String toString() { + return regex; + } +} diff --git a/src/classes/org/junit/After.java b/src/classes/org/junit/After.java new file mode 100644 index 0000000..11b8e18 --- /dev/null +++ b/src/classes/org/junit/After.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * same as org.junit.Test - we don't want to pull the whole of JUnit + * into our JPF classpath just because we run TestJPF derived classes + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface After { + // nothing in here +} diff --git a/src/classes/org/junit/AfterClass.java b/src/classes/org/junit/AfterClass.java new file mode 100644 index 0000000..bd2fee0 --- /dev/null +++ b/src/classes/org/junit/AfterClass.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * same as org.junit.Test - we don't want to pull the whole of JUnit + * into our JPF classpath just because we run TestJPF derived classes + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterClass { + // nothing in here +} diff --git a/src/classes/org/junit/Before.java b/src/classes/org/junit/Before.java new file mode 100644 index 0000000..de2678b --- /dev/null +++ b/src/classes/org/junit/Before.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * same as org.junit.Test - we don't want to pull the whole of JUnit + * into our JPF classpath just because we run TestJPF derived classes + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Before { + // nothing in here +} diff --git a/src/classes/org/junit/BeforeClass.java b/src/classes/org/junit/BeforeClass.java new file mode 100644 index 0000000..c689a10 --- /dev/null +++ b/src/classes/org/junit/BeforeClass.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * same as org.junit.Test - we don't want to pull the whole of JUnit + * into our JPF classpath just because we run TestJPF derived classes + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeClass { + // nothing in here +} \ No newline at end of file diff --git a/src/classes/org/junit/Ignore.java b/src/classes/org/junit/Ignore.java new file mode 100644 index 0000000..c89ebda --- /dev/null +++ b/src/classes/org/junit/Ignore.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * same as org.junit.Test - we don't want to pull the whole of JUnit + * into our JPF classpath just because we run TestJPF derived classes + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Ignore { + String value() default ""; +} diff --git a/src/classes/org/junit/Test.java b/src/classes/org/junit/Test.java new file mode 100644 index 0000000..5275269 --- /dev/null +++ b/src/classes/org/junit/Test.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * this annotation type is shamelessly lifted from JUnit. + * + * The only reason it is here is that we don't want to pull the whole of JUnit into + * our 'classpath' when executing TestJPF classes under JPF, just because some of + * the test SUT methods have a @Test annotation. + * + * Lifting/masking classes in general is not a good practice, but it seems to + * be the lesser of two evils in this case, given that we really don't need + * anything but just the simple annotation type. + * + * NOTE - this might be different if we execute junit under JPF, which is the + * reason why we include the @Test features here. However - this assumes that @Test + * is such a basic JUnit type that it won't change + */ + +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Test { + + static class None extends Throwable { + private static final long serialVersionUID= 1L; + private None() {} + } + + Class expected() default None.class; + + long timeout() default 0L; +} diff --git a/src/classes/sun/misc/AtomicLong.java b/src/classes/sun/misc/AtomicLong.java new file mode 100644 index 0000000..cf3e430 --- /dev/null +++ b/src/classes/sun/misc/AtomicLong.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sun.misc; + +/** + * MJI model class for sun.misc.AtomicLong library abstraction + */ +public class AtomicLong { + long value; + + public AtomicLong () { + } + + private AtomicLong (long val) { + value = val; + } + + public static AtomicLong newAtomicLong (long val) { + return new AtomicLong(val); + } + + public boolean attemptAdd (long l) { + value += l; + + return true; + } + + public boolean attemptIncrememt () { + value++; + + return true; + } + + public boolean attemptSet (long val) { + value = val; + + return true; + } + + public boolean attemptUpdate (long fallback, long newval) { + value = newval; + + return true; + } + + public long get () { + return value; + } + + @SuppressWarnings("unused") + private static boolean VMSupportsCS8 () { + // whatever it means + return false; + } +} diff --git a/src/classes/sun/misc/JavaAWTAccess.java b/src/classes/sun/misc/JavaAWTAccess.java new file mode 100644 index 0000000..84a44ee --- /dev/null +++ b/src/classes/sun/misc/JavaAWTAccess.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.misc; + +/** + * same as the others - we need to model it in case somebody uses Java 5, + * or an earlier Java 6 version on OS X + */ +public interface JavaAWTAccess { + + // don't know about these yet + public Object get(); + public void put(Object k, Object v); + public void remove(Object k); + + public boolean isDisposed(); + public boolean isMainAppContext(); + +} diff --git a/src/classes/sun/misc/JavaIOAccess.java b/src/classes/sun/misc/JavaIOAccess.java new file mode 100644 index 0000000..89c7fec --- /dev/null +++ b/src/classes/sun/misc/JavaIOAccess.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.misc; + +//import java.io.Console; +import java.nio.charset.Charset; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.msic.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ +public interface JavaIOAccess { + //public Console console(); // not in Java 1.5, so we skip for now + public Runnable consoleRestoreHook(); + public Charset charset(); +} diff --git a/src/classes/sun/misc/JavaIODeleteOnExitAccess.java b/src/classes/sun/misc/JavaIODeleteOnExitAccess.java new file mode 100644 index 0000000..931ac84 --- /dev/null +++ b/src/classes/sun/misc/JavaIODeleteOnExitAccess.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.misc; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.msic.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ +public interface JavaIODeleteOnExitAccess extends Runnable { + @Override + public void run(); +} diff --git a/src/classes/sun/misc/JavaIOFileDescriptorAccess.java b/src/classes/sun/misc/JavaIOFileDescriptorAccess.java new file mode 100644 index 0000000..f1ee8c4 --- /dev/null +++ b/src/classes/sun/misc/JavaIOFileDescriptorAccess.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.misc; + +import java.io.FileDescriptor; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.msic.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ + +public interface JavaIOFileDescriptorAccess { + public void set(FileDescriptor fdObj, int fd); + public int get(FileDescriptor fdObj); + public void setHandle(FileDescriptor fdObj, long h); + public long getHandle(FileDescriptor fdObj); +} diff --git a/src/classes/sun/misc/JavaLangAccess.java b/src/classes/sun/misc/JavaLangAccess.java new file mode 100644 index 0000000..8ec78e5 --- /dev/null +++ b/src/classes/sun/misc/JavaLangAccess.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.misc; + +import sun.nio.ch.Interruptible; +import sun.reflect.ConstantPool; +import sun.reflect.annotation.AnnotationType; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.misc.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ + +public interface JavaLangAccess { + + ConstantPool getConstantPool(Class klass); + + void setAnnotationType(Class klass, AnnotationType annotationType); + + AnnotationType getAnnotationType(Class klass); + + > E[] getEnumConstantsShared(Class klass); + + void blockedOn(Thread t, Interruptible b); + + void registerShutdownHook(int slot, Runnable r); + + int getStackTraceDepth(Throwable t); + + StackTraceElement getStackTraceElement(Throwable t, int i); +} diff --git a/src/classes/sun/misc/JavaNetAccess.java b/src/classes/sun/misc/JavaNetAccess.java new file mode 100644 index 0000000..7cb92cd --- /dev/null +++ b/src/classes/sun/misc/JavaNetAccess.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.misc; + +import java.net.URLClassLoader; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.msic.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ +public interface JavaNetAccess { + URLClassPath getURLClassPath (URLClassLoader ucl); +} diff --git a/src/classes/sun/misc/JavaNioAccess.java b/src/classes/sun/misc/JavaNioAccess.java new file mode 100644 index 0000000..67e4ecd --- /dev/null +++ b/src/classes/sun/misc/JavaNioAccess.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sun.misc; + +/** + * <2do> this is not supported yet + */ +public interface JavaNioAccess { + + interface BufferPool { + String getName(); + long getCount(); + long getTotalCapacity(); + long getMemoryUsed(); + } + + BufferPool getDirectBufferPool(); +} diff --git a/src/classes/sun/misc/SharedSecrets.java b/src/classes/sun/misc/SharedSecrets.java new file mode 100644 index 0000000..c74ff4a --- /dev/null +++ b/src/classes/sun/misc/SharedSecrets.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sun.misc; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.ObjectInputStream; +import java.util.jar.JarFile; + +/** + * This is a backdoor mechanism in Java 6 to allow (some sort of) + * controlled access to internals between packages, using + * sun.misc.* interfaces (e.g. JavaLangAccess) that are anonymously + * instantiated within the exporting package (e.g. java.lang), and + * obtained via SharedSecrets, which in turn obtains the + * instances from sun.misc.Unsafe. For most packages these interface + * objects are created on demand by static init of some key classes of + * these packages that call the SharedSecrets setters + * (except for JavaLangAccess and JavaNetAccess) + * + * Since this is used from within the standard libraries of Java 6, we need + * some sort of support, but we don't want to break Java 1.5 yet by introducing + * lots of Java 6 dependencies, which would force us to duplicate their code + * even though it might be pure Java (like java.io.Console). + * + * This is a can of worms, which we only open partially to support + * EnumSets for both Java 1.5 and 6. We make the cut at java.* packages - + * if the backdoor interfaces/types require anything outside sun.* packages, + * we leave it out. + * + * All of this is hopefully going away when we drop Java 1.5 support, and is + * to be replaced by some native peers providing the required native calls + */ +public class SharedSecrets { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private static JavaUtilJarAccess javaUtilJarAccess; + private static JavaLangAccess javaLangAccess; + private static JavaIOAccess javaIOAccess; + private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess; + private static JavaNetAccess javaNetAccess; + private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; + private static JavaNioAccess javaNioAccess; + private static JavaAWTAccess javaAWTAccess; + private static JavaOISAccess javaOISAccess; + private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; + + // (required for EnumSet ops) + public static JavaLangAccess getJavaLangAccess() { + return javaLangAccess; + } + // automatically called by java.lang.System clinit + public static void setJavaLangAccess(JavaLangAccess jla) { + javaLangAccess = jla; + } + + + public static void setJavaNetAccess(JavaNetAccess jna) { + javaNetAccess = jna; + } + // automatically called by java.net.URLClassLoader clinit + public static JavaNetAccess getJavaNetAccess() { + return javaNetAccess; + } + + + public static JavaUtilJarAccess javaUtilJarAccess() { + if (javaUtilJarAccess == null) { + unsafe.ensureClassInitialized(JarFile.class); + } + return javaUtilJarAccess; + } + public static void setJavaUtilJarAccess(JavaUtilJarAccess access) { + javaUtilJarAccess = access; + } + + + public static void setJavaIOAccess(JavaIOAccess jia) { + javaIOAccess = jia; + } + // this is normally done by java.io.Console, which is not in Java 1.5 + // since this is a rather big beast with lost of bytecode, we don't add + // this for now + public static JavaIOAccess getJavaIOAccess() { + if (javaIOAccess == null) { + //unsafe.ensureClassInitialized(Console.class); + throw new UnsupportedOperationException("sun.misc.SharedSecrets.getJavaIOAccess() not supported yet"); + } + return javaIOAccess; + } + + + public static void setJavaNioAccess(JavaNioAccess a) { + javaNioAccess = a; + } + public static JavaNioAccess getJavaNioAccess() { + if (javaNioAccess == null) { + throw new UnsupportedOperationException("sun.misc.SharedSecrets.getJavaNioAccess() not supported yet"); + } + return javaNioAccess; + } + + + public static void setJavaIODeleteOnExitAccess(JavaIODeleteOnExitAccess jida) { + javaIODeleteOnExitAccess = jida; + } + + public static JavaIODeleteOnExitAccess getJavaIODeleteOnExitAccess() { + if (javaIODeleteOnExitAccess == null) { + unsafe.ensureClassInitialized(File.class); + } + return javaIODeleteOnExitAccess; + } + + public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) { + javaIOFileDescriptorAccess = jiofda; + } + public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() { + if (javaIOFileDescriptorAccess == null) { + unsafe.ensureClassInitialized(FileDescriptor.class); + throw new UnsupportedOperationException("sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess() not supported yet"); + } + + return javaIOFileDescriptorAccess; + } + + public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { + if (javaObjectInputStreamAccess == null) { + unsafe.ensureClassInitialized(ObjectInputStream.class); + throw new UnsupportedOperationException("sun.misc.SharedSecrets.getJavaObjectInputStreamAccess() not supported yet"); + } + + return javaObjectInputStreamAccess; + } + + public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) { + javaObjectInputStreamAccess = access; + } + + public static void setJavaAWTAccess (JavaAWTAccess jaa){ + javaAWTAccess = jaa; + } + public static JavaAWTAccess getJavaAWTAccess(){ + return javaAWTAccess; + } + + public static void setJavaOISAccess(JavaOISAccess access) { + javaOISAccess = access; + } + + public static JavaOISAccess getJavaOISAccess() { + if (javaOISAccess == null) { + unsafe.ensureClassInitialized(ObjectInputStream.class); + throw new UnsupportedOperationException("sun.misc.SharedSecrets.getJavaOISAccess() not supported yet"); + } + + return javaOISAccess; + } +} diff --git a/src/classes/sun/misc/Unsafe.java b/src/classes/sun/misc/Unsafe.java new file mode 100644 index 0000000..e024ab7 --- /dev/null +++ b/src/classes/sun/misc/Unsafe.java @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sun.misc; + +import java.lang.reflect.Field; + +/** + * Unsafe = unwanted. See comments in the native peer. We only have it because + * it is required by java.util.concurrent. + * + * Note that in the real world, this class is only callable from the system library, + * not application code + */ + +public class Unsafe { + private static final Unsafe theUnsafe = new Unsafe(); + + public static final int INVALID_FIELD_OFFSET = -1; + + public static Unsafe getUnsafe() { + return theUnsafe; + //return new Unsafe(); + } + + // field offsets are completely useless between VMs, we just return + // a numeric id for the corresponding FieldInfo here + public native int fieldOffset (Field f); + public native long objectFieldOffset (Field f); + + // those do the usual CAS magic + public native boolean compareAndSwapObject (Object oThis, long offset, Object expect, Object update); + public native boolean compareAndSwapInt (Object oThis, long offset, int expect, int update); + public native boolean compareAndSwapLong (Object oThis, long offset, long expect, long update); + + // that looks like some atomic conditional wait + public native void park (boolean isAbsolute, long timeout); + public native void unpark (Object thread); + + // various accessors + public native int getInt(Object obj, long l); + public native int getIntVolatile(Object obj, long l); + + @Deprecated + public int getInt(Object obj, int offset) { + return getInt(obj, (long) offset); + } + + public native void putInt(Object obj, long l, int i); + public native void putIntVolatile(Object obj, long l, int i); + + @Deprecated + public void putInt(Object obj, int offset, int i) { + putInt(obj, (long) offset, i); + } + + public native void putOrderedInt(Object obj, long l, int i); + + public native Object getObject(Object obj, long l); + public native Object getObjectVolatile(Object obj, long l); + + @Deprecated + public Object getObject(Object obj, int offset) { + return getObject(obj, (long) offset); + } + + public native void putObject(Object obj, long l, Object obj1); + public native void putObjectVolatile(Object obj, long l, Object obj1); + + + @Deprecated + public void putObject(Object obj, int offset, Object obj1) { + putObject(obj, (long) offset, obj1); + } + + public native void putOrderedObject(Object obj, long l, Object obj1); + + public native boolean getBoolean(Object obj, long l); + public native boolean getBooleanVolatile(Object obj, long l); + + @Deprecated + public boolean getBoolean(Object obj, int offset) { + return getBoolean(obj, (long) offset); + } + + public native void putBoolean(Object obj, long l, boolean flag); + public native void putBooleanVolatile(Object obj, long l, boolean flag); + + @Deprecated + public void putBoolean(Object obj, int offset, boolean flag) { + putBoolean(obj, (long) offset, flag); + } + + public native byte getByte(Object obj, long l); + public native byte getByteVolatile(Object obj, long l); + + @Deprecated + public byte getByte(Object obj, int offset) { + return getByte(obj, (long) offset); + } + + public native void putByte(Object obj, long l, byte byte0); + public native void putByteVolatile(Object obj, long l, byte byte0); + + @Deprecated + public void putByte(Object obj, int offset, byte byte0) { + putByte(obj, (long) offset, byte0); + } + + public native short getShort(Object obj, long l); + public native short getShortVolatile(Object obj, long l); + + @Deprecated + public short getShort(Object obj, int offset) { + return getShort(obj, (long) offset); + } + + public native void putShort(Object obj, long l, short word0); + public native void putShortVolatile(Object obj, long l, short word0); + + @Deprecated + public void putShort(Object obj, int offset, short word0) { + putShort(obj, (long) offset, word0); + } + + public native char getChar(Object obj, long l); + public native char getCharVolatile(Object obj, long l); + + @Deprecated + public char getChar(Object obj, int offset) { + return getChar(obj, (long) offset); + } + + public native void putChar(Object obj, long l, char c); + public native void putCharVolatile(Object obj, long l, char c); + + @Deprecated + public void putChar(Object obj, int offset, char c) { + putChar(obj, (long) offset, c); + } + + public native long getLong(Object obj, long l); + public native long getLongVolatile(Object obj, long l); + + @Deprecated + public long getLong(Object obj, int offset) { + return getLong(obj, (long) offset); + } + + public native void putLong(Object obj, long l, long l1); + public native void putLongVolatile(Object obj, long l, long l1); + + public native void putOrderedLong(Object obj, long l, long l1); + + @Deprecated + public void putLong(Object obj, int offset, long l1) { + putLong(obj, (long) offset, l1); + } + + public native float getFloat(Object obj, long l); + public native float getFloatVolatile(Object obj, long l); + + @Deprecated + public float getFloat(Object obj, int offset) { + return getFloat(obj, (long) offset); + } + + public native void putFloat(Object obj, long l, float f); + public native void putFloatVolatile(Object obj, long l, float f); + + @Deprecated + public void putFloat(Object obj, int offset, float f) { + putFloat(obj, (long) offset, f); + } + + public native double getDouble(Object obj, long l); + public native double getDoubleVolatile(Object obj, long l); + + @Deprecated + public double getDouble(Object obj, int offset) { + return getDouble(obj, (long) offset); + } + + public native void putDouble(Object obj, long l, double d); + public native void putDoubleVolatile(Object obj, long l, double d); + + @Deprecated + public void putDouble(Object obj, int offset, double d) { + putDouble(obj, (long) offset, d); + } + + public native void ensureClassInitialized(Class cls); + + public native int arrayBaseOffset(Class clazz); + + public native int arrayIndexScale(Class clazz); + + + //--- java.nio finally breaks object boundaries - hello, evil pointer arithmetic + + /** + * this is really a byte[] allocation (used by java.nio.Bits). Note that + * object has to be explicitly freed with freeMemory() (yikes!) + */ + public native long allocateMemory (long bytes); + + /** + * to be used to free allocateMemory() allocated array objects + */ + public native void freeMemory (long byteArrayRef); + + /** + * byte access of allocateMemory() objects. Note that 'address' has + * to point into such an object + */ + public native byte getByte (long address); + public native void putByte (long address, byte val); + + public native char getChar (long address); + public native void putChar (long address, char val); + + public native int getInt (long address); + public native void putInt (long address, int val); + + public native long getLong (long address); + public native void putLong (long address, long val); + + public native float getFloat (long address); + public native void putFloat (long address, float val); + + public native double getDouble (long address); + public native void putDouble (long address, double val); + +} diff --git a/src/classes/sun/net/www/protocol/http/Handler.java b/src/classes/sun/net/www/protocol/http/Handler.java new file mode 100644 index 0000000..3b717be --- /dev/null +++ b/src/classes/sun/net/www/protocol/http/Handler.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sun.net.www.protocol.http; + +import gov.nasa.jpf.CachedROHttpConnection; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.Proxy; +import java.net.URL; + +/** + * replaced handler to support configured URLConnection classes + */ +public class Handler extends java.net.URLStreamHandler { + + protected String proxy; + protected int proxyPort; + + public Handler() { + proxy = null; + proxyPort = -1; + } + + public Handler(String proxy, int port) { + this.proxy = proxy; + this.proxyPort = port; + } + + @Override + protected int getDefaultPort() { + return 80; + } + + + static Class[] argTypes = { URL.class, Proxy.class }; + private native Class getConnectionClass(String url); + + + @Override + protected java.net.URLConnection openConnection (URL u, Proxy p) throws IOException { + + Class clazz = getConnectionClass(u.toString()); + + if (clazz != null){ + try { + Constructor ctor = clazz.getConstructor(argTypes); + return ctor.newInstance(u, p); + + } catch (NoSuchMethodException nmx){ + throw new IOException("connection class has no suitabe ctor: " + clazz.getName()); + } catch (IllegalAccessException iax){ + throw new IOException("connection class has no public ctor: " + clazz.getName()); + } catch (InvocationTargetException itx){ + throw new IOException("exception initializing URLConnection", itx); + } catch (InstantiationException ix){ + throw new IOException("connection class cannot be instantiated: " + clazz.getName()); + } + + } else { + // we just go with the standard thing, hoping that we have a modeled Socket layer + return new CachedROHttpConnection(u, p, this); + } + } + + @Override + protected java.net.URLConnection openConnection(URL u) throws IOException { + return openConnection(u, null); + } + + //... and a lot of methods still missing +} diff --git a/src/classes/sun/nio/ch/Interruptible.java b/src/classes/sun/nio/ch/Interruptible.java new file mode 100644 index 0000000..a253c27 --- /dev/null +++ b/src/classes/sun/nio/ch/Interruptible.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.nio.ch; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.msic.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ + +public interface Interruptible { + public void interrupt(); +} diff --git a/src/classes/sun/reflect/ConstantPool.java b/src/classes/sun/reflect/ConstantPool.java new file mode 100644 index 0000000..e871f69 --- /dev/null +++ b/src/classes/sun/reflect/ConstantPool.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.reflect; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * see sun.msic.SharedSecrets for details + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + * (to be replaced with a native peer for the native methods of the lib class) + */ +public class ConstantPool { + + public int getSize() { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public Class getClassAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public Class getClassAtIfLoaded(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public Member getMethodAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public Member getMethodAtIfLoaded(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public Field getFieldAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public Field getFieldAtIfLoaded(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public String[] getMemberRefInfoAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public int getIntAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public long getLongAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public float getFloatAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public double getDoubleAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public String getStringAt(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + + public String getUTF8At(int index) { + throw new UnsupportedOperationException("sun.reflect.ConstantPool not supported yet"); + } + +} diff --git a/src/classes/sun/reflect/annotation/AnnotationType.java b/src/classes/sun/reflect/annotation/AnnotationType.java new file mode 100644 index 0000000..77a2630 --- /dev/null +++ b/src/classes/sun/reflect/annotation/AnnotationType.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sun.reflect.annotation; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import sun.misc.SharedSecrets; + +/** + * this is a placeholder for a Java 6 class, which we only have here to + * support both Java 1.5 and 6 with the same set of env/ classes + * + * this is Java only, so it's a drag we have to add this, but since it is outside + * java.* and doesn't refer to Java 6 stuff outside the sun.misc.SharedSecrets + * we bite the bullet and add it (for now) + * + * <2do> THIS IS GOING AWAY AS SOON AS WE OFFICIALLY SWITCH TO JAVA 6 + */ +public class AnnotationType { + + private RetentionPolicy retention = RetentionPolicy.RUNTIME; + private boolean inherited = false; + + // caches + private final Map> memberTypes = new HashMap>(); + private final Map memberDefaults = new HashMap(); + private final Map members = new HashMap(); + + + public static synchronized AnnotationType getInstance (Class annotationClass) { + AnnotationType at = SharedSecrets.getJavaLangAccess().getAnnotationType(annotationClass); + if (at == null) { + at = new AnnotationType(annotationClass); + } + return at; + } + + private AnnotationType(final Class annoCls) { + if (!annoCls.isAnnotation()) { + throw new IllegalArgumentException("Not an annotation type"); + } + + Method[] methods = annoCls.getDeclaredMethods(); + + for (Method m : methods) { + if (m.getParameterTypes().length == 0) { + // cache name -> method assoc + String mname = m.getName(); + members.put(mname, m); + + // cache member type + Class type = m.getReturnType(); + memberTypes.put(mname, invocationHandlerReturnType(type)); + + // cache member default val (if any) + Object val = m.getDefaultValue(); + if (val != null) { + memberDefaults.put(mname, val); + } + } else { + // probably an exception + } + } + + if ((annoCls != Retention.class) && (annoCls != Inherited.class)) { // don't get recursive + inherited = annoCls.isAnnotationPresent(Inherited.class); + + Retention r = annoCls.getAnnotation(Retention.class); + if (r == null) { + retention = RetentionPolicy.CLASS; + } else { + retention = r.value(); + } + } + + SharedSecrets.getJavaLangAccess().setAnnotationType(annoCls, this); + } + + public static Class invocationHandlerReturnType (Class type) { + // return box types for builtins + if (type == boolean.class) { + return Boolean.class; + } else if (type == byte.class) { + return Byte.class; + } else if (type == char.class) { + return Character.class; + } else if (type == short.class) { + return Short.class; + } else if (type == int.class) { + return Integer.class; + } else if (type == long.class) { + return Long.class; + } else if (type == float.class) { + return Float.class; + } else if (type == double.class) { + return Double.class; + } else { + return type; + } + } + + public Map> memberTypes() { + return memberTypes; + } + + public Map members() { + return members; + } + + public Map memberDefaults() { + return memberDefaults; + } + + public RetentionPolicy retention() { + return retention; + } + + public boolean isInherited() { + return inherited; + } + +} diff --git a/src/examples/BoundedBuffer.java b/src/examples/BoundedBuffer.java new file mode 100644 index 0000000..985fbc1 --- /dev/null +++ b/src/examples/BoundedBuffer.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * concurrency example with deadlock + * adapted from "Concurrency: State Models & Java Programs", Jeff Magee & Jeff Kramer + * + * Note there need to be at least 2x buffer_size instances of either producers or + * consumers in order to produce the deadlock, which basically depends on + * a notification choice between a consumer and a producer in a context where + * only threads of the notifier type are still runnable + * + * This is a good benchmark for state management/matching in a small heap context. + * Higher numbers of buffer size and producers/consumers result in a nice + * state explosion + */ +public class BoundedBuffer { + + static int BUFFER_SIZE = 1; + static int N_PRODUCERS = 4; + static int N_CONSUMERS = 4; + + static Object DATA = "fortytwo"; + + //--- the bounded buffer implementation + protected Object[] buf; + protected int in = 0; + protected int out= 0; + protected int count= 0; + protected int size; + + public BoundedBuffer(int size) { + this.size = size; + buf = new Object[size]; + } + + public synchronized void put(Object o) throws InterruptedException { + while (count == size) { + wait(); + } + buf[in] = o; + //System.out.println("PUT from " + Thread.currentThread().getName()); + ++count; + in = (in + 1) % size; + notify(); // if this is not a notifyAll() we might notify the wrong waiter + } + + public synchronized Object get() throws InterruptedException { + while (count == 0) { + wait(); + } + Object o = buf[out]; + buf[out] = null; + //System.out.println("GET from " + Thread.currentThread().getName()); + --count; + out = (out + 1) % size; + notify(); // if this is not a notifyAll() we might notify the wrong waiter + return (o); + } + + //--- the producer + static class Producer extends Thread { + static int nProducers = 1; + BoundedBuffer buf; + + Producer(BoundedBuffer b) { + buf = b; + setName("P" + nProducers++); + } + + @Override + public void run() { + try { + while(true) { + // to ease state matching, we don't put different objects in the buffer + buf.put(DATA); + } + } catch (InterruptedException e){} + } + } + + //--- the consumer + static class Consumer extends Thread { + static int nConsumers = 1; + BoundedBuffer buf; + + Consumer(BoundedBuffer b) { + buf = b; + setName( "C" + nConsumers++); + } + + @Override + public void run() { + try { + while(true) { + Object tmp = buf.get(); + } + } catch(InterruptedException e ){} + } + } + + //--- the test driver + public static void main(String [] args) { + readArguments( args); + //System.out.printf("running BoundedBuffer with buffer-size %d, %d producers and %d consumers\n", BUFFER_SIZE, N_PRODUCERS, N_CONSUMERS); + + BoundedBuffer buf = new BoundedBuffer(BUFFER_SIZE); + + for (int i=0; i 0){ + BUFFER_SIZE = Integer.parseInt(args[0]); + } + if (args.length > 1){ + N_PRODUCERS = Integer.parseInt(args[1]); + } + if (args.length > 2){ + N_CONSUMERS = Integer.parseInt(args[2]); + } + } +} diff --git a/src/examples/BoundedBuffer.jpf b/src/examples/BoundedBuffer.jpf new file mode 100644 index 0000000..bdd86dc --- /dev/null +++ b/src/examples/BoundedBuffer.jpf @@ -0,0 +1,4 @@ +target = BoundedBuffer + +# this should produce a deadlock +target.args = 2,4,1 \ No newline at end of file diff --git a/src/examples/Crossing.java b/src/examples/Crossing.java new file mode 100644 index 0000000..14e279d --- /dev/null +++ b/src/examples/Crossing.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This is the famous Bridge-crossing puzzle. The aim is to see what the minimum + * amount of time is for 4 people to cross with flash-light (torch): 10.5.2.1. + * The answer is 17 for the given configuration. + * + * Purpose of this example is to show how to use the 'Verify' API in test + * applications (usually drivers) + * + * One can find this solution with JPF in BFS search mode - DFS will not + * work since this is an infinite-state program (time keeps increasing). + * + * If one uses the ignoreIf(cond) call the branches that will lead to + * solutions worst than the current will be cut-off and this will allow + * DFS also to complete - and BFS to terminate faster. + * + * When setting the native flag in main one can also save information + * from one run to the next using JPF's native peer methods - + * see JPF_Crossing.java for the code of getTotal() and setTotal(int). + */ + +import gov.nasa.jpf.vm.Verify; + +enum Side { LEFT, RIGHT } + +class Bridge { + + Side torchSide; + Person[] onBridge = new Person[2]; + int numOnBridge = 0; + + public Bridge (Side torchSide){ + this.torchSide = torchSide; + } + + void moveTorch(){ + if (torchSide == Side.LEFT){ + torchSide = Side.RIGHT; + } else { + torchSide = Side.LEFT; + } + } + + public int cross() { + int time = 0; + moveTorch(); + + if (numOnBridge == 1) { + onBridge[0].side = torchSide; + time = onBridge[0].timeToCross; + + //System.out.println("Person " + onBridge[0] + + // " moved to " + Torch.side + + // " in time " + time); + } else { + onBridge[0].side = torchSide; + onBridge[1].side = torchSide; + + if (onBridge[0].timeToCross > onBridge[1].timeToCross) { + time = onBridge[0].timeToCross; + } else { + time = onBridge[1].timeToCross; + } + + //System.out.println("Person " + onBridge[0] + + // " and Person " + onBridge[1] + + // " moved to " + Torch.side + + // " in time " + time); + } + + return time; + } + + public void clearBridge() { + numOnBridge = 0; + onBridge[0] = null; + onBridge[1] = null; + } + + boolean isFull(){ + return numOnBridge == 2; + } + + boolean arePersonsOnBridge(){ + return numOnBridge > 0; + } + + boolean isPersonOnBridge (Person p){ + return (p == onBridge[0] || p == onBridge[1]); + } + + void putPersonOnBridge (Person p){ + onBridge[numOnBridge++] = p; + } +} + +class Person { + String name; + Side side; + int timeToCross; + + public Person(String name, int timeToCross) { + this.timeToCross = timeToCross; + this.name = name; + } + + public void tryToMove (Bridge bridge) { + if (side == bridge.torchSide) { + if (!Verify.getBoolean()) { + if (! (bridge.isFull() || bridge.isPersonOnBridge(this))){ + bridge.putPersonOnBridge(this); + } + } + } + } + + @Override + public String toString(){ + return name; + } +} + +public class Crossing { + + Bridge bridge; + Person[] persons; + int elapsedTime; + Side initialSide; + + public Crossing (Person[] persons, Side initialSide){ + this.persons = persons; + for (Person p : persons){ + p.side = initialSide; + } + + this.bridge = new Bridge( initialSide); + this.initialSide = initialSide; + } + + boolean haveAllPersonsCrossed (){ + for (Person p : persons){ + if (p.side == initialSide){ + return false; + } + } + + return true; + } + + void solve (){ + printPersons(); + System.out.println(); + printCrossingState(); + //Verify.setCounter(0, Integer.MAX_VALUE); + + while (!haveAllPersonsCrossed()){ + for (Person p : persons){ + p.tryToMove(bridge); + } + + if (bridge.arePersonsOnBridge()) { + elapsedTime += bridge.cross(); + + //Verify.ignoreIf(elapsedTime >= Verify.getCounter(0)); + //Verify.ignoreIf(elapsedTime > 17); //with this DFS will also find error + + bridge.clearBridge(); + } + + printCrossingState(); + } + + + System.out.println("total time = " + elapsedTime); + + //Verify.setCounter(0, elapsedTime); // new minimum + Verify.printPathOutput("done"); + Verify.storeTraceAndTerminateIf(elapsedTime == 17, null, null); + //assert (elapsedTime > 17); + } + + String personsOnSide (Side side){ + int n=0; + StringBuilder sb = new StringBuilder(); + for (Person p : persons){ + if (p.side == side){ + if (n++ > 0){ + sb.append(','); + } + sb.append( p); + } + } + return sb.toString(); + } + + String torchSymbol (Side side){ + if (bridge.torchSide == side){ + return "*"; + } else { + return " "; + } + } + + void printPersons(){ + for (Person p : persons){ + System.out.printf("%10s needs %2d min to cross\n", p.name, p.timeToCross); + } + } + + void printCrossingState (){ + System.out.printf("%20s %s====%s %-20s : elapsed time=%d\n", + personsOnSide(Side.LEFT), torchSymbol(Side.LEFT), + torchSymbol(Side.RIGHT), personsOnSide(Side.RIGHT), elapsedTime); + } + + public static void main(String[] args) { + Person[] persons = { + new Person("Bill", 1), + new Person("Xoe", 2), + new Person("Sue", 5), + new Person("Joe", 10) + }; + + Crossing crossing = new Crossing( persons, Side.LEFT); + crossing.solve(); + } +} diff --git a/src/examples/Crossing.jpf b/src/examples/Crossing.jpf new file mode 100644 index 0000000..fb4d186 --- /dev/null +++ b/src/examples/Crossing.jpf @@ -0,0 +1,5 @@ +target = Crossing + +vm.tree_output = false +vm.path_output = true +search.class = .search.heuristic.BFSHeuristic diff --git a/src/examples/DiningPhil.java b/src/examples/DiningPhil.java new file mode 100644 index 0000000..7295a5a --- /dev/null +++ b/src/examples/DiningPhil.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class DiningPhil { + + static class Fork { + } + + static class Philosopher extends Thread { + + Fork left; + Fork right; + + public Philosopher(Fork left, Fork right) { + this.left = left; + this.right = right; + //start(); + } + + @Override + public void run() { + // think! + synchronized (left) { + synchronized (right) { + // eat! + } + } + } + } + + static int nPhilosophers = 6; + + public static void main(String[] args) { + if (args.length > 0){ + nPhilosophers = Integer.parseInt(args[0]); + } + + //Verify.beginAtomic(); + Fork[] forks = new Fork[nPhilosophers]; + for (int i = 0; i < nPhilosophers; i++) { + forks[i] = new Fork(); + } + for (int i = 0; i < nPhilosophers; i++) { + Philosopher p = new Philosopher(forks[i], forks[(i + 1) % nPhilosophers]); + p.start(); + } + //Verify.endAtomic(); + } +} \ No newline at end of file diff --git a/src/examples/DiningPhil.jpf b/src/examples/DiningPhil.jpf new file mode 100644 index 0000000..901b818 --- /dev/null +++ b/src/examples/DiningPhil.jpf @@ -0,0 +1,3 @@ +target = DiningPhil + +search.class = .search.heuristic.BFSHeuristic diff --git a/src/examples/HelloWorld.java b/src/examples/HelloWorld.java new file mode 100644 index 0000000..1be027e --- /dev/null +++ b/src/examples/HelloWorld.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * you guess what that one does - just like a normal VM + */ +public class HelloWorld { + public static void main(String[] args){ + System.out.println("I won't say it!"); + } +} diff --git a/src/examples/HelloWorld.jpf b/src/examples/HelloWorld.jpf new file mode 100644 index 0000000..8545924 --- /dev/null +++ b/src/examples/HelloWorld.jpf @@ -0,0 +1 @@ +target=HelloWorld \ No newline at end of file diff --git a/src/examples/NumericValueCheck.java b/src/examples/NumericValueCheck.java new file mode 100644 index 0000000..d99f092 --- /dev/null +++ b/src/examples/NumericValueCheck.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * example to catch numeric value rnge violations with the NumericValueChecker listener + */ +public class NumericValueCheck { + + public static void main (String[] args){ + double someVariable; + + someVariable = 42; // what else + + someVariable = 12345; // ..That's the number only an idiot would have on his luggage + } +} diff --git a/src/examples/NumericValueCheck.jpf b/src/examples/NumericValueCheck.jpf new file mode 100644 index 0000000..6fa8a95 --- /dev/null +++ b/src/examples/NumericValueCheck.jpf @@ -0,0 +1,10 @@ +target = NumericValueCheck + +listener = .listener.NumericValueChecker + +# NumericValueChecker configuration +range.vars = 1 +range.1.var = NumericValueCheck.main(java.lang.String[]):someVariable +range.1.min = 0 +range.1.max = 42 + diff --git a/src/examples/Racer.java b/src/examples/Racer.java new file mode 100644 index 0000000..227cfab --- /dev/null +++ b/src/examples/Racer.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Racer implements Runnable { + + int d = 42; + + @Override + public void run () { + doSomething(1001); // (1) + d = 0; // (2) + } + + public static void main (String[] args){ + Racer racer = new Racer(); + Thread t = new Thread(racer); + t.start(); + + doSomething(1000); // (3) + int c = 420 / racer.d; // (4) + System.out.println(c); + } + + static void doSomething (int n) { + // not very interesting.. + try { Thread.sleep(n); } catch (InterruptedException ix) {} + } +} diff --git a/src/examples/Racer.jpf b/src/examples/Racer.jpf new file mode 100644 index 0000000..5cfdfd2 --- /dev/null +++ b/src/examples/Racer.jpf @@ -0,0 +1,5 @@ +target = Racer + +listener=gov.nasa.jpf.listener.PreciseRaceDetector + +report.console.property_violation=error,trace diff --git a/src/examples/Rand.java b/src/examples/Rand.java new file mode 100644 index 0000000..4f80754 --- /dev/null +++ b/src/examples/Rand.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Random; + +public class Rand { + public static void main (String[] args) { + System.out.println("computing c = a/(b+a - 2).."); + Random random = new Random(42); // (1) + + int a = random.nextInt(2); // (2) + System.out.printf("a=%d\n", a); + + //... lots of code here + + int b = random.nextInt(3); // (3) + System.out.printf(" b=%d ,a=%d\n", b, a); + + int c = a/(b+a -2); // (4) + System.out.printf("=> c=%d , b=%d, a=%d\n", c, b, a); + } +} diff --git a/src/examples/Rand.jpf b/src/examples/Rand.jpf new file mode 100644 index 0000000..904f74b --- /dev/null +++ b/src/examples/Rand.jpf @@ -0,0 +1,4 @@ +target = Rand + +cg.enumerate_random = true +report.console.property_violation=error,trace \ No newline at end of file diff --git a/src/examples/RobotManager-replay-nt.jpf b/src/examples/RobotManager-replay-nt.jpf new file mode 100644 index 0000000..8664914 --- /dev/null +++ b/src/examples/RobotManager-replay-nt.jpf @@ -0,0 +1,7 @@ +target = RobotManager + +listener=.listener.ChoiceSelector,.listener.NullTracker + +choice.use_trace=trace + +cg.enumerate_random=true diff --git a/src/examples/RobotManager-replay-ot.jpf b/src/examples/RobotManager-replay-ot.jpf new file mode 100644 index 0000000..67aa617 --- /dev/null +++ b/src/examples/RobotManager-replay-ot.jpf @@ -0,0 +1,10 @@ +target = RobotManager + +listener=.listener.ChoiceSelector,.listener.ObjectTracker + +choice.use_trace=trace + +ot.refs = 0x160,0x185 +ot.log_fields = false + +cg.enumerate_random=true diff --git a/src/examples/RobotManager.java b/src/examples/RobotManager.java new file mode 100644 index 0000000..2bf025b --- /dev/null +++ b/src/examples/RobotManager.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +/** + * a simplified version of the AWT RobotManager example + */ +public class RobotManager { + + static class Robot { + String id; + + Robot (String id){ + this.id = id; + } + + String getId(){ + return id; + } + + String processSequence(String sequence){ + System.out.printf("robot %s processing sequence: %s\n", id, sequence); + return "Ok"; + } + } + + class StatusAcquisitionThread extends Thread { + boolean done; + + public StatusAcquisitionThread () { + setDaemon(true); + } + + @Override + public void run () { + int n = robotList.size(); + Random random = new Random(0); + + while (!done) { + int idx = random.nextInt(n); + Robot robot = robotList.get(idx); + setRobotOnline(robot, !isRobotOnline(robot.id)); + + try { + Thread.sleep(3000); + } catch (InterruptedException ix) { + } + } + } + + public void terminate () { + done = true; + } + } + + List robotList = new ArrayList(); + HashMap onlineRobots = new HashMap(); + StatusAcquisitionThread acquisitionThread; + + public RobotManager() { + robotList.add( new Robot("RATS-1")); + robotList.add( new Robot("RATS-2")); + robotList.add( new Robot("RCAT-1")); + robotList.add( new Robot("POGO-1")); + + for (Robot r : robotList) { + setRobotOnline(r, true); + } + } + + public void setRobotOnline (Robot robot, boolean isOnline) { + if (isOnline) { + onlineRobots.put(robot.getId(), robot); + } else { + onlineRobots.remove(robot.getId()); + } + } + + public boolean isRobotOnline (String robotName) { + return onlineRobots.containsKey(robotName); + } + + public Robot getOnlineRobot (String robotName) { + return onlineRobots.get(robotName); + } + + public String sendSequence(Robot robot, String sequence) { + return robot.processSequence(sequence); + } + + void startStatusAcquisitionThread (){ + acquisitionThread = new StatusAcquisitionThread(); + acquisitionThread.start(); + } + + void stopStatusAcquisitionThread(){ + acquisitionThread.terminate(); + } + + void processInput (){ + String robotName = "POGO-1"; + String sequence = "left; go"; + + if (isRobotOnline(robotName)){ + Robot robot = getOnlineRobot( robotName); + String result = robot.processSequence(sequence); + System.out.printf("sent sequence \"%s\" to robot %s => %s\n", sequence, robotName, result); + } else { + System.out.print("robot not online: "); + System.out.println(robotName); + } + } + + public static void main (String[] args){ + RobotManager robotManager = new RobotManager(); + robotManager.startStatusAcquisitionThread(); + robotManager.processInput(); + //robotManager.stopStatusAcquisitionThread(); + } +} diff --git a/src/examples/RobotManager.jpf b/src/examples/RobotManager.jpf new file mode 100644 index 0000000..481e64b --- /dev/null +++ b/src/examples/RobotManager.jpf @@ -0,0 +1,5 @@ +target = RobotManager + +listener=.listener.TraceStorer + +cg.enumerate_random=true diff --git a/src/examples/StopWatch.java b/src/examples/StopWatch.java new file mode 100644 index 0000000..8da5066 --- /dev/null +++ b/src/examples/StopWatch.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * example to show how to explore off-nominal paths + */ +public class StopWatch { + + public static void main(String[] args){ + long tStart = System.currentTimeMillis(); + System.out.println("some lengthy computation.."); + long tEnd = System.currentTimeMillis(); + + if (tEnd - tStart > 1000){ + throw new RuntimeException("it took too long.."); + } + + System.out.println("all fine, finished in time"); + } +} diff --git a/src/examples/StopWatch.jpf b/src/examples/StopWatch.jpf new file mode 100644 index 0000000..2cabef9 --- /dev/null +++ b/src/examples/StopWatch.jpf @@ -0,0 +1,3 @@ +target = StopWatch + +listener = .listener.StopWatchFuzzer diff --git a/src/examples/TestExample-coverage.jpf b/src/examples/TestExample-coverage.jpf new file mode 100644 index 0000000..75d9ed4 --- /dev/null +++ b/src/examples/TestExample-coverage.jpf @@ -0,0 +1,7 @@ +target = TestExample + +listener=.listener.CoverageAnalyzer + +coverage.include = T1,T2 +coverage.show_methods = true +#coverage.show_bodies = true \ No newline at end of file diff --git a/src/examples/TestExample.java b/src/examples/TestExample.java new file mode 100644 index 0000000..48aebdc --- /dev/null +++ b/src/examples/TestExample.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class T1 { + int d = 42; + + public int func1(int a, int b) { + if (a > b) { + return 1; + } else if (a == b) { + return 0; + } else { + return -1; + } + } + + public boolean func2(boolean cond) { + if (cond && (d > 40)) { + d--; + } else { + d++; + } + return cond; + } +} + +class T2 { + + public int computeSomething (int a, int b){ + try { + return a / b; + } catch (ArithmeticException ax){ + return -1; // pretty lame error handling + } + } + + public void doSomething() { + System.out.println("something"); + } +} + +public class TestExample { + + public static void main(String[] args) { + T1 t1 = new T1(); + + assert t1.func1(1, 0) > 0; + assert t1.func1(0, 1) < 0; + + assert t1.func2(true) == true; + assert t1.func2(false) == false; + + + T2 t2 = new T2(); + + assert t2.computeSomething(42, 42) == 1.0; + } +} + diff --git a/src/examples/oldclassic-da.jpf b/src/examples/oldclassic-da.jpf new file mode 100644 index 0000000..b50256e --- /dev/null +++ b/src/examples/oldclassic-da.jpf @@ -0,0 +1,10 @@ +# JPF properties to run the oldclassic example with DeadlockAnalyzer report + +target=oldclassic + +# turn off instruction trace +report.console.property_violation=error,snapshot + +# deadlock analyzer is a property-specific trace report generator +listener=.listener.DeadlockAnalyzer +deadlock.format=essential \ No newline at end of file diff --git a/src/examples/oldclassic.java b/src/examples/oldclassic.java new file mode 100644 index 0000000..7c10d6c --- /dev/null +++ b/src/examples/oldclassic.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This example shows a deadlock that occurs as a result of a missed signal, + * i.e. a wait() that happens after the corresponding notify(). + * + * The defect is caused by a violated monitor encapsulation, i.e. directly + * accessing monitor internal data ('Event.count') from concurrent clients + * ('FirstTask', 'SecondTask'), without synchronization with the + * corresponding monitor operations ('wait_for-Event()' and 'signalEvent()'). + * + * The resulting race is typical for unsafe optimizations that try to + * avoid expensive blocking calls by means of local caches + * + * This example was inspired by a defect found in the "Remote Agent" + * spacecraft controller that flew on board of "Deep Space 1", as described + * in: + * + * Model Checking Programs + * W. Visser, K. Havelund, G. Brat, S. Park and F. Lerda + * Automated Software Engineering Journal + * Volume 10, Number 2, April 2003 + * + * @author wvisser + */ + +//------- the test driver +public class oldclassic { + public static void main (String[] args) { + Event new_event1 = new Event(); + Event new_event2 = new Event(); + + FirstTask task1 = new FirstTask(new_event1, new_event2); + SecondTask task2 = new SecondTask(new_event1, new_event2); + + task1.start(); + task2.start(); + } +} + +//------- shared objects implemented as monitors +class Event { + int count = 0; + + public synchronized void signal_event () { + + // NOTE: this abstraction is not strictly required - even if the state space would + // be unbound, JPF could still find the error at a reasonable search depth, + // unless it's left-most branch in the search tree is unbound. If it is, + // there are two ways to work around: (1) use a different search strategy + // (e.g. HeuristicSearch with BFSHeuristic), or (2) set a random choice + // enumeration order ("+cg.randomize_choices=true"). In this example, (2) + // works just fine + count = (count + 1) % 3; + //count++; // requires "+cg.randomize_choices=true" for DFSearch policy + + notifyAll(); + } + + public synchronized void wait_for_event () { + try { + wait(); + } catch (InterruptedException e) { + } + } +} + +//------- the two concurrent threads using the monitors +class FirstTask extends Thread { + Event event1; + Event event2; + int count = 0; // bad optimization - local cache of event1 internals + + public FirstTask (Event e1, Event e2) { + this.event1 = e1; + this.event2 = e2; + } + + @Override + public void run () { + count = event1.count; // violates event1 monitor encapsulation + + while (true) { + System.out.println("1"); + + if (count == event1.count) { // ditto + event1.wait_for_event(); + } + + count = event1.count; // ditto + event2.signal_event(); // updates event2.count + } + } +} + +class SecondTask extends Thread { + Event event1; + Event event2; + int count = 0; // bad optimization - local cache of event2 internals + + public SecondTask (Event e1, Event e2) { + this.event1 = e1; + this.event2 = e2; + } + + @Override + public void run () { + count = event2.count; // violates event2 monitor encapsulation + + while (true) { + System.out.println(" 2"); + event1.signal_event(); // updates event1.count + + if (count == event2.count) { // ditto + event2.wait_for_event(); + } + + count = event2.count; // ditto + } + } +} diff --git a/src/examples/oldclassic.jpf b/src/examples/oldclassic.jpf new file mode 100644 index 0000000..ea4b55a --- /dev/null +++ b/src/examples/oldclassic.jpf @@ -0,0 +1,5 @@ +# JPF properties to run the oldclassic example with DeadlockAnalyzer report + +target=oldclassic + +report.console.property_violation=error,snapshot,trace diff --git a/src/main/gov/nasa/jpf/$coreTag.java b/src/main/gov/nasa/jpf/$coreTag.java new file mode 100644 index 0000000..2b9aca9 --- /dev/null +++ b/src/main/gov/nasa/jpf/$coreTag.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +/** + * if this class can be loaded, the JPF core is in the CLASSPATH. + * + * The reason to use an empty, non-instantiable tag class for this is to make + * sure we don't get conflicts between CLs - this class should not be used + * for anything but to check if it can be found + * + * NOTE - this class has to be reachable through the same CP entry like + * gov.nasa.jpf.JPF and gov.nasa.jpf.Config + */ +public final class $coreTag { + private $coreTag() { + // nobody can call this + } +} diff --git a/src/main/gov/nasa/jpf/Config.java b/src/main/gov/nasa/jpf/Config.java new file mode 100644 index 0000000..947ff87 --- /dev/null +++ b/src/main/gov/nasa/jpf/Config.java @@ -0,0 +1,2468 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + + +import gov.nasa.jpf.util.FileUtils; +import gov.nasa.jpf.util.JPFSiteUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.logging.Logger; +import java.util.regex.Pattern; + + +/** + * class that encapsulates property-based JPF configuration. This is mainly an + * associative array with various typed accessors, and a structured + * initialization process. This implementation has the design constraint that it + * does not promote symbolic information to concrete types, which means that + * frequently accessed data should be promoted and cached in client classes. + * This in turn means we assume the data is not going to change at runtime. + * Major motivation for this mechanism is to avoid 'Option' classes that have + * concrete type fields, and hence are structural bottlenecks, i.e. every + * parameterized user extension (Heuristics, Scheduler etc.) require to update + * this single class. Note that Config is also not thread safe with respect to + * retrieving exceptions that occurred during instantiation + * + * Another important caveat for both implementation and usage of Config is that + * it is supposed to be our master configuration mechanism, i.e. it is also used + * to configure other core services like logging. This means that Config + * initialization should not depend on these services. Initialization has to + * return at all times, recording potential problems for later handling. This is + * why we have to keep the Config data model and initialization fairly simple + * and robust. + * + * Except of JPF and Config itself, all JPF classes are loaded by a + * Classloader that is constucted by Config (e.g. by collecting jars from + * known/configured locations), i.e. we SHOULD NOT rely on any 3rd party + * libraries within Config. The class should be as autarkical as possible. + * + * + * PROPERTY SOURCES + * ---------------- + * + * (1) one site.properties - this file specifies the location of the jpf-core and + * installed extensions, like: + * + * jpf-core = /Users/pcmehlitz/projects/jpf/jpf-core + * ... + * jpf-numeric = /Users/pcmehlitz/projects/jpf/jpf-numeric + * ... + * extensions = ${jpf-core} + * + * Each key/directory that is in site.properties is used to locate a corresponding + * project property (jpf.properties) file + * + * (2) any number of jpf.properties project properties files - each directory + * entry in the 'extensions' list is checked for a jpf.properties file, which + * is automatically loaded if found. Project properties mostly contain path + * settings that are used to initialize class loading by the host VM and JPF + * + * (3) one *.jpf application properties - this specifies all the settings for a + * specific JPF run, esp. listener and target/target.args. + * app properties can be specified as the sole JPF argument, i.e. instead of + * a SUT classname + * .. + * target = x.Y.MySystemUnderTest + * target.args = one,two + * .. + * listener = z.MyListener + * + * (4) commandline properties - all start with '+', they can override all other props + * + * + * LOOKUP ORDER + * ------------ + * property lookup + * property type : spec : default + * ----------------:-----------------------:---------- + * | site : +site : "${user.home}/[.]jpf/site.properties" + * | : : + * | project : 'extensions' value : set in site.properties + * | : : + * | app : +app : - + * | : : + * v cmdline : += : - + * + * * if there is an explicit spec and the pathname does not exist, throw a + * JPFConfigException + * + * * if the system properties cannot be found, throw a JPFConfigException + * + * + * <2do> need to make NumberFormatException handling consistent - should always + * throw an JPFConfigException, not silently returning the default value + * + */ + + +@SuppressWarnings("serial") +public class Config extends Properties { + + static final char KEY_PREFIX = '@'; + public static final String REQUIRES_KEY = "@requires"; + public static final String INCLUDE_KEY = "@include"; + public static final String INCLUDE_UNLESS_KEY = "@include_unless"; + public static final String INCLUDE_IF_KEY = "@include_if"; + public static final String USING_KEY = "@using"; + + static final String[] EMPTY_STRING_ARRAY = new String[0]; + + public static final String LIST_SEPARATOR = ","; + public static final String PATH_SEPARATOR = ","; // the default for automatic appends + + public static final Class[] CONFIG_ARGTYPES = { Config.class }; + public static final Class[] NO_ARGTYPES = new Class[0]; + public static final Object[] NO_ARGS = new Object[0]; + + public static final String TRUE = "true"; + public static final String FALSE = "false"; + + static final String MAX = "MAX"; + + static final String IGNORE_VALUE = "-"; + + // maximum number of processes for distributed applications + public static int MAX_NUM_PRC = 16; + + // do we want to log the config init + public static boolean log = false; + + // bad - a control exception + static class MissingRequiredKeyException extends RuntimeException { + MissingRequiredKeyException(String details){ + super(details); + } + } + + // it seems bad design to keep ClassLoader management in a glorified Properties object, + // but a lot of what Config does is to resolve configured types, for which we need + // control over the loader that is used for resolution + ClassLoader loader = Config.class.getClassLoader(); + + // where did we initialize from + ArrayList sources = new ArrayList(); + + ArrayList changeListeners; + + // Properties are simple Hashmaps, but we want to maintain the order of entries + LinkedList entrySequence = new LinkedList(); + + // an [optional] hashmap to keep objects we want to be singletons + HashMap singletons; + + public final Object[] CONFIG_ARGS = { this }; + + // the original command line args that were passed into the constructor + String[] args; + + // non-property/option command line args (starting from the first arg that is not prepened by '-','+') + String[] freeArgs; + + /** + * the standard Config constructor that processes the whole properties stack + */ + public Config (String[] cmdLineArgs) { + args = cmdLineArgs; + String[] a = cmdLineArgs.clone(); // we might nullify some of them + + // we need the app properties (*.jpf) pathname upfront because it might define 'site' + String appProperties = getAppPropertiesLocation(a); + + //--- the site properties + String siteProperties = getSitePropertiesLocation( a, appProperties); + if (siteProperties != null){ + loadProperties( siteProperties); + } + + //--- get the project properties from current dir + site configured extensions + loadProjectProperties(); + + //--- the application properties + if (appProperties != null){ + loadProperties( appProperties); + } + + //--- at last, the (rest of the) command line properties + loadArgs(a); + + // note that global path collection now happens from initClassLoader(), to + // accommodate for deferred project initialization when explicitly setting Config entries + + //printEntries(); + } + + private Config() { + // just interal, for reloading + } + + /** + * single source Config constructor (does not process stack) + * @param fileName - single properties filename to initialize from + */ + public Config (String fileName){ + loadProperties(fileName); + } + + public Config (Reader in){ + try { + load(in); + } catch (IOException iox){ + exception("error reading data: " + iox); + } + } + + public static void enableLogging (boolean enableLogging){ + log = enableLogging; + } + + public void log (String msg){ + if (log){ // very simplisitc, but we might do more in the future + System.out.println(msg); + } + } + + + String getAppPropertiesLocation(String[] args){ + String path = null; + + path = getPathArg(args, "app"); + if (path == null){ + // see if the first free arg is a *.jpf + path = getAppArg(args); + } + + put("jpf.app", path); + + return path; + } + + String getSitePropertiesLocation(String[] args, String appPropPath){ + String path = getPathArg(args, "site"); + + if (path == null){ + // look into the app properties + // NOTE: we might want to drop this in the future because it constitutes + // a cyclic properties file dependency + if (appPropPath != null){ + path = JPFSiteUtils.getMatchFromFile(appPropPath,"site"); + } + + if (path == null) { + File siteProps = JPFSiteUtils.getStandardSiteProperties(); + if (siteProps != null){ + path = siteProps.getAbsolutePath(); + } + } + } + + put("jpf.site", path); + + return path; + } + + + // watch out - this does not reset the computed paths! + public Config reload() { + log("reloading config"); + + // just reload all our sources + Config newConfig = new Config(); + for (Object src : sources){ + if (src instanceof File) { + newConfig.loadProperties(((File)src).getPath()); + } else if (src instanceof URL) { + newConfig.loadProperties((URL)src); + } else { + log("don't know how to reload: " + src); + } + } + + // now reload command line args on top of that + newConfig.loadArgs(args); + newConfig.args = args; + + return newConfig; + } + + public String[] getArgs() { + return args; + } + + /* + * note that matching args are expanded and stored here, to avoid any + * discrepancy with value expansions (which are order-dependent) + */ + protected String getPathArg (String[] args, String key){ + int keyLen = key.length(); + + for (int i=0; i keyLen + 2){ + if (a.charAt(0) == '+' && a.charAt(keyLen+1) == '='){ + if (a.substring(1, keyLen+1).equals(key)){ + String val = expandString(key, a.substring(keyLen+2)); + args[i] = null; // processed + return val; + } + } + } + } + } + + return null; + } + + /* + * if the first freeArg is a JPF application property filename, use this + * as targetArg and set the "jpf.app" property accordingly + */ + protected String getAppArg (String[] args){ + + for (int i=0; i 0){ + switch (a.charAt(0)) { + case '+': continue; + case '-': continue; + default: + if (a.endsWith(".jpf")){ + String val = expandString("jpf.app", a); + args[i] = null; // processed + return val; + } + } + } + } + + return null; + } + + + protected void loadProperties (URL url){ + log("loading defaults from: " + url); + + InputStream is = null; + try { + is = url.openStream(); + load(is); + sources.add(url); + } catch (IOException iox){ + log("error in input stream for: " + url + " : " + iox.getMessage()); + } finally { + if (is != null){ + try { + is.close(); + } catch (IOException iox1){ + log("error closing input stream for: " + url + " : " + iox1.getMessage()); + } + } + } + } + + protected void setConfigPathProperties (String fileName){ + put("config", fileName); + int i = fileName.lastIndexOf(File.separatorChar); + if (i>=0){ + put("config_path", fileName.substring(0,i)); + } else { + put("config_path", "."); + } + } + + + protected boolean loadProperties (String fileName) { + if (fileName != null && fileName.length() > 0) { + FileInputStream is = null; + try { + File f = new File(fileName); + if (f.isFile()) { + log("loading property file: " + fileName); + + setConfigPathProperties(f.getAbsolutePath()); + sources.add(f); + is = new FileInputStream(f); + load(is); + return true; + } else { + throw exception("property file does not exist: " + f.getAbsolutePath()); + } + } catch (MissingRequiredKeyException rkx){ + // Hmpff - control exception + log("missing required key: " + rkx.getMessage() + ", skipping: " + fileName); + } catch (IOException iex) { + throw exception("error reading properties: " + fileName); + } finally { + if (is != null){ + try { + is.close(); + } catch (IOException iox1){ + log("error closing input stream for file: " + fileName); + } + } + } + } + + return false; + } + + + /** + * this holds the policy defining in which order we process directories + * containing JPF projects (i.e. jpf.properties files) + */ + protected void loadProjectProperties () { + // this is the list of directories holding jpf.properties files that + // have to be processed in order of entry (increasing priority) + LinkedList jpfDirs = new LinkedList(); + + // deduce the JPF projects in use (at least jpf-core) from the CL which + // defined this class + addJPFdirsFromClasspath(jpfDirs); + + // add all the site configured extension dirs (but NOT jpf-core) + addJPFdirsFromSiteExtensions(jpfDirs); + + // add the current dir, which has highest priority (this might bump up + // a previous entry by reodering it - which includes jpf-core) + addCurrentJPFdir(jpfDirs); + + // now load all the jpf.property files we found in these dirs + // (later loads can override previous settings) + for (File dir : jpfDirs){ + loadProperties(new File(dir,"jpf.properties").getAbsolutePath()); + } + } + + protected void appendPath (String pathKey, String key, String configPath){ + String[] paths = getStringArray(key); + if (paths != null){ + for (String e : paths) { + if (!e.startsWith("${") || !e.startsWith(File.separator)) { + e = configPath + File.separatorChar + e; + } + append(pathKey, e, PATH_SEPARATOR); + } + } + } + + protected void addJPFdirs (List jpfDirs, File dir){ + while (dir != null) { + File jpfProp = new File(dir, "jpf.properties"); + if (jpfProp.isFile()) { + registerJPFdir(jpfDirs, dir); + return; // we probably don't want recursion here + } + dir = getParentFile(dir); + } + } + + /** + * add the current dir to the list of JPF components. + * Note: this includes the core, so that we maintain the general + * principle that the enclosing project takes precedence (imagine the opposite: + * if we want to test a certain feature that is overridden by another extension + * we don't know about) + */ + protected void addCurrentJPFdir(List jpfDirs){ + File dir = new File(System.getProperty("user.dir")); + while (dir != null) { + File jpfProp = new File(dir, "jpf.properties"); + if (jpfProp.isFile()) { + registerJPFdir(jpfDirs, dir); + return; + } + dir = getParentFile(dir); + } + } + + protected void addJPFdirsFromClasspath(List jpfDirs) { + String cp = System.getProperty("java.class.path"); + String[] cpEntries = cp.split(File.pathSeparator); + + for (String p : cpEntries) { + File f = new File(p); + File dir = f.isFile() ? getParentFile(f) : f; + + addJPFdirs(jpfDirs, dir); + } + } + + protected void addJPFdirsFromSiteExtensions (List jpfDirs){ + String[] extensions = getCompactStringArray("extensions"); + if (extensions != null){ + for (String pn : extensions){ + addJPFdirs( jpfDirs, new File(pn)); + } + } + } + + /** + * the obvious part is that it only adds to the list if the file is absent + * the not-so-obvious part is that it re-orders already present files + * to maintain the priority + */ + protected boolean registerJPFdir(List list, File dir){ + try { + dir = dir.getCanonicalFile(); + + for (File e : list) { + if (e.equals(dir)) { + list.remove(e); + list.add(e); + return false; + } + } + } catch (IOException iox) { + throw new JPFConfigException("illegal path spec: " + dir); + } + + list.add(dir); + return true; + } + + static File root = new File(File.separator); + + protected File getParentFile(File f){ + if (f == root){ + return null; + } else { + File parent = f.getParentFile(); + if (parent == null){ + parent = new File(f.getAbsolutePath()); + + if (parent.getName().equals(root.getName())) { + return root; + } else { + return parent; + } + } else { + return parent; + } + } + } + + + /* + * argument syntax: + * {'+'['=''] | '-'} {} + * + * (1) null cmdLineArgs are ignored + * (2) all config cmdLineArgs start with '+' + * (3) if '=' is ommitted, a 'true' value is assumed + * (4) if is ommitted, a 'null' value is assumed + * (5) no spaces around '=' + * (6) all '-' driver-cmdLineArgs are ignored + */ + + protected void loadArgs (String[] cmdLineArgs) { + + for (int i=0; i 0){ + switch (a.charAt(0)){ + case '+': // Config arg + processArg(a.substring(1)); + break; + + case '-': // driver arg, ignore + continue; + + default: // free (non property/option) cmdLineArgs to follow + + int n = cmdLineArgs.length - i; + freeArgs = new String[n]; + System.arraycopy(cmdLineArgs, i, freeArgs, 0, n); + + return; + } + } + } + } + + + /* + * this does not include the '+' prefix, just the + * [=[]] + */ + protected void processArg (String a) { + + int idx = a.indexOf("="); + + if (idx == 0){ + throw new JPFConfigException("illegal option: " + a); + } + + if (idx > 0) { + String key = a.substring(0, idx).trim(); + String val = a.substring(idx + 1).trim(); + + if (val.length() == 0){ + val = null; + } + + setProperty(key, val); + + } else { + setProperty(a.trim(), "true"); + } + + } + + + /** + * replace string constants with global static objects + */ + protected String normalize (String v) { + if (v == null){ + return null; // ? maybe TRUE - check default loading of "key" or "key=" + } + + // trim leading and trailing blanks (at least Java 1.4.2 does not take care of trailing blanks) + v = v.trim(); + + // true/false + if ("true".equalsIgnoreCase(v) + || "yes".equalsIgnoreCase(v) + || "on".equalsIgnoreCase(v)) { + v = TRUE; + } else if ("false".equalsIgnoreCase(v) + || "no".equalsIgnoreCase(v) + || "off".equalsIgnoreCase(v)) { + v = FALSE; + } + + // nil/null + if ("nil".equalsIgnoreCase(v) || "null".equalsIgnoreCase(v)){ + v = null; + } + + return v; + } + + + // our internal expander + // Note that we need to know the key this came from, to handle recursive expansion + protected String expandString (String key, String s) { + int i, j = 0; + if (s == null || s.length() == 0) { + return s; + } + + while ((i = s.indexOf("${", j)) >= 0) { + if ((j = s.indexOf('}', i)) > 0) { + String k = s.substring(i + 2, j); + String v; + + if ((key != null) && key.equals(k)) { + // that's expanding itself -> use what is there + v = getProperty(key); + } else { + // refers to another key, which is already expanded, so this + // can't get recursive (we expand during entry storage) + v = getProperty(k); + } + + if (v == null) { // if we don't have it, fall back to system properties + v = System.getProperty(k); + } + + if (v != null) { + s = s.substring(0, i) + v + s.substring(j + 1, s.length()); + j = i + v.length(); + } else { + s = s.substring(0, i) + s.substring(j + 1, s.length()); + j = i; + } + } + } + + return s; + } + + + boolean loadPropertiesRecursive (String fileName){ + // save the current values of automatic properties + String curConfig = (String)get("config"); + String curConfigPath = (String)get("config_path"); + + File propFile = new File(fileName); + if (!propFile.isAbsolute()){ + propFile = new File(curConfigPath, fileName); + } + String absPath = propFile.getAbsolutePath(); + + if (!propFile.isFile()){ + throw exception("property file does not exist: " + absPath); + } + + boolean ret = loadProperties(absPath); + + // restore the automatic properties + super.put("config", curConfig); + super.put("config_path", curConfigPath); + + return ret; + } + + void includePropertyFile(String key, String value){ + value = expandString(key, value); + if (value != null && value.length() > 0){ + loadPropertiesRecursive(value); + } else { + throw exception("@include pathname argument missing"); + } + } + + void includeCondPropertyFile(String key, String value, boolean keyPresent){ + value = expandString(key, value); + if (value != null && value.length() > 0){ + // check if it's a conditional "@include_unless/if = ?key?pathName" + if (value.charAt(0) == '?'){ + int idx = value.indexOf('?', 1); + if (idx > 1){ + String k = value.substring(1, idx); + if (containsKey(k) == keyPresent){ + String v = value.substring(idx+1); + if (v.length() > 0){ + loadPropertiesRecursive(v); + } else { + throw exception("@include_unless pathname argument missing (??)"); + } + } + + } else { + throw exception("malformed @include_unless argument (??), found: " + value); + } + } else { + throw exception("malformed @include_unless argument (??), found: " + value); + } + } else { + throw exception("@include_unless missing ?? argument"); + } + } + + + void includeProjectPropertyFile (String projectId){ + String projectPath = getString(projectId); + if (projectPath != null){ + File projectProps = new File(projectPath, "jpf.properties"); + if (projectProps.isFile()){ + loadPropertiesRecursive(projectProps.getAbsolutePath()); + + } else { + throw exception("project properties not found: " + projectProps.getAbsolutePath()); + } + + } else { + throw exception("unknown project id (check site.properties): " + projectId); + } + } + + // we override this so that we can handle expansion for both key and value + // (value expansion can be recursive, i.e. refer to itself) + @Override + public Object put (Object keyObject, Object valueObject){ + + if (keyObject == null){ + throw exception("no null keys allowed"); + } else if (!(keyObject instanceof String)){ + throw exception("only String keys allowed, got: " + keyObject); + } + if (valueObject != null && !(valueObject instanceof String)){ + throw exception("only String or null values allowed, got: " + valueObject); + } + + String key = (String)keyObject; + String value = (String)valueObject; + + if (key.length() == 0){ + throw exception("no empty keys allowed"); + } + + if (key.charAt(0) == KEY_PREFIX){ + processPseudoProperty( key, value); + return null; // no value it replaces + + } else { + // finally, a real key/value pair to add (or remove) - expand and store + String k = expandString(null, key); + + if (!(value == null)) { // add or overwrite entry + String v = value; + + if (k.charAt(k.length() - 1) == '+') { // the append hack + k = k.substring(0, k.length() - 1); + return append(k, v, null); + + } else if (k.charAt(0) == '+') { // the prepend hack + k = k.substring(1); + return prepend(k, v, null); + + } else { // normal value set + v = normalize(expandString(k, v)); + if (v != null){ + return setKey(k, v); + } else { + return removeKey(k); + } + } + + } else { // setting a null value removes the entry + return removeKey(k); + } + } + } + + protected void processPseudoProperty( String key, String value){ + if (REQUIRES_KEY.equals(key)) { + // shortcircuit loading of property files - used to enforce order + // of properties, e.g. to model dependencies + for (String reqKey : split(value)) { + if (!containsKey(reqKey)) { + throw new MissingRequiredKeyException(reqKey); + } + } + + } else if (INCLUDE_KEY.equals(key)) { + includePropertyFile(key, value); + + } else if (INCLUDE_UNLESS_KEY.equals(key)) { + includeCondPropertyFile(key, value, false); + + } else if (INCLUDE_IF_KEY.equals(key)) { + includeCondPropertyFile(key, value, true); + + } else if (USING_KEY.equals(key)) { + // check if corresponding jpf.properties has already been loaded. If yes, skip + if (!haveSeenProjectProperty(value)){ + includeProjectPropertyFile(value); + } + + } else { + throw exception("unknown keyword: " + key); + } + } + + protected boolean haveSeenProjectProperty (String key){ + String pn = getString(key); + if (pn == null){ + return false; + } else { + return sources.contains( new File( pn, "jpf.properties")); + } + } + + private Object setKey (String k, String v){ + Object oldValue = put0(k, v); + notifyPropertyChangeListeners(k, (String) oldValue, v); + return oldValue; + } + + private Object removeKey (String k){ + Object oldValue = super.get(k); + remove0(k); + notifyPropertyChangeListeners(k, (String) oldValue, null); + return oldValue; + } + + private Object put0 (String k, Object v){ + entrySequence.add(k); + return super.put(k, v); + } + + private Object remove0 (String k){ + entrySequence.add(k); + return super.remove(k); + } + + public String prepend (String key, String value, String separator) { + String oldValue = getProperty(key); + value = normalize( expandString(key, value)); + + append0(key, oldValue, value, oldValue, separator); + + return oldValue; + } + + public String append (String key, String value, String separator) { + String oldValue = getProperty(key); + value = normalize( expandString(key, value)); + + append0(key, oldValue, oldValue, value, separator); + + return oldValue; + } + + + private void append0 (String key, String oldValue, String a, String b, String separator){ + String newValue; + + if (a != null){ + if (b != null) { + StringBuilder sb = new StringBuilder(a); + if (separator != null) { + sb.append(separator); + } + sb.append(b); + newValue = sb.toString(); + + } else { // b==null : nothing to append + if (oldValue == a){ // using reference compare is intentional here + return; // no change + } else { + newValue = a; + } + } + + } else { // a==null : nothing to append to + if (oldValue == b || b == null){ // using reference compare is intentional here + return; // no change + } else { + newValue = b; + } + } + + // if we get here, we have a newValue that differs from oldValue + put0(key, newValue); + notifyPropertyChangeListeners(key, oldValue, newValue); + } + + protected String append (String key, String value) { + return append(key, value, LIST_SEPARATOR); // append with our standard list separator + } + + /** + * check if we have a key.index entry. If not, check the non-indexed key. If no + * key found return null + * This simplifies clients that can have process id indexed properties + */ + public String getIndexableKey (String key, int index){ + String k = key + '.' + index; + if (containsKey(k)){ + return k; + } else { + if (containsKey(key)){ + return key; + } + } + + return null; // neither indexed nor non-indexed key in dictionary + } + + public void setClassLoader (ClassLoader newLoader){ + loader = newLoader; + } + + public ClassLoader getClassLoader (){ + return loader; + } + + public boolean hasSetClassLoader (){ + return Config.class.getClassLoader() != loader; + } + + public JPFClassLoader initClassLoader (ClassLoader parent) { + ArrayList list = new ArrayList(); + + // we prefer to call this here automatically instead of allowing + // explicit collectGlobalPath() calls because (a) this could not preserve + // initial path settings, and (b) setting it *after* the JPFClassLoader got + // installed won't work (would have to add URLs explicitly, or would have + // to create a new JPFClassLoader, which then conflicts with classes already + // defined by the previous one) + collectGlobalPaths(); + if (log){ + log("collected native_classpath=" + get("native_classpath")); + log("collected native_libraries=" + get("native_libraries")); + } + + + String[] cp = getCompactStringArray("native_classpath"); + cp = FileUtils.expandWildcards(cp); + for (String e : cp) { + list.add(e); + } + URL[] urls = FileUtils.getURLs(list); + + String[] nativeLibs = getCompactStringArray("native_libraries"); + + JPFClassLoader cl; + if (parent instanceof JPFClassLoader){ // no need to create a new one, just initialize + cl = (JPFClassLoader)parent; + for (URL url : urls){ + cl.addURL(url); + } + cl.setNativeLibs(nativeLibs); + + } else { + cl = new JPFClassLoader( urls, nativeLibs, parent); + } + + loader = cl; + return cl; + } + + /** + * has to be called if 'native_classpath' gets explicitly changed + * USE WITH CARE - if this is messed up, it is hard to debug + */ + public void updateClassLoader (){ + if (loader != null && loader instanceof JPFClassLoader){ + JPFClassLoader jpfCl = (JPFClassLoader)loader; + + ArrayList list = new ArrayList(); + String[] cp = getCompactStringArray("native_classpath"); + cp = FileUtils.expandWildcards(cp); + for (String e : cp) { + URL url = FileUtils.getURL(e); + jpfCl.addURL(url); // this does not add if already present + } + + String[] nativeLibs = getCompactStringArray("native_libraries"); + jpfCl.setNativeLibs(nativeLibs); + } + } + + + //------------------------------ public methods - the Config API + + + public String[] getEntrySequence () { + // whoever gets this might add/append/remove items, so we have to + // avoid ConcurrentModificationExceptions + return entrySequence.toArray(new String[entrySequence.size()]); + } + + public void addChangeListener (ConfigChangeListener l) { + if (changeListeners == null) { + changeListeners = new ArrayList(); + changeListeners.add(l); + } else { + if (!changeListeners.contains(l)) { + changeListeners.add(l); + } + } + } + + public void removeChangeListener (ConfigChangeListener l) { + if (changeListeners != null) { + changeListeners.remove(l); + + if (changeListeners.size() == 0) { + changeListeners = null; + } + } + } + + // this shouldn't really be public but only accessible to JPF + public void jpfRunTerminated() { + if (changeListeners != null) { + // note we can't use the standard list iterator here because the sole purpose + // of having this notification is to remove the listener from the list during its enumeration + // which would give us ConcurrentModificationExceptions + ArrayList list = (ArrayList)changeListeners.clone(); + for (ConfigChangeListener l : list) { + l.jpfRunTerminated(this); + } + } + } + + public JPFException exception (String msg) { + String context = getString("config"); + if (context != null){ + msg = "error in " + context + " : " + msg; + } + + return new JPFConfigException(msg); + } + + public void throwException(String msg) { + throw new JPFConfigException(msg); + } + + /** + * return any command line args that are not options or properties + * (this usually contains the application class and arguments) + */ + public String[] getFreeArgs(){ + return freeArgs; + } + + //--- special keys + + /* + * target and its associated keys (target.args, target.entry) are now + * just ordinary key/value pairs and only here as convenience methods + * for JPF drivers/shells so that you don't have to remember the key names + * + * NOTE - this does only work for a SingleProcessVM, and only has the + * desired effect before the JPF object is created + */ + + public void setTarget (String clsName) { + put("target", clsName); + } + public String getTarget(){ + return getString("target"); + } + + public void setTargetArgs (String[] args) { + StringBuilder sb = new StringBuilder(); + int i=0; + for (String a : args){ + if (i++ > 0){ + sb.append(','); + } + sb.append(a); + } + put("target.args", sb.toString()); + } + public String[] getTargetArgs(){ + String[] a = getStringArray("target.args"); + if (a == null){ + return new String[0]; + } else { + return a; + } + } + + public void setTargetEntry (String mthName) { + put("target.entry", mthName); + } + public String getTargetEntry(){ + return getString("target.entry"); + } + + + //----------------------- type specific accessors + + public boolean getBoolean(String key) { + String v = getProperty(key); + return (v == TRUE); + } + + public boolean getBoolean(String key, boolean def) { + String v = getProperty(key); + if (v != null) { + return (v == TRUE); + } else { + return def; + } + } + + /** + * for a given , check if there are corresponding + * values for keys .0 ... . + * If a value is found, store it in an array at the respective index + * + * @param baseKey String with base key without trailing '.' + * @param maxSize maximum size of returned value array + * @return trimmed array with String values found in dictionary + */ + public String[] getStringEnumeration (String baseKey, int maxSize) { + String[] arr = new String[maxSize]; + int max=-1; + + StringBuilder sb = new StringBuilder(baseKey); + sb.append('.'); + int len = baseKey.length()+1; + + for (int i=0; i= 0) { + max++; + if (max < maxSize) { + String[] a = new String[max]; + System.arraycopy(arr,0,a,0,max); + return a; + } else { + return arr; + } + } else { + return null; + } + } + + public String[] getKeysStartingWith (String prefix){ + ArrayList list = new ArrayList(); + + for (Enumeration e = keys(); e.hasMoreElements(); ){ + String k = e.nextElement().toString(); + if (k.startsWith(prefix)){ + list.add(k); + } + } + + return list.toArray(new String[list.size()]); + } + + public String[] getKeyComponents (String key){ + return key.split("\\."); + } + + public int[] getIntArray (String key) throws JPFConfigException { + String v = getProperty(key); + + if (v != null) { + String[] sa = split(v); + int[] a = new int[sa.length]; + int i = 0; + try { + for (; i 0){ + String[] a = v.split(":"); + if (a.length > 3){ + //log.severe("illegal duration: " + key + "=" + v); + return defValue; + } + int m = 1000; + for (int i=a.length-1; i>=0; i--, m*=60){ + try { + int n = Integer.parseInt(a[i]); + d += m*n; + } catch (NumberFormatException nfx) { + throw new JPFConfigException("illegal duration element in '" + key + "' = \"" + v + '"'); + } + } + + } else { + try { + d = Long.parseLong(v); + } catch (NumberFormatException nfx) { + throw new JPFConfigException("illegal duration element in '" + key + "' = \"" + v + '"'); + } + } + + return d; + } + + return defValue; + } + + public int getInt(String key) { + return getInt(key, 0); + } + + public int getInt(String key, int defValue) { + String v = getProperty(key); + if (v != null) { + if (MAX.equals(v)){ + return Integer.MAX_VALUE; + } else { + try { + return Integer.parseInt(v); + } catch (NumberFormatException nfx) { + throw new JPFConfigException("illegal int element in '" + key + "' = \"" + v + '"'); + } + } + } + + return defValue; + } + + public long getLong(String key) { + return getLong(key, 0L); + } + + public long getLong(String key, long defValue) { + String v = getProperty(key); + if (v != null) { + if (MAX.equals(v)){ + return Long.MAX_VALUE; + } else { + try { + return Long.parseLong(v); + } catch (NumberFormatException nfx) { + throw new JPFConfigException("illegal long element in '" + key + "' = \"" + v + '"'); + } + } + } + + return defValue; + } + + public long[] getLongArray (String key) throws JPFConfigException { + String v = getProperty(key); + + if (v != null) { + String[] sa = split(v); + long[] a = new long[sa.length]; + int i = 0; + try { + for (; i getStringSet(String key){ + String v = getProperty(key); + if (v != null && (v.length() > 0)) { + HashSet hs = new HashSet(); + for (String s : split(v)) { + hs.add(s); + } + return hs; + } + + return null; + + } + + public HashSet getNonEmptyStringSet(String key){ + HashSet hs = getStringSet(key); + if (hs != null && hs.isEmpty()) { + return null; + } else { + return hs; + } + } + + public String[] getStringArray(String key) { + String v = getProperty(key); + if (v != null && (v.length() > 0)) { + return split(v); + } + + return null; + } + + public String[] getStringArray(String key, char[] delims) { + String v = getProperty(key); + if (v != null && (v.length() > 0)) { + return split(v,delims); + } + + return null; + } + + public String[] getCompactTrimmedStringArray (String key){ + String[] a = getStringArray(key); + + if (a != null) { + for (int i = 0; i < a.length; i++) { + String s = a[i]; + if (s != null && s.length() > 0) { + a[i] = s.trim(); + } + } + + return removeEmptyStrings(a); + + } else { + return EMPTY_STRING_ARRAY; + } + } + + public String[] getCompactStringArray(String key){ + return removeEmptyStrings(getStringArray(key)); + } + + + public String[] getStringArray(String key, String[] def){ + String v = getProperty(key); + if (v != null && (v.length() > 0)) { + return split(v); + } else { + return def; + } + } + + public static String[] removeEmptyStrings (String[] a){ + if (a != null) { + int n = 0; + for (int i=0; i 0){ + n++; + } + } + + if (n < a.length){ // we have empty strings in the split + String[] r = new String[n]; + for (int i=0, j=0; i 0){ + r[j++] = a[i]; + if (j == n){ + break; + } + } + } + return r; + + } else { + return a; + } + } + + return null; + } + + + /** + * return an [optional] id part of a property value (all that follows the first '@') + */ + String getIdPart (String key) { + String v = getProperty(key); + if ((v != null) && (v.length() > 0)) { + int i = v.indexOf('@'); + if (i >= 0){ + return v.substring(i+1); + } + } + + return null; + } + + public Class asClass (String v) throws JPFConfigException { + if ((v != null) && (v.length() > 0)) { + v = stripId(v); + v = expandClassName(v); + try { + return loader.loadClass(v); + } catch (ClassNotFoundException cfx) { + throw new JPFConfigException("class not found " + v + " by classloader: " + loader); + } catch (ExceptionInInitializerError ix) { + throw new JPFConfigException("class initialization of " + v + " failed: " + ix, + ix); + } + } + + return null; + } + + public Class getClass(String key, Class type) throws JPFConfigException { + Class cls = asClass( getProperty(key)); + if (cls != null) { + if (type.isAssignableFrom(cls)) { + return cls.asSubclass(type); + } else { + throw new JPFConfigException("classname entry for: \"" + key + "\" not of type: " + type.getName()); + } + } + return null; + } + + + public Class getClass(String key) throws JPFConfigException { + return asClass( getProperty(key)); + } + + public Class getEssentialClass(String key) throws JPFConfigException { + Class cls = getClass(key); + if (cls == null) { + throw new JPFConfigException("no classname entry for: \"" + key + "\""); + } + + return cls; + } + + String stripId (String v) { + int i = v.indexOf('@'); + if (i >= 0) { + return v.substring(0,i); + } else { + return v; + } + } + + String getId (String v){ + int i = v.indexOf('@'); + if (i >= 0) { + return v.substring(i+1); + } else { + return null; + } + } + + String expandClassName (String clsName) { + if (clsName != null && clsName.length() > 0 && clsName.charAt(0) == '.') { + return "gov.nasa.jpf" + clsName; + } else { + return clsName; + } + } + + + public Class[] getClasses(String key) throws JPFConfigException { + String[] v = getStringArray(key); + if (v != null) { + int n = v.length; + Class[] a = new Class[n]; + for (int i = 0; i < n; i++) { + String clsName = expandClassName(v[i]); + if (clsName != null && clsName.length() > 0){ + try { + clsName = stripId(clsName); + a[i] = loader.loadClass(clsName); + } catch (ClassNotFoundException cnfx) { + throw new JPFConfigException("class not found " + v[i]); + } catch (ExceptionInInitializerError ix) { + throw new JPFConfigException("class initialization of " + v[i] + " failed: " + ix, ix); + } + } + } + + return a; + } + + return null; + } + + /** + * this one is used to instantiate objects from a list of keys that share + * the same prefix, e.g. + * + * shell.panels = config,site + * shell.panels.site = .shell.panels.SitePanel + * shell.panels.config = .shell.panels.ConfigPanel + * ... + * + * note that we specify default class names, not classes, so that the classes + * get loaded through our own loader at call time (they might not be visible + * to our caller) + */ + public T[] getGroupInstances (String keyPrefix, String keyPostfix, Class type, + String... defaultClsNames) throws JPFConfigException { + + String[] ids = getCompactTrimmedStringArray(keyPrefix); + + if (ids.length > 0){ + keyPrefix = keyPrefix + '.'; + T[] arr = (T[]) Array.newInstance(type, ids.length); + + for(int i = 0; i < ids.length; i++){ + String key = keyPrefix + ids[i]; + if (keyPostfix != null){ + key = key + keyPostfix; + } + arr[i] = getEssentialInstance(key, type); + } + + return arr; + + } else { + T[] arr = (T[]) Array.newInstance(type, defaultClsNames.length); + + for (int i=0; i - that's kind of kludged together, not very efficient + String[] getIds (String key) { + String v = getProperty(key); + + if (v != null) { + int i = v.indexOf('@'); + if (i >= 0) { // Ok, we have ids + String[] a = split(v); + String[] ids = new String[a.length]; + for (i = 0; i ArrayList getInstances(String key, Class type) throws JPFConfigException { + + Class[] argTypes = { Config.class }; + Object[] args = { this }; + + return getInstances(key,type,argTypes,args); + } + + public ArrayList getInstances(String key, Class type, Class[]argTypes, Object[] args) + throws JPFConfigException { + Class[] c = getClasses(key); + + if (c != null) { + String[] ids = getIds(key); + + ArrayList a = new ArrayList(c.length); + + for (int i = 0; i < c.length; i++) { + String id = (ids != null) ? ids[i] : null; + T listener = getInstance(key, c[i], type, argTypes, args, id); + if (listener != null) { + a.add( listener); + } else { + // should report here + } + } + + return a; + + } else { + // should report here + } + + return null; + } + + public T getInstance(String key, Class type, String defClsName) throws JPFConfigException { + Class[] argTypes = CONFIG_ARGTYPES; + Object[] args = CONFIG_ARGS; + + Class cls = getClass(key); + String id = getIdPart(key); + + if (cls == null) { + try { + cls = loader.loadClass(defClsName); + } catch (ClassNotFoundException cfx) { + throw new JPFConfigException("class not found " + defClsName); + } catch (ExceptionInInitializerError ix) { + throw new JPFConfigException("class initialization of " + defClsName + " failed: " + ix, ix); + } + } + + return getInstance(key, cls, type, argTypes, args, id); + } + + public T getInstance(String key, Class type) throws JPFConfigException { + Class[] argTypes = CONFIG_ARGTYPES; + Object[] args = CONFIG_ARGS; + + return getInstance(key, type, argTypes, args); + } + + public T getInstance(String key, Class type, Class[] argTypes, + Object[] args) throws JPFConfigException { + Class cls = getClass(key); + String id = getIdPart(key); + + if (cls != null) { + return getInstance(key, cls, type, argTypes, args, id); + } else { + return null; + } + } + + public T getInstance(String key, Class type, Object arg1, Object arg2) throws JPFConfigException { + Class[] argTypes = new Class[2]; + argTypes[0] = arg1.getClass(); + argTypes[1] = arg2.getClass(); + + Object[] args = new Object[2]; + args[0] = arg1; + args[1] = arg2; + + return getInstance(key, type, argTypes, args); + } + + + public T getEssentialInstance(String key, Class type) throws JPFConfigException { + Class[] argTypes = { Config.class }; + Object[] args = { this }; + return getEssentialInstance(key, type, argTypes, args); + } + + /** + * just a convenience method for ctor calls that take two arguments + */ + public T getEssentialInstance(String key, Class type, Object arg1, Object arg2) throws JPFConfigException { + Class[] argTypes = new Class[2]; + argTypes[0] = arg1.getClass(); + argTypes[1] = arg2.getClass(); + + Object[] args = new Object[2]; + args[0] = arg1; + args[1] = arg2; + + return getEssentialInstance(key, type, argTypes, args); + } + + public T getEssentialInstance(String key, Class type, Class[] argTypes, Object[] args) throws JPFConfigException { + Class cls = getEssentialClass(key); + String id = getIdPart(key); + + return getInstance(key, cls, type, argTypes, args, id); + } + + public T getInstance (String id, String clsName, Class type, Class[] argTypes, Object[] args) throws JPFConfigException { + Class cls = asClass(clsName); + + if (cls != null) { + return getInstance(id, cls, type, argTypes, args, id); + } else { + return null; + } + } + + public T getInstance (String id, String clsName, Class type) throws JPFConfigException { + Class[] argTypes = CONFIG_ARGTYPES; + Object[] args = CONFIG_ARGS; + + Class cls = asClass(clsName); + + if (cls != null) { + return getInstance(id, cls, type, argTypes, args, id); + } else { + return null; + } + } + + /** + * this is our private instantiation workhorse - try to instantiate an object of + * class 'cls' by using the following ordered set of ctors 1. ( + * ) 2. (Config) 3. () if all of that fails, or there was + * a 'type' provided the instantiated object does not comply with, return null + */ + T getInstance(String key, Class cls, Class type, Class[] argTypes, + Object[] args, String id) throws JPFConfigException { + Object o = null; + Constructor ctor = null; + + if (cls == null) { + return null; + } + + if (id != null) { // check first if we already have this one instantiated as a singleton + if (singletons == null) { + singletons = new HashMap(); + } else { + o = type.cast(singletons.get(id)); + } + } + + while (o == null) { + try { + ctor = cls.getConstructor(argTypes); + o = ctor.newInstance(args); + } catch (NoSuchMethodException nmx) { + + if ((argTypes.length > 1) || ((argTypes.length == 1) && (argTypes[0] != Config.class))) { + // fallback 1: try a single Config param + argTypes = CONFIG_ARGTYPES; + args = CONFIG_ARGS; + + } else if (argTypes.length > 0) { + // fallback 2: try the default ctor + argTypes = NO_ARGTYPES; + args = NO_ARGS; + + } else { + // Ok, there is no suitable ctor, bail out + throw new JPFConfigException(key, cls, "no suitable ctor found"); + } + } catch (IllegalAccessException iacc) { + throw new JPFConfigException(key, cls, "\n> ctor not accessible: " + + getMethodSignature(ctor)); + } catch (IllegalArgumentException iarg) { + throw new JPFConfigException(key, cls, "\n> illegal constructor arguments: " + + getMethodSignature(ctor)); + } catch (InvocationTargetException ix) { + Throwable tx = ix.getTargetException(); + if (tx instanceof JPFConfigException) { + throw new JPFConfigException(tx.getMessage() + "\n> used within \"" + key + + "\" instantiation of " + cls); + } else { + throw new JPFConfigException(key, cls, "\n> exception in " + + getMethodSignature(ctor) + ":\n>> " + tx, tx); + } + } catch (InstantiationException ivt) { + throw new JPFConfigException(key, cls, + "\n> abstract class cannot be instantiated"); + } catch (ExceptionInInitializerError eie) { + throw new JPFConfigException(key, cls, "\n> static initialization failed:\n>> " + + eie.getException(), eie.getException()); + } + } + + // check type + if (!type.isInstance(o)) { + throw new JPFConfigException(key, cls, "\n> instance not of type: " + + type.getName()); + } + + if (id != null) { // add to singletons (in case it's not already in there) + singletons.put(id, o); + } + + return type.cast(o); // safe according to above + } + + public String getMethodSignature(Constructor ctor) { + StringBuilder sb = new StringBuilder(ctor.getName()); + sb.append('('); + Class[] argTypes = ctor.getParameterTypes(); + for (int i = 0; i < argTypes.length; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(argTypes[i].getName()); + } + sb.append(')'); + return sb.toString(); + } + + public boolean hasValue(String key) { + String v = getProperty(key); + return ((v != null) && (v.length() > 0)); + } + + public boolean hasValueIgnoreCase(String key, String value) { + String v = getProperty(key); + if (v != null) { + return v.equalsIgnoreCase(value); + } + + return false; + } + + public int getChoiceIndexIgnoreCase(String key, String[] choices) { + String v = getProperty(key); + + if ((v != null) && (choices != null)) { + for (int i = 0; i < choices.length; i++) { + if (v.equalsIgnoreCase(choices[i])) { + return i; + } + } + } + + return -1; + } + + public URL getURL (String key){ + String v = getProperty(key); + if (v != null) { + try { + return FileUtils.getURL(v); + } catch (Throwable x){ + throw exception("malformed URL: " + v); + } + } else { + return null; + } + } + + public File[] getPathArray (String key) { + String v = getProperty(key); + if (v != null) { + String[] pe = removeEmptyStrings( pathSplit(v)); + + if (pe != null && pe.length > 0) { + File[] files = new File[pe.length]; + for (int i=0; i elements = new ArrayList(); + boolean quote = false; + + char[] buf = new char[128]; + int k=0; + + for (int i=0; i= buf.length){ + char[] newBuf = new char[buf.length+128]; + System.arraycopy(buf, 0, newBuf, 0, k); + buf = newBuf; + } + buf[k++] = c; + quote = false; + } + + if (k>0){ + elements.add( new String(buf, 0, k)); + } + + return elements.toArray(new String[elements.size()]); + } + + static final String UNINITIALIZED = "uninitialized"; + // this is where we store the initial values in case we have to recollect + String initialNativeClasspath = UNINITIALIZED, + initialClasspath = UNINITIALIZED, + initialSourcepath = UNINITIALIZED, + initialPeerPackages = UNINITIALIZED, + initialNativeLibraries = UNINITIALIZED; + + + /** + * this resets to what was explicitly set in the config files + */ + public void resetGlobalPaths() { + if (initialNativeClasspath == UNINITIALIZED){ + initialNativeClasspath = getString("native_classpath"); + } else { + put0( "native_classpath", initialNativeClasspath); + } + + if (initialClasspath == UNINITIALIZED){ + initialClasspath = getString("classpath"); + } else { + put0( "classpath", initialClasspath); + } + + if (initialSourcepath == UNINITIALIZED){ + initialSourcepath = getString("sourcepath"); + } else { + put0( "sourcepath", initialSourcepath); + } + + if (initialPeerPackages == UNINITIALIZED){ + initialPeerPackages = getString("peer_packages"); + } else { + put0( "peer_packages", initialPeerPackages); + } + + if (initialNativeLibraries == UNINITIALIZED){ + initialNativeLibraries = getString("native_libraries"); + } else { + put0( "native_libraries", initialNativeLibraries); + } + } + + /** + * collect all the .{native_classpath,classpath,sourcepath,peer_packages,native_libraries} + * and append them to the global settings + * + * NOTE - this is now called from within initClassLoader, which should only happen once and + * is the first time we really need the global paths. + * + * <2do> this is Ok for native_classpath and native_libraries, but we should probably do + * classpath, sourcepath and peer_packages separately (they can be collected later) + */ + public void collectGlobalPaths() { + + // note - this is in the order of entry, i.e. reflects priorities + // we have to process this in reverse order so that later entries are prioritized + String[] keys = getEntrySequence(); + + String nativeLibKey = "." + System.getProperty("os.name") + + '.' + System.getProperty("os.arch") + ".native_libraries"; + + for (int i = keys.length-1; i>=0; i--){ + String k = keys[i]; + if (k.endsWith(".native_classpath")){ + appendPath("native_classpath", k); + + } else if (k.endsWith(".classpath")){ + appendPath("classpath", k); + + } else if (k.endsWith(".sourcepath")){ + appendPath("sourcepath", k); + + } else if (k.endsWith("peer_packages")){ + append("peer_packages", getString(k), ","); + + } else if (k.endsWith(nativeLibKey)){ + appendPath("native_libraries", k); + } + } + } + + + static Pattern absPath = Pattern.compile("(?:[a-zA-Z]:)?[/\\\\].*"); + + void appendPath (String pathKey, String key){ + String projName = key.substring(0, key.indexOf('.')); + String pathPrefix = null; + + if (projName.isEmpty()){ + pathPrefix = new File(".").getAbsolutePath(); + } else { + pathPrefix = getString(projName); + } + + if (pathPrefix != null){ + pathPrefix += '/'; + + String[] elements = getCompactStringArray(key); + if (elements != null){ + for (String e : elements) { + if (e != null && e.length()>0){ + + // if this entry is not an absolute path, or doesn't start with + // the project path, prepend the project path + if (!(absPath.matcher(e).matches()) && !e.startsWith(pathPrefix)) { + e = pathPrefix + e; + } + + append(pathKey, e); + } + } + } + + } else { + //throw new JPFConfigException("no project path for " + key); + } + } + + + //--- our modification interface + + /** + * iterate over all keys, if a key starts with the provided keyPrefix, add + * this value under the corresponding key suffix. For example: + * + * test.report.console.finished = result + * + * -> prompotePropertyCategory("test.") -> + * + * report.console.finished = result + * + * if a matching key has an IGNORE_VALUE value ("-"), the entry is *not* promoted + * (we need this to override promoted keys) + */ + public void promotePropertyCategory (String keyPrefix){ + int prefixLen = keyPrefix.length(); + + // HashTable does not support adding elements while iterating over the entrySet + ArrayList> promoted = null; + + for (Map.Entry e : entrySet()){ + Object k = e.getKey(); + if (k instanceof String){ + String key = (String)k; + if (key.startsWith(keyPrefix)){ + Object v = e.getValue(); + if (! IGNORE_VALUE.equals(v)){ + if (promoted == null){ + promoted = new ArrayList>(); + } + promoted.add(e); + } + } + } + } + + if (promoted != null){ + for (Map.Entry e : promoted) { + String key = (String) e.getKey(); + key = key.substring(prefixLen); + + put(key, e.getValue()); + } + } + } + + + @Override + public Object setProperty (String key, String newValue) { + Object oldValue = put(key, newValue); + notifyPropertyChangeListeners(key, (String)oldValue, newValue); + return oldValue; + } + + public void parse (String s) { + + int i = s.indexOf("="); + if (i > 0) { + String key, val; + + if (i > 1 && s.charAt(i-1)=='+') { // append + key = s.substring(0, i-1).trim(); + val = s.substring(i+1); // it's going to be normalized anyways + append(key, val); + + } else { // put + key = s.substring(0, i).trim(); + val = s.substring(i+1); + setProperty(key, val); + } + + } + } + + protected void notifyPropertyChangeListeners (String key, String oldValue, String newValue) { + if (changeListeners != null) { + for (ConfigChangeListener l : changeListeners) { + l.propertyChanged(this, key, oldValue, newValue); + } + } + } + + public String[] asStringArray (String s){ + return split(s); + } + + public TreeMap asOrderedMap() { + TreeMap map = new TreeMap(); + map.putAll(this); + return map; + } + + //--- various debugging methods + + public void print (PrintWriter pw) { + pw.println("----------- Config contents"); + + // just how much do you have to do to get a printout with keys in alphabetical order :< + TreeSet kset = new TreeSet(); + for (Enumeration e = propertyNames(); e.hasMoreElements();) { + Object k = e.nextElement(); + if (k instanceof String) { + kset.add( (String)k); + } + } + + for (String key : kset) { + String val = getProperty(key); + pw.print(key); + pw.print(" = "); + pw.println(val); + } + + pw.flush(); + } + + public void printSources (PrintWriter pw) { + pw.println("----------- Config sources"); + for (Object src : sources){ + pw.println(src); + } + } + + public void printEntries() { + PrintWriter pw = new PrintWriter(System.out); + print(pw); + } + + public String getSourceName (Object src){ + if (src instanceof File){ + return ((File)src).getAbsolutePath(); + } else if (src instanceof URL){ + return ((URL)src).toString(); + } else { + return src.toString(); + } + } + + public List getSources() { + return sources; + } + + public void printStatus(Logger log) { + int idx = 0; + + for (Object src : sources){ + if (src instanceof File){ + log.config("configuration source " + idx++ + " : " + getSourceName(src)); + } + } + } + + +} diff --git a/src/main/gov/nasa/jpf/ConfigChangeListener.java b/src/main/gov/nasa/jpf/ConfigChangeListener.java new file mode 100644 index 0000000..24a3cfc --- /dev/null +++ b/src/main/gov/nasa/jpf/ConfigChangeListener.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +/** + * listener for gov.nasa.jpf.Config changes. Implementors + * can register themselves upon initialization, to react to + * downstream changes even if they cache or process Config + * settings for increased performance. + * + * the notification is per-key + */ +public interface ConfigChangeListener { + + /** + * a JPF property was changed during runtime (e.g. by using the Verify API + * or encountering annotations) + */ + void propertyChanged (Config conf, String key, String oldValue, String newValue); + + /** + * this can be used to let a config listener remove itself, which is + * required if the same Config object is used for several JPF runs + */ + void jpfRunTerminated (Config conf); +} diff --git a/src/main/gov/nasa/jpf/Error.java b/src/main/gov/nasa/jpf/Error.java new file mode 100644 index 0000000..39f3eb8 --- /dev/null +++ b/src/main/gov/nasa/jpf/Error.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.vm.Path; +import gov.nasa.jpf.vm.ThreadList; + +/** + * class used to store property violations (property and path) + */ +public class Error { + + int id; + + Property property; + private String errorMessage; + + private Path path; + ThreadList threadList; + + public Error (int id, Property prop, Path p, ThreadList l) { + this.id = id; + property = prop; + errorMessage = prop.getErrorMessage(); + path = p; // client has to clone in case we go on + threadList = l; + } + + public int getId() { + return id; + } + + public String getDescription () { + StringBuilder sb = new StringBuilder(); + sb.append(property.getClass().getName()); + + String s = property.getExplanation(); + if (s != null) { + sb.append(" (\""); + sb.append(s); + sb.append("\")"); + } + + return sb.toString(); + } + + public String getDetails() { + return errorMessage; + } + + public Path getPath () { + return path; + } + + public Property getProperty () { + return property; + } +} diff --git a/src/main/gov/nasa/jpf/GenericProperty.java b/src/main/gov/nasa/jpf/GenericProperty.java new file mode 100644 index 0000000..b2eaffb --- /dev/null +++ b/src/main/gov/nasa/jpf/GenericProperty.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.VM; + +import java.io.PrintWriter; + +/** + * generic abstract base class implementing program properties. This is mostly + * a convenience construct that implements error printout, so that only + * the check itself has to be provided + * + * <2do> why is this still not an interface ?? + */ +public abstract class GenericProperty implements Property, Cloneable { + @Override + public abstract boolean check (Search search, VM vm); + + protected GenericProperty () { + // nothing yet + } + + @Override + public Property clone() throws CloneNotSupportedException { + return (Property) super.clone(); + } + + @Override + public String getErrorMessage () { + return null; + } + + @Override + public String getExplanation () { + return null; + } + + @Override + public void reset () { + // nothing to do here, but Property implementors that store + // stuff have to override (it's called if search.multiple_errors is on) + } + + @Override + public void printOn (PrintWriter pw) { + pw.println(getErrorMessage()); + } +} diff --git a/src/main/gov/nasa/jpf/JPF.java b/src/main/gov/nasa/jpf/JPF.java new file mode 100644 index 0000000..b4009a5 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPF.java @@ -0,0 +1,731 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.report.Reporter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.search.SearchListener; +import gov.nasa.jpf.tool.RunJPF; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.util.LogManager; +import gov.nasa.jpf.util.Misc; +import gov.nasa.jpf.util.RunRegistry; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.NoOutOfMemoryErrorProperty; +import gov.nasa.jpf.vm.VMListener; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + + +/** + * main class of the JPF verification framework. This reads the configuration, + * instantiates the Search and VM objects, and kicks off the Search + */ +public class JPF implements Runnable { + + public static String VERSION = "8.0"; // the major version number + + static Logger logger = null; // initially + + public enum Status { NEW, RUNNING, DONE }; + + class ConfigListener implements ConfigChangeListener { + + /** + * check for new listeners that are dynamically configured + */ + @Override + public void propertyChanged(Config config, String key, String oldValue, String newValue) { + if ("listener".equals(key)) { + if (oldValue == null) + oldValue = ""; + + String[] nv = config.asStringArray(newValue); + String[] ov = config.asStringArray(oldValue); + String[] newListeners = Misc.getAddedElements(ov, nv); + Class[] argTypes = { Config.class, JPF.class }; // Many listeners have 2 parameter constructors + Object[] args = {config, JPF.this }; + + if (newListeners != null) { + for (String clsName : newListeners) { + try { + JPFListener newListener = config.getInstance("listener", clsName, JPFListener.class, argTypes, args); + addListener(newListener); + logger.info("config changed, added listener " + clsName); + + } catch (JPFConfigException cfx) { + logger.warning("listener change failed: " + cfx.getMessage()); + } + } + } + } + } + + /** + * clean up to avoid a sublte but serious memory leak when using the + * same config for multiple JPF objects/runs - this listener is an inner + * class object that keeps its encapsulating JPF instance alive + */ + @Override + public void jpfRunTerminated(Config config){ + config.removeChangeListener(this); + } + } + + /** this is the backbone of all JPF configuration */ + Config config; + + /** The search policy used to explore the state space */ + Search search; + + /** Reference to the virtual machine used by the search */ + VM vm; + + /** the report generator */ + Reporter reporter; + + Status status = Status.NEW; + + /** a list of listeners that get automatically added from VM, Search or Reporter initialization */ + List pendingVMListeners; + List pendingSearchListeners; + + + /** we use this as safety margin, to be released upon OutOfMemoryErrors */ + byte[] memoryReserve; + + private static Logger initLogging(Config conf) { + LogManager.init(conf); + return getLogger("gov.nasa.jpf"); + } + + /** + * use this one to get a Logger that is initialized via our Config mechanism. Note that + * our own Loggers do NOT pass + */ + public static JPFLogger getLogger (String name) { + return LogManager.getLogger( name); + } + + public static void main(String[] args){ + int options = RunJPF.getOptions(args); + + if (args.length == 0 || RunJPF.isOptionEnabled( RunJPF.HELP,options)) { + RunJPF.showUsage(); + return; + } + if (RunJPF.isOptionEnabled( RunJPF.ADD_PROJECT,options)){ + RunJPF.addProject(args); + return; + } + + if (RunJPF.isOptionEnabled( RunJPF.BUILD_INFO,options)){ + RunJPF.showBuild(RunJPF.class.getClassLoader()); + } + + if (RunJPF.isOptionEnabled( RunJPF.LOG,options)){ + Config.enableLogging(true); + } + + Config conf = createConfig(args); + + if (RunJPF.isOptionEnabled( RunJPF.SHOW, options)) { + conf.printEntries(); + } + + start(conf, args); + } + + public static void start(Config conf, String[] args){ + // this is redundant to jpf.report..start=..config.. + // but nobody can remember this (it's only used to produce complete reports) + + if (logger == null) { + logger = initLogging(conf); + } + + if (!checkArgs(args)){ + return; + } + + setNativeClassPath(conf); // in case we have to find a shell + + // check if there is a shell class specification, in which case we just delegate + JPFShell shell = conf.getInstance("shell", JPFShell.class); + if (shell != null) { + shell.start(args); // responsible for exception handling itself + + } else { + // no shell, we start JPF directly + LogManager.printStatus(logger); + conf.printStatus(logger); + + // this has to be done after we checked&consumed all "-.." arguments + // this is NOT about checking properties! + checkUnknownArgs(args); + + try { + JPF jpf = new JPF(conf); + jpf.run(); + + } catch (ExitException x) { + logger.severe( "JPF terminated"); + + // this is how we get most runtime config exceptions + if (x.shouldReport()) { + x.printStackTrace(); + } + + /** + Throwable cause = x.getCause(); + if ((cause != null) && conf.getBoolean("pass_exceptions", false)) { + cause.fillInStackTrace(); + throw cause; + } + **/ + + } catch (JPFException jx) { + logger.severe( "JPF exception, terminating: " + jx.getMessage()); + if (conf.getBoolean("jpf.print_exception_stack")) { + + Throwable cause = jx.getCause(); + if (cause != null && cause != jx){ + cause.printStackTrace(); + } else { + jx.printStackTrace(); + } + } + // pass this on, caller has to handle + throw jx; + } + } + } + + + static void setNativeClassPath(Config config) { + if (!config.hasSetClassLoader()) { + config.initClassLoader( JPF.class.getClassLoader()); + } + } + + + protected JPF (){ + // just to support unit test mockups + } + + /** + * create new JPF object. Note this is always guaranteed to return, but the + * Search and/or VM object instantiation might have failed (i.e. the JPF + * object might not be really usable). If you directly use getSearch() / getVM(), + * check for null + */ + public JPF(Config conf) { + config = conf; + + setNativeClassPath(config); // before we do anything else + + if (logger == null) { // maybe somebody created a JPF object explicitly + logger = initLogging(config); + } + + initialize(); + } + + /** + * convenience method if caller doesn't care about Config + */ + public JPF (String ... args) { + this( createConfig(args)); + } + + private void initialize() { + VERSION = config.getString("jpf.version", VERSION); + memoryReserve = new byte[config.getInt("jpf.memory_reserve", 64 * 1024)]; // in bytes + + try { + + Class[] vmArgTypes = { JPF.class, Config.class }; + Object[] vmArgs = { this, config }; + vm = config.getEssentialInstance("vm.class", VM.class, vmArgTypes, vmArgs); + + Class[] searchArgTypes = { Config.class, VM.class }; + Object[] searchArgs = { config, vm }; + search = config.getEssentialInstance("search.class", Search.class, + searchArgTypes, searchArgs); + + // although the Reporter will always be notified last, this has to be set + // first so that it can register utility listeners like Statistics that + // can be used by configured listeners + Class[] reporterArgTypes = { Config.class, JPF.class }; + Object[] reporterArgs = { config, this }; + reporter = config.getInstance("report.class", Reporter.class, reporterArgTypes, reporterArgs); + if (reporter != null){ + search.setReporter(reporter); + } + + addListeners(); + + config.addChangeListener(new ConfigListener()); + + } catch (JPFConfigException cx) { + logger.severe(cx.toString()); + //cx.getCause().printStackTrace(); + throw new ExitException(false, cx); + } + } + + + public Status getStatus() { + return status; + } + + public boolean isRunnable () { + return ((vm != null) && (search != null)); + } + + public void addPropertyListener (PropertyListenerAdapter pl) { + if (vm != null) { + vm.addListener( pl); + } + if (search != null) { + search.addListener( pl); + search.addProperty(pl); + } + } + + public void addSearchListener (SearchListener l) { + if (search != null) { + search.addListener(l); + } + } + + protected void addPendingVMListener (VMListener l){ + if (pendingVMListeners == null){ + pendingVMListeners = new ArrayList(); + } + pendingVMListeners.add(l); + } + + protected void addPendingSearchListener (SearchListener l){ + if (pendingSearchListeners == null){ + pendingSearchListeners = new ArrayList(); + } + pendingSearchListeners.add(l); + } + + public void addListener (JPFListener l) { + // the VM is instantiated first + if (l instanceof VMListener) { + if (vm != null) { + vm.addListener( (VMListener) l); + + } else { // no VM yet, we are in VM initialization + addPendingVMListener((VMListener)l); + } + } + + if (l instanceof SearchListener) { + if (search != null) { + search.addListener( (SearchListener) l); + + } else { // no search yet, we are in Search initialization + addPendingSearchListener((SearchListener)l); + } + } + } + + public T getListenerOfType( Class type){ + if (search != null){ + T listener = search.getNextListenerOfType(type, null); + if (listener != null){ + return listener; + } + } + + if (vm != null){ + T listener = vm.getNextListenerOfType(type, null); + if (listener != null){ + return listener; + } + } + + return null; + } + + public boolean addUniqueTypeListener (JPFListener l) { + boolean addedListener = false; + Class cls = l.getClass(); + + if (l instanceof VMListener) { + if (vm != null) { + if (!vm.hasListenerOfType(cls)) { + vm.addListener( (VMListener) l); + addedListener = true; + } + } + } + if (l instanceof SearchListener) { + if (search != null) { + if (!search.hasListenerOfType(cls)) { + search.addListener( (SearchListener) l); + addedListener = true; + } + } + } + + return addedListener; + } + + + public void removeListener (JPFListener l){ + if (l instanceof VMListener) { + if (vm != null) { + vm.removeListener( (VMListener) l); + } + } + if (l instanceof SearchListener) { + if (search != null) { + search.removeListener( (SearchListener) l); + } + } + } + + public void addVMListener (VMListener l) { + if (vm != null) { + vm.addListener(l); + } + } + + public void addSearchProperty (Property p) { + if (search != null) { + search.addProperty(p); + } + } + + /** + * this is called after vm, search and reporter got instantiated + */ + void addListeners () { + Class[] argTypes = { Config.class, JPF.class }; + Object[] args = { config, this }; + + // first listeners that were automatically added from VM, Search and Reporter initialization + if (pendingVMListeners != null){ + for (VMListener l : pendingVMListeners) { + vm.addListener(l); + } + pendingVMListeners = null; + } + + if (pendingSearchListeners != null){ + for (SearchListener l : pendingSearchListeners) { + search.addListener(l); + } + pendingSearchListeners = null; + } + + // and finally everything that's user configured + List listeners = config.getInstances("listener", JPFListener.class, argTypes, args); + if (listeners != null) { + for (JPFListener l : listeners) { + addListener(l); + } + } + } + + public Reporter getReporter () { + return reporter; + } + + public boolean addPublisherExtension (Class pCls, PublisherExtension e) { + if (reporter != null) { + return reporter.addPublisherExtension(pCls, e); + } + return false; + } + + public void setPublisherItems (Class pCls, + int category, String[] topics) { + if (reporter != null) { + reporter.setPublisherItems(pCls, category, topics); + } + } + + + public Config getConfig() { + return config; + } + + /** + * return the search object. This can be null if the initialization has failed + */ + public Search getSearch() { + return search; + } + + /** + * return the VM object. This can be null if the initialization has failed + */ + public VM getVM() { + return vm; + } + + public static void exit() { + // Hmm, exception as non local return. But we might be called from a + // context we don't want to kill + throw new ExitException(); + } + + public boolean foundErrors() { + return !(search.getErrors().isEmpty()); + } + + /** + * this assumes that we have checked and 'consumed' (nullified) all known + * options, so we just have to check for any '-' option prior to the + * target class name + */ + static void checkUnknownArgs (String[] args) { + for ( int i=0; i 0) { + s = arg.substring(idx+1); + if (consume) { + args[i]=null; + } + } else if (i < args.length-1) { + s = args[i+1]; + if (consume) { + args[i] = null; + args[i+1] = null; + } + } + break; + } + } + } + } + + return s; + } + + /** + * what property file to look for + */ + static String getConfigFileName (String[] args) { + if (args.length > 0) { + // check if the last arg is a mode property file + // if yes, it has to include a 'target' spec + int idx = args.length-1; + String lastArg = args[idx]; + if (lastArg.endsWith(".jpf") || lastArg.endsWith(".properties")) { + if (lastArg.startsWith("-c")) { + int i = lastArg.indexOf('='); + if (i > 0) { + lastArg = lastArg.substring(i+1); + } + } + args[idx] = null; + return lastArg; + } + } + + return getArg(args, "-c(onfig)?(=.+)?", "jpf.properties", true); + } + + /** + * return a Config object that holds the JPF options. This first + * loads the properties from a (potentially configured) properties file, and + * then overlays all command line arguments that are key/value pairs + */ + public static Config createConfig (String[] args) { + return new Config(args); + } + + /** + * runs the verification. + */ + @Override + public void run() { + Runtime rt = Runtime.getRuntime(); + + // this might be executed consecutively, so notify everybody + RunRegistry.getDefaultRegistry().reset(); + + if (isRunnable()) { + try { + if (vm.initialize()) { + status = Status.RUNNING; + search.search(); + } + } catch (OutOfMemoryError oom) { + + // try to get memory back before we do anything that makes it worse + // (note that we even try to avoid calls here, we are on thin ice) + + // NOTE - we don't try to recover at this point (that is what we do + // if we fall below search.min_free within search()), we only want to + // terminate gracefully (incl. report) + + memoryReserve = null; // release something + long m0 = rt.freeMemory(); + long d = 10000; + + // see if we can reclaim some memory before logging or printing statistics + for (int i=0; i<10; i++) { + rt.gc(); + long m1 = rt.freeMemory(); + if ((m1 <= m0) || ((m1 - m0) < d)) { + break; + } + m0 = m1; + } + + logger.severe("JPF out of memory"); + + // that's questionable, but we might want to see statistics / coverage + // to know how far we got. We don't inform any other listeners though + // if it throws an exception we bail - we can't handle it w/o memory + try { + search.notifySearchConstraintHit("JPF out of memory"); + search.error(new NoOutOfMemoryErrorProperty()); // JUnit tests will succeed if OOM isn't flagged. + reporter.searchFinished(search); + } catch (Throwable t){ + throw new JPFListenerException("exception during out-of-memory termination", t); + } + + // NOTE - this is not an exception firewall anymore + + } finally { + status = Status.DONE; + + config.jpfRunTerminated(); + cleanUp(); + } + } + } + + protected void cleanUp(){ + search.cleanUp(); + vm.cleanUp(); + reporter.cleanUp(); + } + + public List getSearchErrors () { + if (search != null) { + return search.getErrors(); + } + + return null; + } + + public Error getLastError () { + if (search != null) { + return search.getLastError(); + } + + return null; + } + + + // some minimal sanity checks + static boolean checkArgs (String[] args){ + String lastArg = args[args.length-1]; + if (lastArg != null && lastArg.endsWith(".jpf")){ + if (!new File(lastArg).isFile()){ + logger.severe("application property file not found: " + lastArg); + return false; + } + } + + return true; + } + + public static void handleException(JPFException e) { + logger.severe(e.getMessage()); + exit(); + } + + /** + * private helper class for local termination of JPF (without killing the + * whole Java process via System.exit). + * While this is basically a bad non-local goto exception, it seems to be the + * least of evils given the current JPF structure, and the need to terminate + * w/o exiting the whole Java process. If we just do a System.exit(), we couldn't + * use JPF in an embedded context + */ + @SuppressWarnings("serial") + public static class ExitException extends RuntimeException { + boolean report = true; + + ExitException() {} + + ExitException (boolean report, Throwable cause){ + super(cause); + + this.report = report; + } + + ExitException(String msg) { + super(msg); + } + + public boolean shouldReport() { + return report; + } + } +} diff --git a/src/main/gov/nasa/jpf/JPFClassLoader.java b/src/main/gov/nasa/jpf/JPFClassLoader.java new file mode 100644 index 0000000..d737330 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFClassLoader.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * classloader that is used by Config to instantiate from JPF configured + * paths. This is a standard parent-first loader to avoid multiple class + * instances when using our Run*.jar tools + * + * The main reason for having our own classloader is dynamically configured resource + * and library lookup + */ +public class JPFClassLoader extends URLClassLoader { + + String[] nativeLibs; + + + static { + //ClassLoader.registerAsParallelCapable(); // for jdk7 + } + + public JPFClassLoader (URL[] urls){ + super(urls); + } + + public JPFClassLoader (URL[] urls, String[] libs, ClassLoader parent){ + super(urls, parent); + + nativeLibs = libs; + } + + @Override + protected String findLibrary (String libBaseName){ + + if (nativeLibs != null){ + String libName = File.separator + System.mapLibraryName(libBaseName); + + for (String libPath : nativeLibs) { + if (libPath.endsWith(libName)) { + return libPath; + } + } + } + + return null; // means VM uses java.library.path to look it up + } + + /** + * we make it public since we add paths dynamically during JPF init + * + * Note this is ignored according to the javadocs if the provided url is already in the classpath. + * We do rely on this feature since me might add jpf.jar several times during bootstrap + */ + @Override + public void addURL (URL url){ + if (url != null){ + super.addURL(url); + } + } + + public void setNativeLibs (String[] libs){ + nativeLibs = libs; + } +} diff --git a/src/main/gov/nasa/jpf/JPFConfigException.java b/src/main/gov/nasa/jpf/JPFConfigException.java new file mode 100644 index 0000000..57e413a --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFConfigException.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +/** + * this class wraps the various exceptions we might encounter during + * initialization and use of Config + */ +public class JPFConfigException extends JPFException { + + public JPFConfigException(String msg) { + super(msg); + } + + public JPFConfigException(String msg, Throwable cause) { + super(msg, cause); + } + + public JPFConfigException(String key, Class cls, String failure) { + super("error instantiating class " + cls.getName() + " for entry \"" + key + "\":" + failure); + } + + public JPFConfigException(String key, Class cls, String failure, Throwable cause) { + this(key, cls, failure); + initCause(cause); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("JPF configuration error: "); + sb.append(getMessage()); + + return sb.toString(); + } +} diff --git a/src/main/gov/nasa/jpf/JPFErrorException.java b/src/main/gov/nasa/jpf/JPFErrorException.java new file mode 100644 index 0000000..b6b0932 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFErrorException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +/** + * internal JPF error + */ +@SuppressWarnings("serial") +public class JPFErrorException extends JPFException { + public JPFErrorException (String s) { + super(s); + } +} diff --git a/src/main/gov/nasa/jpf/JPFException.java b/src/main/gov/nasa/jpf/JPFException.java new file mode 100644 index 0000000..0d89416 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFException.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import java.io.PrintStream; + +/** + * common root for all exceptions thrown by JPF + */ +@SuppressWarnings("serial") +public class JPFException extends RuntimeException { + + public JPFException (String details) { + super(details); + } + + public JPFException (Throwable cause) { + super(cause); + } + + public JPFException (String details, Throwable cause){ + super(details, cause); + } + + @Override + public void printStackTrace (PrintStream out) { + out.println("---------------------- JPF error stack trace ---------------------"); + super.printStackTrace(out); + } + +} diff --git a/src/main/gov/nasa/jpf/JPFListener.java b/src/main/gov/nasa/jpf/JPFListener.java new file mode 100644 index 0000000..d53b491 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFListener.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +/** + * this is just a common root type for VMListeners and SearchListeners. No + * own interface, just a type tag. It's main purpose is to provide some + * typechecks during config-based reflection instantiation + */ +public interface JPFListener { + // see VMListener, SearchListener +} diff --git a/src/main/gov/nasa/jpf/JPFListenerException.java b/src/main/gov/nasa/jpf/JPFListenerException.java new file mode 100644 index 0000000..8517498 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFListenerException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +/** + * JPFException that wraps whatever can go wrong in a listener during notification + */ +public class JPFListenerException extends JPFException { + + public JPFListenerException(String details, Throwable cause) { + super(details, cause); + } + +} diff --git a/src/main/gov/nasa/jpf/JPFNativePeerException.java b/src/main/gov/nasa/jpf/JPFNativePeerException.java new file mode 100644 index 0000000..bd4c168 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFNativePeerException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +/** + * JPFException that wraps whatever can go wrong in a native method + */ +public class JPFNativePeerException extends JPFException { + + public JPFNativePeerException(String details, Throwable cause) { + super(details, cause); + } + +} diff --git a/src/main/gov/nasa/jpf/JPFShell.java b/src/main/gov/nasa/jpf/JPFShell.java new file mode 100644 index 0000000..b8093c6 --- /dev/null +++ b/src/main/gov/nasa/jpf/JPFShell.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +/** + * type that can be used to instantiate and run a JPF object + * Shell objects can be configured via the JPF 'shell' property, and are + * typically JPF user interface implementations + * + * Instantiation and start() call are done from the JPF.main() method + * + * Usually, JPFShell implementors have a (Config) ctor so that they + * don't need to obtain a new Config object. This is the reason for + * using a shell *instance* instead of a static main() method - we cannot + * pass the Config object that was already created by JPF.main() at this point + * into the shell main(), which means we would either have to turn Config + * into a singleton (causing problems for multiple JPF runs), or create a new + * Config object within the shell. Since initialization of Config objects is + * an expensive task with our new bootstrapping, it seems better to pass the + * Config object from JPF.main() (which is done automatically when using + * Config based initialization) + */ +public interface JPFShell { + + void start(String[] args); +} diff --git a/src/main/gov/nasa/jpf/ListenerAdapter.java b/src/main/gov/nasa/jpf/ListenerAdapter.java new file mode 100644 index 0000000..ed470bf --- /dev/null +++ b/src/main/gov/nasa/jpf/ListenerAdapter.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.jvm.ClassFile; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.search.SearchListener; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.VMListener; + +/** + * Adapter class that dummy implements both VMListener and SearchListener interfaces + * Used to ease implementation of listeners that only process a few notifications + */ +public abstract class ListenerAdapter implements VMListener, SearchListener, PublisherExtension { + + //--- the VMListener interface + @Override + public void vmInitialized(VM vm) {} + @Override + public void instructionExecuted(VM vm, ThreadInfo currentThread, Instruction nextInstruction, Instruction executedInstruction) {} + @Override + public void executeInstruction(VM vm, ThreadInfo currentThread, Instruction instructionToExecute) {} + @Override + public void threadStarted(VM vm, ThreadInfo startedThread) {} + @Override + public void threadWaiting (VM vm, ThreadInfo waitingThread) {} + @Override + public void threadNotified (VM vm, ThreadInfo notifiedThread) {} + @Override + public void threadInterrupted (VM vm, ThreadInfo interruptedThread) {} + @Override + public void threadScheduled (VM vm, ThreadInfo scheduledThread) {} + @Override + public void threadBlocked (VM vm, ThreadInfo blockedThread, ElementInfo lock) {} + @Override + public void threadTerminated(VM vm, ThreadInfo terminatedThread) {} + @Override + public void loadClass (VM vm, ClassFile cf) {} + @Override + public void classLoaded(VM vm, ClassInfo loadedClass) {} + @Override + public void objectCreated(VM vm, ThreadInfo currentThread, ElementInfo newObject) {} + @Override + public void objectReleased(VM vm, ThreadInfo currentThread, ElementInfo releasedObject) {} + @Override + public void objectLocked (VM vm, ThreadInfo currentThread, ElementInfo lockedObject) {} + @Override + public void objectUnlocked (VM vm, ThreadInfo currentThread, ElementInfo unlockedObject) {} + @Override + public void objectWait (VM vm, ThreadInfo currentThread, ElementInfo waitingObject) {} + @Override + public void objectNotify (VM vm, ThreadInfo currentThread, ElementInfo notifyingObject) {} + @Override + public void objectNotifyAll (VM vm, ThreadInfo currentThread, ElementInfo notifyingObject) {} + @Override + public void objectExposed (VM vm, ThreadInfo currentThread, ElementInfo fieldOwnerObject, ElementInfo exposedObject) {} + @Override + public void objectShared (VM vm, ThreadInfo currentThread, ElementInfo sharedObject) {} + @Override + public void gcBegin(VM vm) {} + @Override + public void gcEnd(VM vm) {} + @Override + public void exceptionThrown(VM vm, ThreadInfo currentThread, ElementInfo thrownException) {} + @Override + public void exceptionBailout(VM vm, ThreadInfo currentThread) {} + @Override + public void exceptionHandled(VM vm, ThreadInfo currentThread) {} + @Override + public void choiceGeneratorRegistered (VM vm, ChoiceGenerator nextCG, ThreadInfo currentThread, Instruction executedInstruction) {} + @Override + public void choiceGeneratorSet (VM vm, ChoiceGenerator newCG) {} + @Override + public void choiceGeneratorAdvanced (VM vm, ChoiceGenerator currentCG) {} + @Override + public void choiceGeneratorProcessed (VM vm, ChoiceGenerator processedCG) {} + @Override + public void methodEntered (VM vm, ThreadInfo currentThread, MethodInfo enteredMethod) {} + @Override + public void methodExited (VM vm, ThreadInfo currentThread, MethodInfo exitedMethod) {} + + + //--- the SearchListener interface + @Override + public void stateAdvanced(Search search) {} + @Override + public void stateProcessed(Search search) {} + @Override + public void stateBacktracked(Search search) {} + @Override + public void statePurged(Search search) {} + @Override + public void stateStored(Search search) {} + @Override + public void stateRestored(Search search) {} + @Override + public void searchProbed (Search search){} + @Override + public void propertyViolated(Search search) {} + @Override + public void searchStarted(Search search) {} + @Override + public void searchConstraintHit(Search search) {} + @Override + public void searchFinished(Search search) {} + + + //--- PublisherExtension interface + @Override + public void publishStart (Publisher publisher) {} + @Override + public void publishTransition (Publisher publisher) {} + @Override + public void publishPropertyViolation (Publisher publisher) {} + @Override + public void publishConstraintHit (Publisher publisher) {} + @Override + public void publishFinished (Publisher publisher) {} + @Override + public void publishProbe (Publisher publisher) {} + +} diff --git a/src/main/gov/nasa/jpf/Property.java b/src/main/gov/nasa/jpf/Property.java new file mode 100644 index 0000000..ead8073 --- /dev/null +++ b/src/main/gov/nasa/jpf/Property.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.Printable; +import gov.nasa.jpf.vm.VM; + + +/** + * abstraction that is used by Search objects to determine if program + * properties have been violated (e.g. NoUncaughtExceptions) + */ +public interface Property extends Printable { + + /** + * return true if property is NOT violated + */ + boolean check (Search search, VM vm); + + String getErrorMessage (); + + String getExplanation(); + + void reset (); // required for search.multiple_errors + + Property clone() throws CloneNotSupportedException; // so that we can store multiple errors +} diff --git a/src/main/gov/nasa/jpf/PropertyListenerAdapter.java b/src/main/gov/nasa/jpf/PropertyListenerAdapter.java new file mode 100644 index 0000000..88c9a66 --- /dev/null +++ b/src/main/gov/nasa/jpf/PropertyListenerAdapter.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.jvm.ClassFile; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.search.SearchListener; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.VMListener; + +/** + * abstract base class that dummy implements Property, Search- and VMListener methods + * convenient for creating listeners that act as properties, just having to override + * the methods they need + * + * the only local functionality is that instances register themselves automatically + * as property when the search is started + * + * <2do> rewrite once GenericProperty is an interface + */ +public abstract class PropertyListenerAdapter extends GenericProperty implements + SearchListener, VMListener, PublisherExtension { + + //--- Property interface + @Override + public boolean check(Search search, VM vm) { + // return false if property is violated + return true; + } + + @Override + public void reset () { + // override if the property has any local state + } + + @Override + public Property clone() throws CloneNotSupportedException { + return super.clone(); + } + +//--- the VMListener interface + @Override + public void vmInitialized(VM vm) {} + @Override + public void instructionExecuted(VM vm, ThreadInfo currentThread, Instruction nextInstruction, Instruction executedInstruction) {} + @Override + public void executeInstruction(VM vm, ThreadInfo currentThread, Instruction instructionToExecute) {} + @Override + public void threadStarted(VM vm, ThreadInfo startedThread) {} + @Override + public void threadWaiting (VM vm, ThreadInfo waitingThread) {} + @Override + public void threadNotified (VM vm, ThreadInfo notifiedThread) {} + @Override + public void threadInterrupted (VM vm, ThreadInfo interruptedThread) {} + @Override + public void threadScheduled (VM vm, ThreadInfo scheduledThread) {} + @Override + public void threadBlocked (VM vm, ThreadInfo blockedThread, ElementInfo lock) {} + @Override + public void threadTerminated(VM vm, ThreadInfo terminatedThread) {} + @Override + public void loadClass (VM vm, ClassFile cf) {} + @Override + public void classLoaded(VM vm, ClassInfo loadedClass) {} + @Override + public void objectCreated(VM vm, ThreadInfo currentThread, ElementInfo newObject) {} + @Override + public void objectReleased(VM vm, ThreadInfo currentThread, ElementInfo releasedObject) {} + @Override + public void objectLocked (VM vm, ThreadInfo currentThread, ElementInfo lockedObject) {} + @Override + public void objectUnlocked (VM vm, ThreadInfo currentThread, ElementInfo unlockedObject) {} + @Override + public void objectWait (VM vm, ThreadInfo currentThread, ElementInfo waitingObject) {} + @Override + public void objectNotify (VM vm, ThreadInfo currentThread, ElementInfo notifyingObject) {} + @Override + public void objectNotifyAll (VM vm, ThreadInfo currentThread, ElementInfo notifyingObject) {} + @Override + public void objectExposed (VM vm, ThreadInfo currentThread, ElementInfo fieldOwnerObject, ElementInfo exposedObject) {} + @Override + public void objectShared (VM vm, ThreadInfo currentThread, ElementInfo sharedObject) {} + @Override + public void gcBegin(VM vm) {} + @Override + public void gcEnd(VM vm) {} + @Override + public void exceptionThrown(VM vm, ThreadInfo currentThread, ElementInfo thrownException) {} + @Override + public void exceptionBailout(VM vm, ThreadInfo currentThread) {} + @Override + public void exceptionHandled(VM vm, ThreadInfo currentThread) {} + @Override + public void choiceGeneratorRegistered (VM vm, ChoiceGenerator nextCG, ThreadInfo currentThread, Instruction executedInstruction) {} + @Override + public void choiceGeneratorSet (VM vm, ChoiceGenerator newCG) {} + @Override + public void choiceGeneratorAdvanced (VM vm, ChoiceGenerator currentCG) {} + @Override + public void choiceGeneratorProcessed (VM vm, ChoiceGenerator processedCG) {} + @Override + public void methodEntered (VM vm, ThreadInfo currentThread, MethodInfo enteredMethod) {} + @Override + public void methodExited (VM vm, ThreadInfo currentThread, MethodInfo exitedMethod) {} + + + //--- the SearchListener interface + @Override + public void stateAdvanced(Search search) {} + @Override + public void stateProcessed(Search search) {} + @Override + public void stateBacktracked(Search search) {} + @Override + public void statePurged(Search search) {} + @Override + public void stateStored(Search search) {} + @Override + public void stateRestored(Search search) {} + @Override + public void searchProbed (Search search){} + @Override + public void propertyViolated(Search search) {} + @Override + public void searchStarted(Search search) { + search.addProperty(this); + } + @Override + public void searchConstraintHit(Search search) {} + @Override + public void searchFinished(Search search) {} + + + //--- PublisherExtension interface + @Override + public void publishStart (Publisher publisher) {} + @Override + public void publishTransition (Publisher publisher) {} + @Override + public void publishPropertyViolation (Publisher publisher) {} + @Override + public void publishConstraintHit (Publisher publisher) {} + @Override + public void publishFinished (Publisher publisher) {} + @Override + public void publishProbe (Publisher publisher) {} +} diff --git a/src/main/gov/nasa/jpf/State.java b/src/main/gov/nasa/jpf/State.java new file mode 100644 index 0000000..0601584 --- /dev/null +++ b/src/main/gov/nasa/jpf/State.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf; + +import gov.nasa.jpf.search.SearchState; +import gov.nasa.jpf.vm.RestorableVMState; + +/** + * abstraction of JPF execution state that can be queried and stored by + * listeners + */ +public class State { + RestorableVMState vmState; + SearchState searchState; + boolean hasSuccessor; // <2do> pcm - do we really need this? + boolean isNew; + + public State (boolean isNew, boolean hasSuccessor, SearchState searchState, + RestorableVMState vmState) { + this.isNew = isNew; + this.hasSuccessor = hasSuccessor; + this.searchState = searchState; + this.vmState = vmState; + } + + public boolean isNew () { + return isNew; + } + + public SearchState getSearchState () { + return searchState; + } + + public RestorableVMState getVMState () { + return vmState; + } + + public boolean hasSuccessor () { + return hasSuccessor; + } + + public void restore () { + } +} diff --git a/src/main/gov/nasa/jpf/StateExtension.java b/src/main/gov/nasa/jpf/StateExtension.java new file mode 100644 index 0000000..a293b31 --- /dev/null +++ b/src/main/gov/nasa/jpf/StateExtension.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +public interface StateExtension { + +} diff --git a/src/main/gov/nasa/jpf/SystemAttribute.java b/src/main/gov/nasa/jpf/SystemAttribute.java new file mode 100644 index 0000000..189ce8e --- /dev/null +++ b/src/main/gov/nasa/jpf/SystemAttribute.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf; + +/** + * a type tag for attributes used by JPF + * SystemAttributes are protected by the .util.ObjectList API against accidental + * set(..) overwrite, they have to be removed by forceSet(..) + */ +public interface SystemAttribute { + // nothing in here +} diff --git a/src/main/gov/nasa/jpf/jvm/ClassFile.java b/src/main/gov/nasa/jpf/jvm/ClassFile.java new file mode 100644 index 0000000..d3dbdb5 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/ClassFile.java @@ -0,0 +1,2735 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.jvm.JVMByteCodeReader; +import gov.nasa.jpf.vm.ClassParseException; +import gov.nasa.jpf.JPFException; +import gov.nasa.jpf.util.BailOut; +import gov.nasa.jpf.util.BinaryClassSource; + +import java.io.File; + +/** + * class to read and dissect Java classfile contents (as specified by the Java VM + * spec http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#16628 + */ +public class ClassFile extends BinaryClassSource { + + public static final int CONSTANT_UTF8 = 1; + public static final int CONSTANT_INTEGER = 3; + public static final int CONSTANT_FLOAT = 4; + public static final int CONSTANT_LONG = 5; + public static final int CONSTANT_DOUBLE = 6; + public static final int CONSTANT_CLASS = 7; + public static final int CONSTANT_STRING = 8; + public static final int FIELD_REF = 9; + public static final int METHOD_REF = 10; + public static final int INTERFACE_METHOD_REF = 11; + public static final int NAME_AND_TYPE = 12; + public static final int METHOD_HANDLE = 15; + public static final int METHOD_TYPE = 16; + public static final int INVOKE_DYNAMIC = 18; + + public static final int REF_GETFIELD = 1; + public static final int REF_GETSTATIC = 2; + public static final int REF_PUTFIELD = 3; + public static final int REF_PUTSTATIC = 4; + public static final int REF_INVOKEVIRTUAL = 5; + public static final int REF_INVOKESTATIC = 6; + public static final int REF_INVOKESPECIAL = 7; + public static final int REF_NEW_INVOKESPECIAL = 8; + public static final int REF_INVOKEINTERFACE = 9; + + // used to store types in cpValue[] + public static enum CpInfo { + Unused_0, // 0 + ConstantUtf8, // 1 + Unused_2, // 2 + ConstantInteger, // 3 + ConstantFloat, // 4 + ConstantLong, // 5 + ConstantDouble, // 6 + ConstantClass, // 7 + ConstantString, // 8 + FieldRef, // 9 + MethodRef, // 10 + InterfaceMethodRef, // 11 + NameAndType, // 12 + Unused_13, + Unused_14, + MethodHandle, // 15 + MethodType, // 16 + Unused_17, + InvokeDynamic // 18 + } + + // <2do> this is going away + String requestedTypeName; // the type name that caused this classfile to be loaded + + // the const pool + int[] cpPos; // cpPos[i] holds data start index for cp_entry i (0 is unused) + Object[] cpValue; // cpValue[i] hold the String/Integer/Float/Double associated with corresponding cp_entries + + //--- ctors + public ClassFile (byte[] data, int offset){ + super(data,offset); + } + + public ClassFile (byte[] data){ + super(data,0); + } + + public ClassFile (String typeName, byte[] data){ + super(data,0); + + this.requestedTypeName = typeName; + } + + public ClassFile (String typeName, byte[] data, int offset){ + super(data, offset); + + this.requestedTypeName = typeName; + } + + public ClassFile (File file) throws ClassParseException { + super(file); + } + + public ClassFile (String pathName) throws ClassParseException { + super( new File(pathName)); + } + + + + + /** + * set classfile data. This is mainly provided to allow + * on-the-fly classfile instrumentation with 3rd party libraries + * + * BEWARE - like getData(), this method can cause parsing to fail if the + * provided data does not conform to the VM specs. In particular, this + * method should ONLY be called before executing parse(ClassFileReader) and + * will otherwise throw a JPFException + */ + public void setData(byte[] newData){ + if (cpPos != null){ + throw new JPFException("concurrent modification of ClassFile data"); + } + + data = newData; + } + + /** + * return the typename this classfile gets loaded for + * <2do> this is going away + */ + public String getRequestedTypeName(){ + return requestedTypeName; + } + + + //--- general attributes + public static final String SYNTHETIC_ATTR = "Synthetic"; + public static final String DEPRECATED_ATTR = "Deprecated"; + public static final String SIGNATURE_ATTR = "Signature"; + public static final String RUNTIME_INVISIBLE_ANNOTATIONS_ATTR = "RuntimeInvisibleAnnotations"; + public static final String RUNTIME_VISIBLE_ANNOTATIONS_ATTR = "RuntimeVisibleAnnotations"; + public static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR = "RuntimeVisibleTypeAnnotations"; + + //--- standard field attributes + public static final String CONST_VALUE_ATTR = "ConstantValue"; + + protected final static String[] stdFieldAttrs = { + CONST_VALUE_ATTR, SYNTHETIC_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR, + RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR }; + + + //--- standard method attributes + public static final String CODE_ATTR = "Code"; + public static final String EXCEPTIONS_ATTR = "Exceptions"; + public static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR = "RuntimeInvisibleParameterAnnotations"; + public static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR = "RuntimeVisibleParameterAnnotations"; + public static final String ANNOTATIONDEFAULT_ATTR = "AnnotationDefault"; + + protected final static String[] stdMethodAttrs = { + CODE_ATTR, EXCEPTIONS_ATTR, SYNTHETIC_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR, + RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, + RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR, + RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR, + RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR, + ANNOTATIONDEFAULT_ATTR + }; + + + //--- standard code attributes + public static final String LINE_NUMBER_TABLE_ATTR = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE_ATTR = "LocalVariableTable"; + + protected final static String[] stdCodeAttrs = { LINE_NUMBER_TABLE_ATTR, LOCAL_VAR_TABLE_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR }; + + + //--- standard class attributes + public static final String SOURCE_FILE_ATTR = "SourceFile"; + public static final String INNER_CLASSES_ATTR = "InnerClasses"; + public static final String ENCLOSING_METHOD_ATTR = "EnclosingMethod"; + public static final String BOOTSTRAP_METHOD_ATTR = "BootstrapMethods"; + + protected final static String[] stdClassAttrs = { + SOURCE_FILE_ATTR, DEPRECATED_ATTR, INNER_CLASSES_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR, + RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR, + ENCLOSING_METHOD_ATTR, BOOTSTRAP_METHOD_ATTR }; + + + protected String internStdAttrName(int cpIdx, String name, String[] stdNames){ + for (int i=0; i"; + } + } + + public String getTypeName (int typeCode){ + switch(typeCode){ + case 4: return "boolean"; + case 5: return "char"; + case 6: return "float"; + case 7: return "double"; + case 8: return "byte"; + case 9: return "short"; + case 10: return "int"; + case 11: return "long"; + default: + return ""; + } + } + + @Override + public int getPos(){ + return pos; + } + + public int getPc(){ + return pc; + } + + //--- traverse/analyze the const pool (this is rather exotic) + + public int getNumberOfCpEntries(){ + return cpValue.length; + } + + public Object getCpValue (int i){ + return cpValue[i]; + } + + public int getCpTag (int i){ + return data[cpPos[i]]; + } + + /** + * the result can be used as input for u2(dataIndex) + * + * NOTE - this returns -1 for the dreaded unused extra entries associated + * with ConstantDouble and ConstantLong + */ + public int getDataPosOfCpEntry (int i){ + return cpPos[i]; + } + + //--- standard attributes + + public Object getConstValueAttribute(int dataPos){ + int cpIdx = u2(dataPos); + Object v = cpValue[cpIdx]; + return v; + } + + public String getSourceFileAttribute(int dataPos){ + // SourceFile_attribute { u2 attr_name_idx; u4 attr_length; u2 sourcefile_idx; } + + int cpIdx = u2(dataPos + 6); + Object v = cpValue[cpIdx]; + return (String)v; + } + + + //--- low level readers + + public final int u1(int dataIdx){ + return data[dataIdx] & 0xff; + } + + public final int u2(int dataIdx){ + return ((data[dataIdx]&0xff) << 8) | (data[dataIdx+1]&0xff); + } + + public final int i1(int dataIdx) { + return data[dataIdx++]; + } + + public final int i2(int dataIdx) { + int idx = dataIdx; + return (data[idx++] << 8) | (data[idx]&0xff); + } + + public final int readU2(){ + int idx = pos; + pos += 2; + return ((data[idx++]&0xff) << 8) | (data[idx]&0xff); + } + + public final int readI2() { + int idx = pos; + pos += 2; + return (data[idx++] << 8) | (data[idx]&0xff); + } + + public final int readI4(){ + int idx = pos; + pos += 4; + byte[] data = this.data; + + return (data[idx++] <<24) | ((data[idx++]&0xff) << 16) | ((data[idx++]&0xff) << 8) | (data[idx]&0xff); + } + + + //--- reader notifications + private void setClass(ClassFileReader reader, String clsName, String superClsName, int flags, int cpCount) throws ClassParseException { + int p = pos; + reader.setClass( this, clsName, superClsName, flags, cpCount); + pos = p; + } + + private void setInterfaceCount(ClassFileReader reader, int ifcCount){ + int p = pos; + reader.setInterfaceCount( this, ifcCount); + pos = p; + } + private void setInterface(ClassFileReader reader, int ifcIndex, String ifcName){ + int p = pos; + reader.setInterface( this, ifcIndex, ifcName); + pos = p; + } + private void setInterfacesDone(ClassFileReader reader){ + int p = pos; + reader.setInterfacesDone( this); + pos = p; + } + + + private void setFieldCount(ClassFileReader reader, int fieldCount){ + int p = pos; + reader.setFieldCount( this, fieldCount); + pos = p; + + } + private void setField(ClassFileReader reader, int fieldIndex, int accessFlags, String name, String descriptor){ + int p = pos; + reader.setField( this, fieldIndex, accessFlags, name, descriptor); + pos = p; + } + private void setFieldAttributeCount(ClassFileReader reader, int fieldIndex, int attrCount){ + int p = pos; + reader.setFieldAttributeCount( this, fieldIndex, attrCount); + pos = p; + } + private void setFieldAttribute(ClassFileReader reader, int fieldIndex, int attrIndex, String name, int attrLength){ + int p = pos + attrLength; + reader.setFieldAttribute( this, fieldIndex, attrIndex, name, attrLength); + pos = p; + } + private void setFieldAttributesDone(ClassFileReader reader, int fieldIndex){ + int p = pos; + reader.setFieldAttributesDone( this, fieldIndex); + pos = p; + } + private void setFieldDone(ClassFileReader reader, int fieldIndex){ + int p = pos; + reader.setFieldDone( this, fieldIndex); + pos = p; + } + private void setFieldsDone(ClassFileReader reader){ + int p = pos; + reader.setFieldsDone( this); + pos = p; + } + private void setConstantValue(ClassFileReader reader, Object tag, Object value){ + int p = pos; + reader.setConstantValue( this, tag, value); + pos = p; + } + + private void setMethodCount(ClassFileReader reader, int methodCount){ + int p = pos; + reader.setMethodCount( this, methodCount); + pos = p; + } + private void setMethod(ClassFileReader reader, int methodIndex, int accessFlags, String name, String descriptor){ + int p = pos; + reader.setMethod( this, methodIndex, accessFlags, name, descriptor); + pos = p; + } + private void setMethodAttributeCount(ClassFileReader reader, int methodIndex, int attrCount){ + int p = pos; + reader.setMethodAttributeCount( this, methodIndex, attrCount); + pos = p; + } + private void setMethodAttribute(ClassFileReader reader, int methodIndex, int attrIndex, String name, int attrLength){ + int p = pos + attrLength; + reader.setMethodAttribute( this, methodIndex, attrIndex, name, attrLength); + pos = p; + } + private void setMethodAttributesDone(ClassFileReader reader, int methodIndex){ + int p = pos; + reader.setMethodAttributesDone( this, methodIndex); + pos = p; + } + private void setMethodDone(ClassFileReader reader, int methodIndex){ + int p = pos; + reader.setMethodDone( this, methodIndex); + pos = p; + } + private void setMethodsDone(ClassFileReader reader){ + int p = pos; + reader.setMethodsDone( this); + pos = p; + } + private void setExceptionCount(ClassFileReader reader, Object tag, int exceptionCount){ + int p = pos; + reader.setExceptionCount( this, tag, exceptionCount); + pos = p; + } + private void setExceptionsDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setExceptionsDone( this, tag); + pos = p; + } + private void setException(ClassFileReader reader, Object tag, int exceptionIndex, String exceptionType){ + int p = pos; + reader.setException( this, tag, exceptionIndex, exceptionType); + pos = p; + } + private void setCode(ClassFileReader reader, Object tag, int maxStack, int maxLocals, int codeLength){ + int p = pos + codeLength; + reader.setCode( this, tag, maxStack, maxLocals, codeLength); + pos = p; + } + private void setExceptionTableCount(ClassFileReader reader, Object tag, int exceptionTableCount){ + int p = pos; + reader.setExceptionHandlerTableCount( this, tag, exceptionTableCount); + pos = p; + } + private void setExceptionTableEntry(ClassFileReader reader, Object tag, int exceptionIndex, + int startPc, int endPc, int handlerPc, String catchType){ + int p = pos; + reader.setExceptionHandler( this, tag, exceptionIndex, startPc, endPc, handlerPc, catchType); + pos = p; + } + private void setExceptionTableDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setExceptionHandlerTableDone( this, tag); + pos = p; + } + + private void setCodeAttributeCount(ClassFileReader reader, Object tag, int attrCount){ + int p = pos; + reader.setCodeAttributeCount( this, tag, attrCount); + pos = p; + } + private void setCodeAttribute(ClassFileReader reader, Object tag, int attrIndex, String name, int attrLength){ + int p = pos + attrLength; + reader.setCodeAttribute( this, tag, attrIndex, name, attrLength); + pos = p; + } + private void setCodeAttributesDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setCodeAttributesDone( this, tag); + pos = p; + } + + private void setLineNumberTableCount(ClassFileReader reader, Object tag, int lineNumberCount){ + int p = pos; + reader.setLineNumberTableCount( this, tag, lineNumberCount); + pos = p; + } + private void setLineNumber(ClassFileReader reader, Object tag, int lineIndex, int lineNumber, int startPc){ + int p = pos; + reader.setLineNumber( this, tag, lineIndex, lineNumber, startPc); + pos = p; + } + private void setLineNumberTableDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setLineNumberTableDone( this, tag); + pos = p; + } + + private void setLocalVarTableCount(ClassFileReader reader, Object tag, int localVarCount){ + int p = pos; + reader.setLocalVarTableCount( this, tag, localVarCount); + pos = p; + } + private void setLocalVar(ClassFileReader reader, Object tag, int localVarIndex, String varName, String descriptor, + int scopeStartPc, int scopeEndPc, int slotIndex){ + int p = pos; + reader.setLocalVar( this, tag, localVarIndex, varName, descriptor, scopeStartPc, scopeEndPc, slotIndex); + pos = p; + } + private void setLocalVarTableDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setLocalVarTableDone( this, tag); + pos = p; + } + + + private void setClassAttributeCount(ClassFileReader reader, int attrCount){ + int p = pos; + reader.setClassAttributeCount( this, attrCount); + pos = p; + } + private void setClassAttribute(ClassFileReader reader, int attrIndex, String name, int attrLength){ + int p = pos + attrLength; + reader.setClassAttribute( this, attrIndex, name, attrLength); + pos = p; + } + private void setClassAttributesDone(ClassFileReader reader){ + int p = pos; + reader.setClassAttributesDone(this); + pos = p; + } + + private void setSourceFile(ClassFileReader reader, Object tag, String pathName){ + int p = pos; + reader.setSourceFile( this, tag, pathName); + pos = p; + } + + private void setBootstrapMethodCount (ClassFileReader reader, Object tag, int bootstrapMethodCount){ + int p = pos; + reader.setBootstrapMethodCount( this, tag, bootstrapMethodCount); + pos = p; + } + private void setBootstrapMethod (ClassFileReader reader, Object tag, int idx, + int refKind, String cls, String mth, String descriptor, int[] cpArgs){ + int p = pos; + reader.setBootstrapMethod( this, tag, idx, refKind, cls, mth, descriptor, cpArgs); + pos = p; + } + private void setBootstrapMethodsDone (ClassFileReader reader, Object tag){ + int p = pos; + reader.setBootstrapMethodsDone( this, tag); + pos = p; + } + + private void setInnerClassCount(ClassFileReader reader, Object tag, int innerClsCount){ + int p = pos; + reader.setInnerClassCount( this, tag, innerClsCount); + pos = p; + } + private void setInnerClass(ClassFileReader reader, Object tag, int innerClsIndex, String outerName, String innerName, + String innerSimpleName, int accessFlags){ + int p = pos; + reader.setInnerClass( this, tag, innerClsIndex, outerName, innerName, innerSimpleName, accessFlags); + pos = p; + } + private void setEnclosingMethod(ClassFileReader reader, Object tag, String enclosingClass, String enclosedMethod, String descriptor){ + int p = pos; + reader.setEnclosingMethod( this, tag, enclosingClass, enclosedMethod, descriptor); + pos = p; + } + private void setInnerClassesDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setInnerClassesDone(this, tag); + pos = p; + } + + private void setAnnotationCount(ClassFileReader reader, Object tag, int annotationCount){ + int p = pos; + reader.setAnnotationCount( this, tag, annotationCount); + pos = p; + } + private void setAnnotation(ClassFileReader reader, Object tag, int annotationIndex, String annotationType){ + int p = pos; + reader.setAnnotation( this, tag, annotationIndex, annotationType); + pos = p; + } + private void setAnnotationsDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setAnnotationsDone(this, tag); + pos = p; + } + + private void setTypeAnnotationCount(ClassFileReader reader, Object tag, int annotationCount){ + int p = pos; + reader.setTypeAnnotationCount( this, tag, annotationCount); + pos = p; + } + private void setTypeAnnotationsDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setTypeAnnotationsDone(this, tag); + pos = p; + } + + + private void setAnnotationValueCount(ClassFileReader reader, Object tag, int annotationIndex, int nValuePairs){ + int p = pos; + reader.setAnnotationValueCount( this, tag, annotationIndex, nValuePairs); + pos = p; + } + private void setPrimitiveAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, Object val){ + int p = pos; + reader.setPrimitiveAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, val); + pos = p; + } + private void setStringAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String s){ + int p = pos; + reader.setStringAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, s); + pos = p; + } + private void setClassAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String typeName){ + int p = pos; + reader.setClassAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, typeName); + pos = p; + } + private void setEnumAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String enumType, String enumValue){ + int p = pos; + reader.setEnumAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, enumType, enumValue); + pos = p; + } + + private void setAnnotationValueElementCount(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, + String elementName, int elementCount){ + int p = pos; + reader.setAnnotationValueElementCount(this, tag, annotationIndex, valueIndex, elementName, elementCount); + pos = p; + } + private void setAnnotationValueElementsDone(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, + String elementName){ + int p = pos; + reader.setAnnotationValueElementsDone(this, tag, annotationIndex, valueIndex, elementName); + pos = p; + } + + public void setAnnotationValuesDone(ClassFileReader reader, Object tag, int annotationIndex){ + int p = pos; + reader.setAnnotationValuesDone(this, tag, annotationIndex); + pos = p; + } + + private void setParameterCount(ClassFileReader reader, Object tag, int parameterCount){ + int p = pos; + reader.setParameterCount(this, tag, parameterCount); + pos = p; + } + private void setParameterAnnotationCount(ClassFileReader reader, Object tag, int paramIndex, int annotationCount){ + int p = pos; + reader.setParameterAnnotationCount(this, tag, paramIndex, annotationCount); + pos = p; + } + private void setParameterAnnotation(ClassFileReader reader, Object tag, int annotationIndex, String annotationType){ + int p = pos; + reader.setParameterAnnotation( this, tag, annotationIndex, annotationType); + pos = p; + } + private void setParameterAnnotationsDone(ClassFileReader reader, Object tag, int paramIndex){ + int p = pos; + reader.setParameterAnnotationsDone(this, tag, paramIndex); + pos = p; + } + private void setParametersDone(ClassFileReader reader, Object tag){ + int p = pos; + reader.setParametersDone(this, tag); + pos = p; + } + + public void setSignature(ClassFileReader reader, Object tag, String signature){ + int p = pos; + reader.setSignature(this, tag, signature); + pos = p; + } + + //--- parsing + + /** + * this is the main parsing routine that uses the ClassFileReader interface + * to tell clients about the classfile contents + * + * ClassFile structure: http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#74353 + * u4 magic; // 0xcafebabe + * u2 minor_version; + * u2 major_version; + * + * u2 constant_pool_count; + * cp_entry constant_pool[constant_pool_count-1]; + * u2 access_flags; + * + * u2 this_class; + * u2 super_class; + * + * u2 interfaces_count; + * u2 interfaces[interfaces_count]; + * + * u2 fields_count; + * field_info fields[fields_count]; + * + * u2 methods_count; + * method_info methods[methods_count]; + * + * u2 attributes_count; + * attribute_info attributes[attributes_count]; + */ + public void parse( ClassFileReader reader) throws ClassParseException { + int cpIdx; + + try { + // yeah, cafebabe + int magic = readI4(); + if (magic != 0xCAFEBABE) { + error("wrong magic: " + Integer.toHexString(magic)); + } + + // we don't do much with the version numbers yet + int minor = readU2(); + int major = readU2(); + + // get the const pool + int cpCount = readU2(); + cpPos = new int[cpCount]; + cpValue = new Object[cpCount]; + parseCp(cpCount); + + // the class essentials + int accessFlags = readU2(); + + cpIdx = readU2(); + String clsName = (String) cpValue[cpIdx]; + + cpIdx = readU2(); + String superClsName = (String) cpValue[cpIdx]; + + + setClass(reader, clsName, superClsName, accessFlags, cpCount); + + // interfaces + int ifcCount = readU2(); + parseInterfaces(reader, ifcCount); + + // fields + int fieldCount = readU2(); + parseFields(reader, fieldCount); + + // methods + int methodCount = readU2(); + parseMethods(reader, methodCount); + + // class attributes + int classAttrCount = readU2(); + parseClassAttributes(reader, classAttrCount); + + } catch (BailOut x){ + // nothing, just a control exception to shortcut the classfile parsing + } + } + + + //--- constpool parsing + + public static String readModifiedUTF8String( byte[] data, int pos, int len) throws ClassParseException { + + int n = 0; // the number of chars in buf + char[] buf = new char[len]; // it can't be more, but it can be less chars + + // \u0001 - \u007f : single byte chars: 0xxxxxxx + // \u0000 and \u0080 - \u07ff : double byte chars: 110xxxxx, 10xxxxxx + // \u0800 - \uffff : tripple byte chars: 1110xxxx, 10xxxxxx, 10xxxxxx + + int max = pos+len; + for (int i=pos; i; } + dataIdx[i] = j; + values[i] = CpInfo.ConstantClass; + + j += 3; + break; + + case CONSTANT_STRING: // String_info { u1 tag; u2 string_index; } + dataIdx[i] = j; + values[i] = CpInfo.ConstantString; + + j += 3; + break; + + case FIELD_REF: // Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; } + dataIdx[i] = j; + values[i] = CpInfo.FieldRef; + j += 5; + break; + + case METHOD_REF: // Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } + dataIdx[i] = j; + values[i] = CpInfo.MethodRef; + j += 5; + break; + + case INTERFACE_METHOD_REF: // InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } + dataIdx[i] = j; + values[i] = CpInfo.InterfaceMethodRef; + j += 5; + break; + + case NAME_AND_TYPE: // NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; } + dataIdx[i] = j; + values[i] = CpInfo.NameAndType; + + j += 5; + break; + + //--- the Java 8 ones + + case METHOD_HANDLE: // MethodHandle_info { u1 tag; u1 reference_kind; u2 reference_index; } + dataIdx[i] = j; + values[i] = CpInfo.MethodHandle; + j += 4; + break; + + case METHOD_TYPE: // MethodType_info { u1 tag; u2 descriptor_index; } + dataIdx[i] = j; + values[i] = CpInfo.MethodType; + j += 3; + break; + + case INVOKE_DYNAMIC: // InvokeDynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; } + dataIdx[i] = j; + values[i] = CpInfo.InvokeDynamic; + j += 5; + break; + + default: + error("illegal constpool tag: " + data[j]); + } + } + + pos = j; + + //--- second pass: store values of delegating constant values + for (int i=1; i; u4 attrLength; u2 constIndex } + * + * pos is at constIndex + */ + public void parseConstValueAttr(ClassFileReader reader, Object tag){ + int cpIdx = readU2(); + setConstantValue(reader, tag, cpValue[cpIdx]); + } + + + //--- methods + protected void parseMethods(ClassFileReader reader, int methodCount) { + + setMethodCount(reader, methodCount); + + for (int i=0; i; u4 attr_length; + * u2 max_stack; u2 max_locals; + * u4 code_length; u1 code[code_length]; + * u2 exception_table_length; + * { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; + * } exception_table[exception_table_length]; + * u2 attributes_count; + * attribute_info attributes[attributes_count]; } + * + * pos is at max_stack + */ + public void parseCodeAttr (ClassFileReader reader, Object tag){ + int maxStack = readU2(); + int maxLocals = readU2(); + int codeLength = readI4(); // no code length > 2GB supported + int codeStartPos = pos; + + setCode(reader, tag, maxStack, maxLocals, codeLength); + + int exceptionCount = readU2(); + setExceptionTableCount(reader, tag, exceptionCount); + + for (int i = 0; i < exceptionCount; i++) { + int startPc = readU2(); + int endPc = readU2(); + int handlerPc = readU2(); + + int cpIdx = readU2(); + String catchType = (String) cpValue[cpIdx]; // a Constant_class + + setExceptionTableEntry(reader, tag, i, startPc, endPc, handlerPc, catchType); + } + setExceptionTableDone(reader, tag); + + int attrCount = readU2(); + parseCodeAttrAttributes(reader, tag, attrCount); + } + + + protected void parseCodeAttrAttributes(ClassFileReader reader, Object tag, int attrCount){ + + setCodeAttributeCount(reader, tag, attrCount); + + for (int i=0; i; u4 length; u2 sourceFile; } + */ + public void parseSourceFileAttr(ClassFileReader reader, Object tag){ + int cpIdx = readU2(); + String pathName = utf8At(cpIdx); + setSourceFile(reader, tag, pathName); + } + + /** + * (optionally) called by ClassFileReader from within setClassAttribute() notification + * + * InnerClass { + * u2 nameIdx; + * u4 length; + * u2 classCount; + * { u2 innerCls; + * u2 outerCls; + * u2 innerName; + * u2 innerAccessFlags; + * } classes[classCount] } + * } + * + * pos is at classCount + */ + public void parseInnerClassesAttr(ClassFileReader reader, Object tag){ + int innerClsCount = readU2(); + setInnerClassCount(reader, tag, innerClsCount); + + for (int i = 0; i < innerClsCount; i++) { + int cpIdx = readU2(); + String innerClsName = (cpIdx != 0) ? (String) cpValue[cpIdx] : null; + cpIdx = readU2(); + String outerClsName = (cpIdx != 0) ? (String) cpValue[cpIdx] : null; + cpIdx = readU2(); + String innerSimpleName = (cpIdx != 0) ? (String) cpValue[cpIdx] : null; + int accessFlags = readU2(); + + setInnerClass(reader, tag, i, outerClsName, innerClsName, innerSimpleName, accessFlags); + } + + setInnerClassesDone(reader, tag); + } + + /** + * EnclosingMethod_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 class_index -> Class_info { u1 tag; u2 name_index->utf8 } + * u2 method_index -> NameAndType_info { u1 tag; u2 name_index->utf8; u2 descriptor_index->utf8 } + * } + */ + public void parseEnclosingMethodAttr(ClassFileReader reader, Object tag){ + String enclosedMethod = null; + String descriptor = null; + + int cpIdx = readU2(); // start of Class_info + String enclosingClass = nameAt(cpIdx); + + cpIdx = readU2(); // start of NameAndType_info + + // check if this is inside a method - we also get EnclosingMethod_infos for + // classes that are not immediately enclosed + if (cpIdx != 0){ + enclosedMethod = nameAt(cpIdx); + descriptor = descriptorAt(cpIdx); + } + + setEnclosingMethod(reader, tag, enclosingClass, enclosedMethod, descriptor); + } + + /** + * BootstrapMethods_attribute { + * u2 attribute_name_index; + * u4 attribute_length; + * u2 num_bootstrap_methods; + * { u2 bootstrap_method_ref; -> MethodHandle + * u2 num_bootstrap_arguments; + * u2 bootstrap_arguments[num_bootstrap_arguments]; + * } bootstrap_methods[num_bootstrap_methods]; + * } + * + * pos is at num_bootstrap_methods + */ + public void parseBootstrapMethodAttr (ClassFileReader reader, Object tag){ + int nBootstrapMethods = readU2(); + + setBootstrapMethodCount(reader, tag, nBootstrapMethods); + + for (int i=0; i>8) & 0xff)); + sb.append( Integer.toString(e & 0xff)); + sb.append(')'); + } + + return sb.toString(); + } + + public static String getScopeEncoding (long[] scopeEntries){ + StringBuffer sb = new StringBuffer(); + for (int i=0; i> 16) & 0xffff); + int startPc = (int)((e >> 32) & 0xffff); + + if (i>0){ + sb.append(','); + } + + sb.append('['); + sb.append( Integer.toString(startPc)); + sb.append(".."); + sb.append( Integer.toString(startPc + length-1)); + sb.append("]#"); + sb.append(slotIndex); + } + + return sb.toString(); + } + + // JSR 308 type annotation, which adds 3 fields to the old annotation structure + // + // type_annotation { + // u1 target_type; // targeted program element (sec 3.2) + // union { // ?? this is probably packed - variable size unions make no sense + // type_parameter_target; + // supertype_target; + // type_parameter_bound_target; + // empty_target; + // method_formal_parameter_target; + // throws_target; + // localvar_target; + // catch_target; + // offset_target; + // type_argument_target; + // } target_info; // targeted program element (sec 3.3) + // + // type_path target_path; // encoding of annotation position in compound type (array, generic, etc., sec 3.4) + // + // // standard annotation fields + // u2 type_index; // the annotation type + // u2 num_element_value_pairs; + // { + // u2 element_name_index; + // element_value value; + // } element_value_pairs[num_element_value_pairs]; + // } + // + // struct type_path { + // u1 path_length; + // type_path_entry path[path_length]; + // } + // + // struct type_path_entry { + // u1 type_path_kind; + // // 0: deeper in array type + // // 1: deeper in nested type + // // 2: bound of wildcard typearg + // // 3: type argument of parameterized type + // u1 type_argument_index; + // // 0, if type_path_kind == 0,1,2 + // // 0-based index of type arg in parameterized type if type_path_kind i== 3 + // } + + int getTargetInfoSize (int targetType){ + int len = 3; // max static length are xx_TYPE_ARGUMENTs + if (targetType == LOCAL_VARIABLE || targetType == RESOURCE_VARIABLE){ + len = Math.max( len, u2(pos) * 6); // three u2 values per entry + } + + return len; + } + + int getTypePathSize (short[] typePath){ + int typePathSize = 1; + if (typePath != null) { + typePathSize += typePath.length * 2; + } + return typePathSize; + } + + + short[] readTypePath (){ + short[] typePath = null; + + int pathLength = readUByte(); + if (pathLength > 0){ + typePath = new short[pathLength]; + for (int i=0; i>2)<<2)+startPos; // skip over padding + + defaultOffset = readI4(); + int low = readI4(); + int high = readI4(); + + int len = high-low+1; + nextPos = pos + len*4; + reader.tableswitch(defaultOffset, low, high); + pos = nextPos; + break; + case 171: // lookupswitch + pos = (((pc+4)>>2)<<2)+startPos; // skip over padding + + defaultOffset = readI4(); + int nPairs = readI4(); + + nextPos = pos + (nPairs*8); + reader.lookupswitch(defaultOffset, nPairs); + pos = nextPos; + break; + case 172: // ireturn + reader.ireturn(); + break; + case 173: // lreturn + reader.lreturn(); + break; + case 174: // freturn + reader.freturn(); + break; + case 175: // dreturn + reader.dreturn(); + break; + case 176: // areturn + reader.areturn(); + break; + case 177: // return + reader.return_(); + break; + case 178: // getstatic + cpIdx = readU2(); // CP index of fieldRef + reader.getstatic(cpIdx); + break; + case 179: // putstatic + cpIdx = readU2(); // CP index of fieldRef + reader.putstatic(cpIdx); + break; + case 180: // getfield + cpIdx = readU2(); // CP index of fieldRef + reader.getfield(cpIdx); + break; + case 181: // putfield + cpIdx = readU2(); // CP index of fieldRef + reader.putfield(cpIdx); + break; + case 182: // invokevirtual + cpIdx = readU2(); // CP index of methodRef + reader.invokevirtual(cpIdx); + break; + case 183: // invokespecial + cpIdx = readU2(); // CP index of methodRef + reader.invokespecial(cpIdx); + break; + case 184: // invokestatic + cpIdx = readU2(); // CP index of methodRef + reader.invokestatic(cpIdx); + break; + case 185: // invokeinterface + cpIdx = readU2(); // CP index of methodRef + int count = readUByte(); + int zero = readUByte(); // must be 0 + reader.invokeinterface(cpIdx, count, zero); + break; + case 186: // invokedynamic + cpIdx = readU2(); // CP index of bootstrap method + readUByte(); // 0 + readUByte(); // 0 + reader.invokedynamic(cpIdx); + break; + case 187: // new + cpIdx = readU2(); + reader.new_(cpIdx); + break; + case 188: // newarray + int aType = readUByte(); + reader.newarray(aType); + break; + case 189: // anewarray + cpIdx = readU2(); // CP index of component type + reader.anewarray(cpIdx); + break; + case 190: // arraylength + reader.arraylength(); + break; + case 191: // athrow + reader.athrow(); + break; + case 192: // checkcast + cpIdx = readU2(); // cast type cp index + reader.checkcast(cpIdx); + break; + case 193: // instanceof + cpIdx = readU2(); // check type cp index + reader.instanceof_(cpIdx); + break; + case 194: // monitorenter + reader.monitorenter(); + break; + case 195: // monitorexit + reader.monitorexit(); + break; + case 196: // wide + isWide = true; + // affects immediate operand width if next bytecode is: + // iload,fload,aload,lload,dload, + // istore,fstore,astore,lstore,dstore + // ret + reader.wide(); + continue; + case 197: // multianewarray + cpIdx = readU2(); + int dimensions = readUByte(); + reader.multianewarray(cpIdx, dimensions); + break; + case 198: // ifnull + offset = readI2(); + reader.ifnull(offset); + break; + case 199: // ifnonnull + offset = readI2(); + reader.ifnonnull(offset); + break; + case 200: // goto_w + offset = readI4(); + reader.goto_w(offset); + break; + case 201: // jsr_w + offset = readI4(); + reader.jsr_w(offset); + break; + + + default: + reader.unknown(opcode); + } + + isWide = false; // reset wide modifier + } + + } + + //--- those can only be called from within a JVMByteCodeReader.tableswitch() notification + public void parseTableSwitchEntries(JVMByteCodeReader reader, int low, int high){ + for (int val=low; val<=high; val++){ + int offset = readI4(); + reader.tableswitchEntry(val, offset); + } + } + public int getTableSwitchOffset(int low, int high, int defaultOffset, int val){ + if (val < low || val > high){ + return defaultOffset; + } + + int n = Math.abs(val - low); + pos += n*4; + int pcOffset = readI4(); + + return pcOffset; + } + + //--- those can only be called from within a JVMByteCodeReader.lookupswitch() notification + public void parseLookupSwitchEntries(JVMByteCodeReader reader, int nEntries){ + for (int i=0; i match){ + pos +=4; + } else if (val == match) { + int offset = readI4(); + return offset; + } else { + break; + } + } + return defaultOffset; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/ClassFilePrinter.java b/src/main/gov/nasa/jpf/jvm/ClassFilePrinter.java new file mode 100644 index 0000000..d41cdd9 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/ClassFilePrinter.java @@ -0,0 +1,780 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.jvm.JVMByteCodePrinter; +import gov.nasa.jpf.util.StructuredPrinter; +import gov.nasa.jpf.vm.ClassParseException; +import java.io.PrintWriter; + +/** + * simple tool to print contents of a classfile + * + * <2do> use indentation level variable and formated output + */ +public class ClassFilePrinter extends StructuredPrinter implements ClassFileReader { + + + public static void main(String[] args){ + ClassFilePrinter printer = new ClassFilePrinter(); + + try { + ClassFile cf = new ClassFile(args[0]); + cf.parse(printer); + + } catch (ClassParseException cfx){ + cfx.printStackTrace(); + } + } + + @Override + public void setClass(ClassFile cf, String clsName, String superClsName, int flags, int cpCount) { + printSectionHeader( "constpool"); + printCp(pw,cf); + + incIndent(); + printSectionHeader( "class"); + pw.printf("%sclass=%s\n", indent, clsName); + pw.printf("%ssuperclass=%s\n", indent, superClsName); + pw.printf("%sflags=0x%X\n", indent, flags); + } + + //--- interfaces + @Override + public void setInterfaceCount(ClassFile cf, int ifcCount) { + pw.printf("%sinterface count=%d\n", indent, ifcCount); + incIndent(); + } + + @Override + public void setInterface(ClassFile cf, int ifcIndex, String ifcName) { + pw.printf("%s[%d]: %s\n", indent, ifcIndex, ifcName); + } + + @Override + public void setInterfacesDone(ClassFile cf){ + decIndent(); + } + + //--- fields + @Override + public void setFieldCount(ClassFile cf, int fieldCount) { + printSectionHeader( "fields"); + pw.printf( "%sfield count=%d\n", indent, fieldCount); + } + + @Override + public void setField(ClassFile cf, int fieldIndex, int accessFlags, String name, String descriptor) { + pw.printf("%s[%d]: %s, type=%s,flags=0x%X", indent, fieldIndex, name, descriptor, accessFlags); + } + + @Override + public void setFieldAttributeCount(ClassFile cf, int fieldIndex, int attrCount) { + pw.printf(", attr count=%d\n", attrCount); + incIndent(); + } + + @Override + public void setFieldAttribute(ClassFile cf, int fieldIndex, int attrIndex, String name, int attrLength) { + pw.printf("%s[%d]: %s", indent, attrIndex, name); + + if (name == ClassFile.CONST_VALUE_ATTR) { + cf.parseConstValueAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR){ + cf.parseAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR){ + cf.parseAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ + cf.parseTypeAnnotationsAttr(this, null); + + } else if (name == ClassFile.SIGNATURE_ATTR){ + cf.parseSignatureAttr(this, null); + + } else { + pw.printf(" ,length=%d,data=[",attrLength ); + printRawData(pw, cf, attrLength, 10); + pw.println(']'); + } + } + + @Override + public void setFieldAttributesDone(ClassFile cf, int fieldIndex){ + decIndent(); + } + + @Override + public void setFieldDone(ClassFile cf, int fieldIndex){ + pw.println(); + } + + @Override + public void setFieldsDone(ClassFile cf){ + } + + @Override + public void setConstantValue(ClassFile cf, Object tag, Object value) { + pw.printf(" value=%s\n", value); + } + + //--- methods + @Override + public void setMethodCount(ClassFile cf, int methodCount) { + printSectionHeader( "methods"); + pw.printf( "%smethod count=%d\n", indent, methodCount); + } + + @Override + public void setMethod(ClassFile cf, int methodIndex, int accessFlags, String name, String descriptor) { + pw.printf("%s[%d]: %s%s, flags=0x%X", indent, methodIndex, name, descriptor, accessFlags); + } + + @Override + public void setMethodAttributeCount(ClassFile cf, int methodIndex, int attrCount) { + pw.printf(", attr count=%d\n", attrCount); + incIndent(); + } + + @Override + public void setMethodAttribute(ClassFile cf, int methodIndex, int attrIndex, String name, int attrLength) { + pw.printf("%s[%d]: %s", indent, attrIndex, name); + + if (name == ClassFile.CODE_ATTR) { + cf.parseCodeAttr(this, null); + + } else if (name == ClassFile.EXCEPTIONS_ATTR){ + cf.parseExceptionAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR){ + cf.parseAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR){ + cf.parseAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR){ + cf.parseParameterAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ + cf.parseTypeAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR){ + cf.parseParameterAnnotationsAttr(this, null); + + } else if (name == ClassFile.SIGNATURE_ATTR){ + cf.parseSignatureAttr(this, null); + + } else { + pw.printf(" ,length=%d,data=[", attrLength ); + printRawData(pw, cf, attrLength, 10); + pw.println(']'); + } + } + + @Override + public void setMethodAttributesDone(ClassFile cf, int methodIndex){ + decIndent(); + } + + @Override + public void setMethodDone(ClassFile cf, int methodIndex){ + pw.println(); + } + + @Override + public void setMethodsDone(ClassFile cf){ + } + + @Override + public void setExceptionCount(ClassFile cf, Object tag, int exceptionCount){ + pw.printf(", count=%d\n", exceptionCount); + incIndent(); + } + @Override + public void setException(ClassFile cf, Object tag, int exceptionIndex, String exceptionType){ + pw.printf("%s[%d]: %s\n", indent, exceptionIndex, exceptionType); + } + @Override + public void setExceptionsDone(ClassFile cf, Object tag){ + decIndent(); + } + + + @Override + public void setCode(ClassFile cf, Object tag, int maxStack, int maxLocals, int codeLength) { + pw.printf(", maxStack=%d,maxLocals=%d,length=%d\n", maxStack, maxLocals,codeLength); + incIndent(); + JVMByteCodePrinter bcPrinter = new JVMByteCodePrinter(pw, cf, indent); + cf.parseBytecode(bcPrinter, tag, codeLength); + decIndent(); + } + + @Override + public void setExceptionHandlerTableCount(ClassFile cf, Object tag, int exceptionTableCount) { + pw.printf("%sexception table count=%d\n", indent, exceptionTableCount); + incIndent(); + } + @Override + public void setExceptionHandler(ClassFile cf, Object tag, int exceptionIndex, + int startPc, int endPc, int handlerPc, String catchType) { + pw.printf("%s[%d]: type=%s, range=[%d..%d], handler=%d\n", indent, exceptionIndex, catchType, startPc, endPc, handlerPc); + } + @Override + public void setExceptionHandlerTableDone(ClassFile cf, Object tag){ + decIndent(); + } + + @Override + public void setCodeAttributeCount(ClassFile cf, Object tag, int attrCount) { + pw.printf("%scode attribute count=%d\n", indent, attrCount); + incIndent(); + } + @Override + public void setCodeAttribute(ClassFile cf, Object tag, int attrIndex, String name, int attrLength) { + pw.printf("%s[%d]: %s", indent, attrIndex, name); + + if (name == ClassFile.LINE_NUMBER_TABLE_ATTR) { + cf.parseLineNumberTableAttr(this, tag); + + } else if (name == ClassFile.LOCAL_VAR_TABLE_ATTR) { + cf.parseLocalVarTableAttr(this, tag); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ + cf.parseTypeAnnotationsAttr(this, tag); + + } else { // generic + pw.printf(" ,length=%d,data=[", attrLength ); + printRawData(pw, cf, attrLength, 10); + pw.println(']'); + } + } + @Override + public void setCodeAttributesDone(ClassFile cf, Object tag){ + decIndent(); + } + + @Override + public void setLineNumberTableCount(ClassFile cf, Object tag, int lineNumberCount) { + pw.printf(", linenumber count=%d\n", lineNumberCount); + incIndent(); + } + @Override + public void setLineNumber(ClassFile cf, Object tag, int lineIndex, int lineNumber, int startPc) { + pw.printf("%s[%d]: line=%d, pc=%d\n", indent, lineIndex, lineNumber, startPc); + } + @Override + public void setLineNumberTableDone(ClassFile cf, Object tag){ + decIndent(); + } + + @Override + public void setLocalVarTableCount(ClassFile cf, Object tag, int localVarCount) { + pw.printf(", localVar count=%d\n", localVarCount); + incIndent(); + } + @Override + public void setLocalVar(ClassFile cf, Object tag, int localVarIndex, + String varName, String descriptor, int scopeStartPc, int scopeEndPc, int slotIndex) { + pw.printf("%s[%d]: %s, type=%s, scope=[%d..%d], slot=%d\n", indent, localVarIndex, varName, descriptor, + scopeStartPc, scopeEndPc, slotIndex); + } + @Override + public void setLocalVarTableDone(ClassFile cf, Object tag){ + decIndent(); + } + + //--- class attributes + @Override + public void setClassAttributeCount(ClassFile cf, int attrCount) { + printSectionHeader( "class attributes"); + pw.printf("%sclass attribute count=%d\n", indent, attrCount); + incIndent(); + } + @Override + public void setClassAttribute(ClassFile cf, int attrIndex, String name, int attrLength) { + pw.printf("%s[%d]: %s", indent, attrIndex, name); + + if (name == ClassFile.SOURCE_FILE_ATTR) { + cf.parseSourceFileAttr(this, null); + + } else if (name == ClassFile.DEPRECATED_ATTR) { + + } else if (name == ClassFile.INNER_CLASSES_ATTR) { + cf.parseInnerClassesAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR){ + cf.parseAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ + cf.parseTypeAnnotationsAttr(this, null); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR){ + cf.parseAnnotationsAttr(this, null); + + } else if (name == ClassFile.SIGNATURE_ATTR){ + cf.parseSignatureAttr(this, null); + + } else if (name == ClassFile.ENCLOSING_METHOD_ATTR){ + cf.parseEnclosingMethodAttr(this, null); + + } else if (name == ClassFile.BOOTSTRAP_METHOD_ATTR){ + cf.parseBootstrapMethodAttr(this, null); + + } else { + pw.printf(" ,length=%d,data=[", attrLength ); + printRawData(pw, cf, attrLength, 10); + pw.println(']'); + } + } + @Override + public void setClassAttributesDone(ClassFile cf){ + decIndent(); + } + + @Override + public void setEnclosingMethod(ClassFile cf, Object tag, String enclosingClass, String enclosingMethod, String descriptor) { + if (enclosingMethod != null){ + pw.printf(", enclosingClass=%s, method=%s%s\n", enclosingClass, enclosingMethod, descriptor); + } else { + pw.printf(", enclosingClass=%s\n", enclosingClass); + } + } + + + @Override + public void setSourceFile(ClassFile cf, Object tag, String pathName){ + pw.printf(", path=%s\n", pathName); + } + + @Override + public void setInnerClassCount(ClassFile cf, Object tag, int innerClsCount) { + pw.printf( ", inner class count=%d\n", innerClsCount); + incIndent(); + } + @Override + public void setInnerClass(ClassFile cf, Object tag, int innerClsIndex, + String outerName, String innerName, String innerSimpleName, int accessFlags) { + pw.printf("%s[%d]: %s, fullName=%s, outerClass=%s, flags=0x%X\n", indent, innerClsIndex, + innerSimpleName, innerName, outerName, accessFlags); + } + @Override + public void setInnerClassesDone(ClassFile cf, Object tag){ + decIndent(); + } + + @Override + public void setBootstrapMethodCount (ClassFile cf, Object tag, int count) { + pw.printf( ", bootstrap method count=%d\n", count); + incIndent(); + } + + @Override + public void setBootstrapMethod (ClassFile cf, Object tag, int idx, + int refKind, String cls, String mth, String descriptor, int[] cpArgs){ + String refTypeName = cf.getRefTypeName(refKind); + pw.printf("%s[%d]: %s %s.%s%s\n", indent, idx, refTypeName, cls, mth, descriptor); + incIndent(); + pw.printf("%smethod arg count: %d\n", indent, cpArgs.length); + incIndent(); + for (int i=0; i"); + continue; + } + + switch (cf.u1(j)){ + case ClassFile.CONSTANT_UTF8: + pw.print( "constant_utf8 {\""); + pw.print( cf.getCpValue(i)); + pw.println("\"}"); + break; + case ClassFile.CONSTANT_INTEGER: + pw.print( "constant_integer {"); + pw.print( cf.getCpValue(i)); + pw.println("}"); + break; + case ClassFile.CONSTANT_FLOAT: + pw.print( "constant_float {"); + pw.print( cf.getCpValue(i)); + pw.println("}"); + break; + case ClassFile.CONSTANT_LONG: + pw.print( "constant_long {"); + pw.print( cf.getCpValue(i)); + pw.println("}"); + break; + case ClassFile.CONSTANT_DOUBLE: + pw.print( "constant_double {"); + pw.print( cf.getCpValue(i)); + pw.println("}"); + break; + case ClassFile.CONSTANT_CLASS: + pw.print("constant_class {name=#"); + pw.print( cf.u2(j+1)); + pw.print("(\""); + pw.print( cf.classNameAt(i)); + pw.println("\")}"); + break; + case ClassFile.CONSTANT_STRING: + pw.print("constant_string {utf8=#"); + pw.print( cf.u2(j+1)); + pw.print("(\""); + pw.print( cf.stringAt(i)); + pw.println("\")}"); + break; + case ClassFile.FIELD_REF: + printRef(pw, cf, i, j, "fieldref"); + break; + case ClassFile.METHOD_REF: + printRef(pw, cf, i, j, "methodref"); + break; + case ClassFile.INTERFACE_METHOD_REF: + printRef(pw, cf, i, j, "interface_methodref"); + break; + case ClassFile.NAME_AND_TYPE: + pw.print("name_and_type {name=#"); + pw.print( cf.u2(j+1)); + pw.print("(\""); + pw.print(cf.utf8At(cf.u2(j+1))); + pw.print("\"),desciptor=#"); + pw.print( cf.u2(j+3)); + pw.print("(\""); + pw.print(cf.utf8At(cf.u2(j+3))); + pw.println("\")}"); + break; + + case ClassFile.METHOD_HANDLE: + pw.print("method_handle {"); + pw.print("(\""); + pw.println("\")}"); + break; + + case ClassFile.METHOD_TYPE: + pw.print("method_type {"); + pw.print("(\""); + pw.println("\")}"); + break; + + case ClassFile.INVOKE_DYNAMIC: + pw.print("invoke_dynamic {bootstrap=#"); + pw.print(cf.u2(j+1)); + pw.print("(\""); + pw.println("\")}"); + break; + + default: + pw.print("ERROR: illegal tag" + cf.u1(j)); + } + } + pw.println(); + } + + void printRef(PrintWriter pw, ClassFile cf, int cpIdx, int dataPos, String refType){ + pw.print(refType); + pw.print(" {class=#"); + pw.print(cf.u2(dataPos + 1)); + pw.print("(\""); + pw.print(cf.refClassNameAt(cpIdx)); + pw.print("\"),nameType=#"); + pw.print(cf.u2(dataPos + 3)); + pw.print("(\""); + pw.print(cf.refNameAt(cpIdx)); + pw.print("\",\""); + pw.print(cf.refDescriptorAt(cpIdx)); + pw.println("\")}"); + } + + void printRawData(PrintWriter pw, ClassFile cf, int dataLength, int maxBytes){ + int max = Math.min(dataLength, maxBytes); + int max1 = max-1; + for (int i=0; imaxBytes){ + pw.print(".."); + } + } +} diff --git a/src/main/gov/nasa/jpf/jvm/ClassFileReader.java b/src/main/gov/nasa/jpf/jvm/ClassFileReader.java new file mode 100644 index 0000000..6017fad --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/ClassFileReader.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.vm.ClassParseException; + +/** + * interface for classfile processors + * + * NOTE - all types are given ss descriptors, i.e. "Lx/y/Z;" or type codes such as "I" + * + * iteration groups always start with a + * setXCount(int xCount) + * + * followed by xCount notifications + * setX (int xIndex) + * + * with 0<=xIndex Integer.MAX_VALUE) { + error("classfile too big: " + f.getPath()); + } + byte[] data = new byte[(int) len]; + FileUtils.getContents(fis, data); + + return new JVMClassFileMatch( clsName, getClassURL(clsName), data); + + } catch (IOException iox) { + error("cannot read " + f.getPath()); + + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException iox) { + error("cannot close input stream for file " + f.getPath()); + } + } + } + } + + return null; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMAnnotationParser.java b/src/main/gov/nasa/jpf/jvm/JVMAnnotationParser.java new file mode 100644 index 0000000..8acef37 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMAnnotationParser.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.JPFException; +import gov.nasa.jpf.vm.AnnotationInfo; +import gov.nasa.jpf.vm.AnnotationParser; +import gov.nasa.jpf.vm.ClassParseException; +import gov.nasa.jpf.vm.Types; + +/** + * parser that reads annotation classfiles and extracts default value entries + * + * Java annotations form a different type system. Java annotations are essentially + * restricted interfaces (no super-interface, no fields other than static finals + * that are inlined by the compiler) + * + * Since Java annotations use only a small subset of the Java classfile format + * we only have to parse methods and method attributes + * + * <2do> class and enum values are not yet supported + */ +public class JVMAnnotationParser extends ClassFileReaderAdapter implements AnnotationParser { + + ClassFile cf; + AnnotationInfo ai; + + String key; + Object value; + Object[] valElements; + + String annotationName; + AnnotationInfo.Entry[] entries; + + public JVMAnnotationParser (ClassFile cf) { + this.cf = cf; + } + + @Override + public void parse (AnnotationInfo ai) throws ClassParseException { + this.ai = ai; + + cf.parse(this); + } + + //--- the overridden ClassFileReader methods + + @Override + public void setClass (ClassFile cf, String clsName, String superClsName, int flags, int cpCount) throws ClassParseException { + entries = null; + annotationName = Types.getClassNameFromTypeName(clsName); + + ai.setName(annotationName); + } + + @Override + public void setInterface (ClassFile cf, int ifcIndex, String ifcName) { + if (!"java/lang/annotation/Annotation".equals(ifcName)) { + throw new JPFException("illegal annotation interface of: " + annotationName + " is " + ifcName); + } + } + + @Override + public void setMethodCount (ClassFile cf, int methodCount) { + entries = new AnnotationInfo.Entry[methodCount]; + } + + @Override + public void setMethod (ClassFile cf, int methodIndex, int accessFlags, String name, String descriptor) { + key = name; + value = null; + } + + @Override + public void setMethodDone (ClassFile cf, int methodIndex){ + entries[methodIndex] = new AnnotationInfo.Entry(key, value); + } + + @Override + public void setMethodsDone (ClassFile cf){ + ai.setEntries(entries); + } + + @Override + public void setMethodAttribute (ClassFile cf, int methodIndex, int attrIndex, String name, int attrLength) { + if (name == ClassFile.ANNOTATIONDEFAULT_ATTR) { + cf.parseAnnotationDefaultAttr(this, key); + } + } + + @Override + public void setClassAttribute (ClassFile cf, int attrIndex, String name, int attrLength) { + if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) { + key = null; + cf.parseAnnotationsAttr(this, null); + } + } + + @Override + public void setAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) { + if (annotationType.equals("Ljava/lang/annotation/Inherited;")) { + ai.setInherited( true); + } + } + + @Override + public void setPrimitiveAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, Object val) { + if (arrayIndex >= 0) { + valElements[arrayIndex] = val; + } else { + if (key != null){ + value = val; + } + } + } + + @Override + public void setStringAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String val) { + if (arrayIndex >= 0) { + valElements[arrayIndex] = val; + } else { + if (key != null){ + value = val; + } + } + } + + @Override + public void setClassAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String typeName) { + Object val = AnnotationInfo.getClassValue(typeName); + if (arrayIndex >= 0) { + valElements[arrayIndex] = val; + } else { + if (key != null){ + value = val; + } + } + } + + @Override + public void setEnumAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String enumType, String enumValue) { + Object val = AnnotationInfo.getEnumValue(enumType, enumValue); + if (arrayIndex >= 0) { + valElements[arrayIndex] = val; + } else { + if (key != null){ + value = val; + } + } + } + + @Override + public void setAnnotationValueElementCount (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int elementCount) { + valElements = new Object[elementCount]; + } + + @Override + public void setAnnotationValueElementsDone (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName) { + if (key != null) { + value = valElements; + } + } +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMByteCodePrinter.java b/src/main/gov/nasa/jpf/jvm/JVMByteCodePrinter.java new file mode 100644 index 0000000..f5cb578 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMByteCodePrinter.java @@ -0,0 +1,1096 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import java.io.PrintWriter; + +/** + * utility class that prints out bytecode in readable form + */ +public class JVMByteCodePrinter implements JVMByteCodeReader { + + PrintWriter pw; + ClassFile cf; // need this to get the constpool entries + + String prefix; + + public JVMByteCodePrinter (PrintWriter pw, ClassFile cf, String prefix){ + this.pw = pw; + this.cf = cf; + this.prefix = prefix; + } + + @Override + public void aconst_null() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aconst_null"); + } + + @Override + public void aload(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "aload", localVarIndex); + } + + @Override + public void aload_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aload_0"); + } + + @Override + public void aload_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aload_1"); + } + + @Override + public void aload_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aload_2"); + } + + @Override + public void aload_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aload_3"); + } + + @Override + public void aaload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aaload"); + } + + @Override + public void astore(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "astore", localVarIndex); + } + + @Override + public void astore_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "astore_0"); + } + + @Override + public void astore_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "astore_1"); + } + + @Override + public void astore_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "astore_2"); + } + + @Override + public void astore_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "astore_3"); + } + + @Override + public void aastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "aastore"); + } + + @Override + public void areturn() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "areturn"); + } + + @Override + public void anewarray(int cpClassIndex) { + pw.printf("%s%3d: %s @%d(\"%s\")\n", prefix, cf.getPc(), "anewarray", cpClassIndex, cf.classNameAt(cpClassIndex)); + } + + @Override + public void arraylength() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "arraylength"); + } + + @Override + public void athrow() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "athrow"); + } + + @Override + public void baload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "baload"); + } + + @Override + public void bastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "bastore"); + } + + @Override + public void bipush(int b) { + pw.printf("%s%3d: %s %d\n", prefix, cf.getPc(), "bipush", b); + } + + @Override + public void caload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "caload"); + } + + @Override + public void castore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "castore"); + } + + @Override + public void checkcast(int cpClassIndex) { + pw.printf("%s%3d: %s @%d(\"%s\")\n", prefix, cf.getPc(), "checkcast", cpClassIndex, cf.classNameAt(cpClassIndex)); + } + + @Override + public void d2f() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "d2f"); + } + + @Override + public void d2i() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "d2i"); + } + + @Override + public void d2l() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "d2l"); + } + + @Override + public void dadd() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dadd"); + } + + @Override + public void daload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "daload"); + } + + @Override + public void dastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dastore"); + } + + @Override + public void dcmpg() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dcmpg"); + } + + @Override + public void dcmpl() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dcmpl"); + } + + @Override + public void dconst_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dconst_0"); + } + + @Override + public void dconst_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dcont_1"); + } + + @Override + public void ddiv() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ddiv"); + } + + @Override + public void dload(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "dload", localVarIndex); + } + + @Override + public void dload_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dload_0"); + } + + @Override + public void dload_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dload_1"); + } + + @Override + public void dload_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dload_2"); + } + + @Override + public void dload_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dload_3"); + } + + @Override + public void dmul() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dmul"); + } + + @Override + public void dneg() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dneg"); + } + + @Override + public void drem() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "drem"); + } + + @Override + public void dreturn() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dreturn"); + } + + @Override + public void dstore(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "dstore", localVarIndex); + } + + @Override + public void dstore_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dstore_0"); + } + + @Override + public void dstore_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dstore_1"); + } + + @Override + public void dstore_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dstore_2"); + } + + @Override + public void dstore_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dstore_3"); + } + + @Override + public void dsub() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dsub"); + } + + @Override + public void dup() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dup"); + } + + @Override + public void dup_x1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dup_x1"); + } + + @Override + public void dup_x2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dup_x2"); + } + + @Override + public void dup2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dup2"); + } + + @Override + public void dup2_x1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dup2_x1"); + } + + @Override + public void dup2_x2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "dup2_x2"); + } + + @Override + public void f2d() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "f2d"); + } + + @Override + public void f2i() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "f2i"); + } + + @Override + public void f2l() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "f2l"); + } + + @Override + public void fadd() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fadd"); + } + + @Override + public void faload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "faload"); + } + + @Override + public void fastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fastore"); + } + + @Override + public void fcmpg() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fcmpg"); + } + + @Override + public void fcmpl() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fcmpl"); + } + + @Override + public void fconst_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fconst_0"); + } + + @Override + public void fconst_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fconst_1"); + } + + @Override + public void fconst_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fconst_2"); + } + + @Override + public void fdiv() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fdiv"); + } + + @Override + public void fload(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "fload", localVarIndex); + } + + @Override + public void fload_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fload_0"); + } + + @Override + public void fload_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fload_1"); + } + + @Override + public void fload_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fload_2"); + } + + @Override + public void fload_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fload_3"); + } + + @Override + public void fmul() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fmul"); + } + + @Override + public void fneg() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fneg"); + } + + @Override + public void frem() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "frem"); + } + + @Override + public void freturn() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "freturn"); + } + + @Override + public void fstore(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "fstore", localVarIndex); + } + + @Override + public void fstore_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fstore_0"); + } + + @Override + public void fstore_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fstore_1"); + } + + @Override + public void fstore_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fstore_2"); + } + + @Override + public void fstore_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fstore_3"); + } + + @Override + public void fsub() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "fsub"); + } + + @Override + public void getfield(int cpFieldRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "getfield", cpFieldRefIndex, + cf.fieldClassNameAt(cpFieldRefIndex), + cf.fieldNameAt(cpFieldRefIndex), + cf.fieldDescriptorAt(cpFieldRefIndex)); + } + + @Override + public void getstatic(int cpFieldRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "getstatic", cpFieldRefIndex, + cf.fieldClassNameAt(cpFieldRefIndex), + cf.fieldNameAt(cpFieldRefIndex), + cf.fieldDescriptorAt(cpFieldRefIndex)); + } + + @Override + public void goto_(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "goto", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void goto_w(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "goto_w", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void i2b() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "i2b"); + } + + @Override + public void i2c() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "i2c"); + } + + @Override + public void i2d() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "i2d"); + } + + @Override + public void i2f() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "i2f"); + } + + @Override + public void i2l() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "i2l"); + } + + @Override + public void i2s() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "i2s"); + } + + @Override + public void iadd() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iadd"); + } + + @Override + public void iaload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iaload"); + } + + @Override + public void iand() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iand"); + } + + @Override + public void iastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iastore"); + } + + @Override + public void iconst_m1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_m1"); + } + + @Override + public void iconst_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_0"); + } + + @Override + public void iconst_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_1"); + } + + @Override + public void iconst_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_2"); + } + + @Override + public void iconst_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_3"); + } + + @Override + public void iconst_4() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_4"); + } + + @Override + public void iconst_5() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iconst_5"); + } + + @Override + public void idiv() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "idiv"); + } + + @Override + public void if_acmpeq(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_acmpeq", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_acmpne(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_acmpne", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_icmpeq(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_icmpeq", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_icmpne(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_icmpne", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_icmplt(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_icmplt", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_icmpge(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_icmpge", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_icmpgt(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_icmpgt", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void if_icmple(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "if_icmple", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifeq(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifeq", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifne(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifne", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void iflt(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "iflt", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifge(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifge", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifgt(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifgt", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifle(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifle", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifnonnull(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifnonnull", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void ifnull(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "ifnull", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void iinc(int localVarIndex, int incConstant) { + pw.printf("%s%3d: %s [%d] %+d\n", prefix, cf.getPc(), "iinc", localVarIndex, incConstant); + } + + @Override + public void iload(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "iload", localVarIndex); + } + + @Override + public void iload_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iload_0"); + } + + @Override + public void iload_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iload_1"); + } + + @Override + public void iload_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iload_2"); + } + + @Override + public void iload_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iload_3"); + } + + @Override + public void imul() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "imul"); + } + + @Override + public void ineg() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ineg"); + } + + @Override + public void instanceof_(int cpClassIndex) { + pw.printf("%s%3d: %s @%d(\"%s\")\n", prefix, cf.getPc(), "instanceof", cpClassIndex, cf.classNameAt(cpClassIndex)); + } + + @Override + public void invokeinterface(int cpInterfaceMethodRefIndex, int count, int zero) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\") %d\n", prefix, cf.getPc(), "invokeinterface", cpInterfaceMethodRefIndex, + cf.methodClassNameAt(cpInterfaceMethodRefIndex), + cf.methodNameAt(cpInterfaceMethodRefIndex), + cf.methodDescriptorAt(cpInterfaceMethodRefIndex), + count); + } + + @Override + public void invokespecial(int cpMethodRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "invokespecial", cpMethodRefIndex, + cf.methodClassNameAt(cpMethodRefIndex), + cf.methodNameAt(cpMethodRefIndex), + cf.methodDescriptorAt(cpMethodRefIndex)); + } + + @Override + public void invokestatic(int cpMethodRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "invokestatic", cpMethodRefIndex, + cf.methodClassNameAt(cpMethodRefIndex), + cf.methodNameAt(cpMethodRefIndex), + cf.methodDescriptorAt(cpMethodRefIndex)); + } + + @Override + public void invokevirtual(int cpMethodRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "invokevirtual", cpMethodRefIndex, + cf.methodClassNameAt(cpMethodRefIndex), + cf.methodNameAt(cpMethodRefIndex), + cf.methodDescriptorAt(cpMethodRefIndex)); + } + + @Override + public void invokedynamic (int cpInvokeDynamicIndex){ + pw.printf("%s%3d: %s @%d\n", prefix, cf.getPc(), "invokedynamic", cpInvokeDynamicIndex); + } + + @Override + public void ior() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ior"); + } + + @Override + public void irem() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "irem"); + } + + @Override + public void ireturn() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ireturn"); + } + + @Override + public void ishl() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ishl"); + } + + @Override + public void ishr() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ishr"); + } + + @Override + public void istore(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "istore", localVarIndex); + } + + @Override + public void istore_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "istore_0"); + } + + @Override + public void istore_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "istore_1"); + } + + @Override + public void istore_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "istore_2"); + } + + @Override + public void istore_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "istore_3"); + } + + @Override + public void isub() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "isub"); + } + + @Override + public void iushr() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "iushr"); + } + + @Override + public void ixor() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ixor"); + } + + @Override + public void jsr(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "jsr", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void jsr_w(int pcOffset) { + pw.printf("%s%3d: %s %+d (%d)\n", prefix, cf.getPc(), "jsr_w", pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void l2d() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "l2d"); + } + + @Override + public void l2f() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "l2f"); + } + + @Override + public void l2i() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "l2i"); + } + + @Override + public void ladd() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ladd"); + } + + @Override + public void laload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "laload"); + } + + @Override + public void land() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "land"); + } + + @Override + public void lastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lastore"); + } + + @Override + public void lcmp() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lcmp"); + } + + @Override + public void lconst_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lconst_0"); + } + + @Override + public void lconst_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lconst_1"); + } + + @Override + public void ldc_(int cpIntOrFloatOrStringIndex) { + pw.printf("%s%3d: %s @%d(%s)\n", prefix, cf.getPc(), "ldc", cpIntOrFloatOrStringIndex, + cf.getCpValue(cpIntOrFloatOrStringIndex)); + } + + @Override + public void ldc_w_(int cpIntOrFloatOrStringIndex) { + pw.printf("%s%3d: %s @%d(%s)\n", prefix, cf.getPc(), "ldc_w", cpIntOrFloatOrStringIndex, + cf.getCpValue(cpIntOrFloatOrStringIndex)); + } + + @Override + public void ldc2_w(int cpLongOrDoubleIndex) { + pw.printf("%s%3d: %s @%d(%s)\n", prefix, cf.getPc(), "ldc2_w", cpLongOrDoubleIndex, + cf.getCpValue(cpLongOrDoubleIndex)); + } + + @Override + public void ldiv() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "ldiv"); + } + + @Override + public void lload(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "lload", localVarIndex); + } + + @Override + public void lload_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lload_0"); + } + + @Override + public void lload_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lload_1"); + } + + @Override + public void lload_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lload_2"); + } + + @Override + public void lload_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lload_3"); + } + + @Override + public void lmul() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lmul"); + } + + @Override + public void lneg() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lneg"); + } + + @Override + public void lookupswitch(int defaultPcOffset, int nEntries) { + pw.printf("%s%3d: %s default:%+d\n", prefix, cf.getPc(), "lookupswitch", defaultPcOffset); + cf.parseLookupSwitchEntries(this, nEntries); + } + @Override + public void lookupswitchEntry(int index, int match, int pcOffset){ + pw.printf("%s %d : %+d (%d)\n", prefix, match, pcOffset, (cf.getPc() + pcOffset)); + } + + + @Override + public void lor() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lor"); + } + + @Override + public void lrem() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lrem"); + } + + @Override + public void lreturn() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lreturn"); + } + + @Override + public void lshl() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lshl"); + } + + @Override + public void lshr() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lshr"); + } + + @Override + public void lstore(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "lstore", localVarIndex); + } + + @Override + public void lstore_0() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lstore_0"); + } + + @Override + public void lstore_1() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lstore_1"); + } + + @Override + public void lstore_2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lstore_2"); + } + + @Override + public void lstore_3() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lstore_3"); + } + + @Override + public void lsub() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lsub"); + } + + @Override + public void lushr() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lushr"); + } + + @Override + public void lxor() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "lxor"); + } + + @Override + public void monitorenter() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "monitorenter"); + } + + @Override + public void monitorexit() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "monitorexit"); + } + + @Override + public void multianewarray(int cpClassIndex, int dimensions) { + pw.printf("%s%3d: %s @%d(\"%s\") dim: %d\n", prefix, cf.getPc(), "multianewarray", + cpClassIndex, cf.classNameAt(cpClassIndex), dimensions); + } + + @Override + public void new_(int cpClassIndex) { + pw.printf("%s%3d: %s @%d(\"%s\")\n", prefix, cf.getPc(), "new", + cpClassIndex, cf.classNameAt(cpClassIndex)); + } + + @Override + public void newarray(int typeCode) { + pw.printf("%s%3d: %s %s[]\n", prefix, cf.getPc(), "newarray", cf.getTypeName(typeCode)); + } + + @Override + public void nop() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "nop"); + } + + @Override + public void pop() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "pop"); + } + + @Override + public void pop2() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "pop2"); + } + + @Override + public void putfield(int cpFieldRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "putfield", cpFieldRefIndex, + cf.fieldClassNameAt(cpFieldRefIndex), + cf.fieldNameAt(cpFieldRefIndex), + cf.fieldDescriptorAt(cpFieldRefIndex)); + } + + @Override + public void putstatic(int cpFieldRefIndex) { + pw.printf("%s%3d: %s @%d(\"%s\",\"%s\",\"%s\")\n", prefix, cf.getPc(), "putstatic", cpFieldRefIndex, + cf.fieldClassNameAt(cpFieldRefIndex), + cf.fieldNameAt(cpFieldRefIndex), + cf.fieldDescriptorAt(cpFieldRefIndex)); + } + + @Override + public void ret(int localVarIndex) { + pw.printf("%s%3d: %s [%d]\n", prefix, cf.getPc(), "ret", localVarIndex); + } + + @Override + public void return_() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "return"); + } + + @Override + public void saload() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "saload"); + } + + @Override + public void sastore() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "sastore"); + } + + @Override + public void sipush(int val) { + pw.printf("%s%3d: %s %d\n", prefix, cf.getPc(), "sipush", val); + } + + @Override + public void swap() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "swap"); + } + + @Override + public void tableswitch(int defaultPcOffset, int low, int high) { + pw.printf("%s%3d: %s [%d..%d] default: %+d\n", prefix, cf.getPc(), "tableswitch", low, high, defaultPcOffset); + cf.parseTableSwitchEntries(this, low, high); + } + @Override + public void tableswitchEntry(int val, int pcOffset){ + pw.printf("%s %d: %+d (%d)\n", prefix, val, pcOffset, (cf.getPc() + pcOffset)); + } + + @Override + public void wide() { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), "wide"); + } + + @Override + public void unknown(int bytecode) { + pw.printf("%s%3d: %s\n", prefix, cf.getPc(), ""); + } + + +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMByteCodeReader.java b/src/main/gov/nasa/jpf/jvm/JVMByteCodeReader.java new file mode 100644 index 0000000..0eb5796 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMByteCodeReader.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +/** + * interface to process bytecode + */ +public interface JVMByteCodeReader { + + void aconst_null(); + void aload(int localVarIndex); + void aload_0(); + void aload_1(); + void aload_2(); + void aload_3(); + void aaload(); + void astore(int localVarIndex); + void astore_0(); + void astore_1(); + void astore_2(); + void astore_3(); + void aastore(); + void areturn(); + void anewarray(int cpClassIndex); + void arraylength(); + void athrow(); + + void baload(); + void bastore(); + void bipush(int b); + + void caload(); + void castore(); + void checkcast(int cpClassIndex); + + void d2f(); + void d2i(); + void d2l(); + void dadd(); + void daload(); + void dastore(); + void dcmpg(); + void dcmpl(); + void dconst_0(); + void dconst_1(); + void ddiv(); + void dload(int localVarIndex); + void dload_0(); + void dload_1(); + void dload_2(); + void dload_3(); + void dmul(); + void dneg(); + void drem(); + void dreturn(); + void dstore(int localVarIndex); + void dstore_0(); + void dstore_1(); + void dstore_2(); + void dstore_3(); + void dsub(); + void dup(); + void dup_x1(); + void dup_x2(); + void dup2(); + void dup2_x1(); + void dup2_x2(); + + void f2d(); + void f2i(); + void f2l(); + void fadd(); + void faload(); + void fastore(); + void fcmpg(); + void fcmpl(); + void fconst_0(); + void fconst_1(); + void fconst_2(); + void fdiv(); + void fload(int localVarIndex); + void fload_0(); + void fload_1(); + void fload_2(); + void fload_3(); + void fmul(); + void fneg(); + void frem(); + void freturn(); + void fstore(int localVarIndex); + void fstore_0(); + void fstore_1(); + void fstore_2(); + void fstore_3(); + void fsub(); + + void getfield(int cpFieldRefIndex); + void getstatic(int cpFieldRefIndex); + void goto_(int pcOffset); + void goto_w (int pcOffset); + + void i2b(); + void i2c(); + void i2d(); + void i2f(); + void i2l(); + void i2s(); + void iadd(); + void iaload(); + void iand(); + void iastore(); + void iconst_m1(); + void iconst_0(); + void iconst_1(); + void iconst_2(); + void iconst_3(); + void iconst_4(); + void iconst_5(); + void idiv(); + void if_acmpeq(int pcOffset); + void if_acmpne(int pcOffset); + void if_icmpeq(int pcOffset); + void if_icmpne(int pcOffset); + void if_icmplt(int pcOffset); + void if_icmpge(int pcOffset); + void if_icmpgt(int pcOffset); + void if_icmple(int pcOffset); + void ifeq(int pcOffset); + void ifne(int pcOffset); + void iflt(int pcOffset); + void ifge(int pcOffset); + void ifgt(int pcOffset); + void ifle(int pcOffset); + void ifnonnull(int pcOffset); + void ifnull(int pcOffset); + void iinc(int localVarIndex, int incConstant); + void iload(int localVarIndex); + void iload_0(); + void iload_1(); + void iload_2(); + void iload_3(); + void imul(); + void ineg(); + void instanceof_(int cpClassIndex); + void invokeinterface (int cpInterfaceMethodRefIndex, int count, int zero); + void invokedynamic (int cpInvokeDynamicIndex); + void invokespecial (int cpMethodRefIndex); + void invokestatic (int cpMethodRefIndex); + void invokevirtual (int cpMethodRefIndex); + void ior(); + void irem(); + void ireturn(); + void ishl(); + void ishr(); + void istore(int localVarIndex); + void istore_0(); + void istore_1(); + void istore_2(); + void istore_3(); + void isub(); + void iushr(); + void ixor(); + + void jsr(int pcOffset); + void jsr_w(int pcOffset); + + void l2d(); + void l2f(); + void l2i(); + void ladd(); + void laload(); + void land(); + void lastore(); + void lcmp(); + void lconst_0(); + void lconst_1(); + void ldc_(int cpIntOrFloatOrStringIndex); + void ldc_w_(int cpIntOrFloatOrStringIndex); + void ldc2_w(int cpLongOrDoubleIndex); + void ldiv(); + void lload(int localVarIndex); + void lload_0(); + void lload_1(); + void lload_2(); + void lload_3(); + void lmul(); + void lneg(); + void lookupswitch(int defaultPcOffset, int nEntries); + void lookupswitchEntry(int index, int match, int pcOffset); + void lor(); + void lrem(); + void lreturn(); + void lshl(); + void lshr(); + void lstore(int localVarIndex); + void lstore_0(); + void lstore_1(); + void lstore_2(); + void lstore_3(); + void lsub(); + void lushr(); + void lxor(); + + void monitorenter(); + void monitorexit(); + void multianewarray(int cpClassIndex, int dimensions); + + void new_(int cpClassIndex); + void newarray(int typeCode); + void nop(); + + void pop(); + void pop2(); + void putfield(int cpFieldRefIndex); + void putstatic(int cpFieldRefIndex); + + void ret(int localVarIndex); + void return_(); + + void saload(); + void sastore(); + void sipush(int val); + void swap(); + + void tableswitch(int defaultPcOffset, int low, int high); + void tableswitchEntry(int value, int pcOffset); + + void wide (); + + void unknown(int bytecode); +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMByteCodeReaderAdapter.java b/src/main/gov/nasa/jpf/jvm/JVMByteCodeReaderAdapter.java new file mode 100644 index 0000000..7b7ea3b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMByteCodeReaderAdapter.java @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.jvm.JVMByteCodeReader; + +/** + * empty implementation of a JVMByteCodeReader, to efficiently allow overriding + * single methods + */ +public class JVMByteCodeReaderAdapter implements JVMByteCodeReader { + + @Override + public void aconst_null() {} + @Override + public void aload(int localVarIndex) {} + @Override + public void aload_0() {} + @Override + public void aload_1() {} + @Override + public void aload_2() {} + @Override + public void aload_3() {} + @Override + public void aaload() {} + @Override + public void astore(int localVarIndex) {} + @Override + public void astore_0() {} + @Override + public void astore_1() {} + @Override + public void astore_2() {} + @Override + public void astore_3() {} + @Override + public void aastore() {} + @Override + public void areturn() {} + @Override + public void anewarray(int cpClassIndex) {} + @Override + public void arraylength() {} + @Override + public void athrow() {} + + @Override + public void baload() {} + @Override + public void bastore() {} + @Override + public void bipush(int b) {} + + @Override + public void caload() {} + @Override + public void castore() {} + @Override + public void checkcast(int cpClassIndex) {} + + @Override + public void d2f() {} + @Override + public void d2i() {} + @Override + public void d2l() {} + @Override + public void dadd() {} + @Override + public void daload() {} + @Override + public void dastore() {} + @Override + public void dcmpg() {} + @Override + public void dcmpl() {} + @Override + public void dconst_0() {} + @Override + public void dconst_1() {} + @Override + public void ddiv() {} + @Override + public void dload(int localVarIndex) {} + @Override + public void dload_0() {} + @Override + public void dload_1() {} + @Override + public void dload_2() {} + @Override + public void dload_3() {} + @Override + public void dmul() {} + @Override + public void dneg() {} + @Override + public void drem() {} + @Override + public void dreturn() {} + @Override + public void dstore(int localVarIndex) {} + @Override + public void dstore_0() {} + @Override + public void dstore_1() {} + @Override + public void dstore_2() {} + @Override + public void dstore_3() {} + @Override + public void dsub() {} + @Override + public void dup() {} + @Override + public void dup_x1() {} + @Override + public void dup_x2() {} + @Override + public void dup2() {} + @Override + public void dup2_x1() {} + @Override + public void dup2_x2() {} + + @Override + public void f2d() {} + @Override + public void f2i() {} + @Override + public void f2l() {} + @Override + public void fadd() {} + @Override + public void faload() {} + @Override + public void fastore() {} + @Override + public void fcmpg() {} + @Override + public void fcmpl() {} + @Override + public void fconst_0() {} + @Override + public void fconst_1() {} + @Override + public void fconst_2() {} + @Override + public void fdiv() {} + @Override + public void fload(int localVarIndex) {} + @Override + public void fload_0() {} + @Override + public void fload_1() {} + @Override + public void fload_2() {} + @Override + public void fload_3() {} + @Override + public void fmul() {} + @Override + public void fneg() {} + @Override + public void frem() {} + @Override + public void freturn() {} + @Override + public void fstore(int localVarIndex) {} + @Override + public void fstore_0() {} + @Override + public void fstore_1() {} + @Override + public void fstore_2() {} + @Override + public void fstore_3() {} + @Override + public void fsub() {} + + @Override + public void getfield(int cpFieldRefIndex) {} + @Override + public void getstatic(int cpFieldRefIndex) {} + @Override + public void goto_(int pcOffset) {} + @Override + public void goto_w (int pcOffset) {} + + @Override + public void i2b() {} + @Override + public void i2c() {} + @Override + public void i2d() {} + @Override + public void i2f() {} + @Override + public void i2l() {} + @Override + public void i2s() {} + @Override + public void iadd() {} + @Override + public void iaload() {} + @Override + public void iand() {} + @Override + public void iastore() {} + @Override + public void iconst_m1() {} + @Override + public void iconst_0() {} + @Override + public void iconst_1() {} + @Override + public void iconst_2() {} + @Override + public void iconst_3() {} + @Override + public void iconst_4() {} + @Override + public void iconst_5() {} + @Override + public void idiv() {} + @Override + public void if_acmpeq(int pcOffset) {} + @Override + public void if_acmpne(int pcOffset) {} + @Override + public void if_icmpeq(int pcOffset) {} + @Override + public void if_icmpne(int pcOffset) {} + @Override + public void if_icmplt(int pcOffset) {} + @Override + public void if_icmpge(int pcOffset) {} + @Override + public void if_icmpgt(int pcOffset) {} + @Override + public void if_icmple(int pcOffset) {} + @Override + public void ifeq(int pcOffset) {} + @Override + public void ifne(int pcOffset) {} + @Override + public void iflt(int pcOffset) {} + @Override + public void ifge(int pcOffset) {} + @Override + public void ifgt(int pcOffset) {} + @Override + public void ifle(int pcOffset) {} + @Override + public void ifnonnull(int pcOffset) {} + @Override + public void ifnull(int pcOffset) {} + @Override + public void iinc(int localVarIndex, int incConstant) {} + @Override + public void iload(int localVarIndex) {} + @Override + public void iload_0() {} + @Override + public void iload_1() {} + @Override + public void iload_2() {} + @Override + public void iload_3() {} + @Override + public void imul() {} + @Override + public void ineg() {} + @Override + public void instanceof_(int cpClassIndex) {} + @Override + public void invokeinterface (int cpInterfaceMethodRefIndex, int count, int zero) {} + @Override + public void invokedynamic (int cpInvokeDynamicIndex) {} + @Override + public void invokespecial (int cpMethodRefIndex) {} + @Override + public void invokestatic (int cpMethodRefIndex) {} + @Override + public void invokevirtual (int cpMethodRefIndex) {} + @Override + public void ior() {} + @Override + public void irem() {} + @Override + public void ireturn() {} + @Override + public void ishl() {} + @Override + public void ishr() {} + @Override + public void istore(int localVarIndex) {} + @Override + public void istore_0() {} + @Override + public void istore_1() {} + @Override + public void istore_2() {} + @Override + public void istore_3() {} + @Override + public void isub() {} + @Override + public void iushr() {} + @Override + public void ixor() {} + + @Override + public void jsr(int pcOffset) {} + @Override + public void jsr_w(int pcOffset) {} + + @Override + public void l2d() {} + @Override + public void l2f() {} + @Override + public void l2i() {} + @Override + public void ladd() {} + @Override + public void laload() {} + @Override + public void land() {} + @Override + public void lastore() {} + @Override + public void lcmp() {} + @Override + public void lconst_0() {} + @Override + public void lconst_1() {} + @Override + public void ldc_(int cpIntOrFloatOrStringIndex) {} + @Override + public void ldc_w_(int cpIntOrFloatOrStringIndex) {} + @Override + public void ldc2_w(int cpLongOrDoubleIndex) {} + @Override + public void ldiv() {} + @Override + public void lload(int localVarIndex) {} + @Override + public void lload_0() {} + @Override + public void lload_1() {} + @Override + public void lload_2() {} + @Override + public void lload_3() {} + @Override + public void lmul() {} + @Override + public void lneg() {} + @Override + public void lookupswitch(int defaultPcOffset, int nEntries) {} + @Override + public void lookupswitchEntry(int index, int match, int pcOffset) {} + @Override + public void lor() {} + @Override + public void lrem() {} + @Override + public void lreturn() {} + @Override + public void lshl() {} + @Override + public void lshr() {} + @Override + public void lstore(int localVarIndex) {} + @Override + public void lstore_0() {} + @Override + public void lstore_1() {} + @Override + public void lstore_2() {} + @Override + public void lstore_3() {} + @Override + public void lsub() {} + @Override + public void lushr() {} + @Override + public void lxor() {} + + @Override + public void monitorenter() {} + @Override + public void monitorexit() {} + @Override + public void multianewarray(int cpClassIndex, int dimensions) {} + + @Override + public void new_(int cpClassIndex) {} + @Override + public void newarray(int typeCode) {} + @Override + public void nop() {} + + @Override + public void pop() {} + @Override + public void pop2() {} + @Override + public void putfield(int cpFieldRefIndex) {} + @Override + public void putstatic(int cpFieldRefIndex) {} + + @Override + public void ret(int localVarIndex) {} + @Override + public void return_() {} + + @Override + public void saload() {} + @Override + public void sastore() {} + @Override + public void sipush(int val) {} + @Override + public void swap() {} + + @Override + public void tableswitch(int defaultPcOffset, int low, int high) {} + @Override + public void tableswitchEntry(int value, int pcOffset) {} + + @Override + public void wide () {} + + @Override + public void unknown(int bytecode) {} +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMClassFileContainer.java b/src/main/gov/nasa/jpf/jvm/JVMClassFileContainer.java new file mode 100644 index 0000000..94239e0 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMClassFileContainer.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.vm.AnnotationInfo; +import gov.nasa.jpf.vm.ClassFileContainer; +import gov.nasa.jpf.vm.ClassFileMatch; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ClassParseException; + +/** + * ClassFileContainer that holds Java classfiles + */ +public abstract class JVMClassFileContainer extends ClassFileContainer { + + // the VM and container type specific info we need to instantiate a ClassInfo from this container + public class JVMClassFileMatch extends ClassFileMatch { + byte[] data; + + JVMClassFileMatch (String typeName, String url, byte[] data) { + super(typeName, url); + + this.data = data; + } + + @Override + public ClassFileContainer getContainer(){ + return JVMClassFileContainer.this; + } + + public byte[] getData(){ + return data; + } + + @Override + public JVMClassInfo createClassInfo (ClassLoaderInfo loader) throws ClassParseException { + JVMSystemClassLoaderInfo sysCli = (JVMSystemClassLoaderInfo)loader.getSystemClassLoader(); + + JVMCodeBuilder cb = sysCli.getCodeBuilder(typeName); + ClassFile cf = new ClassFile(data); + + return new JVMClassInfo( typeName, loader, cf, url, cb); + } + + @Override + public AnnotationInfo createAnnotationInfo (ClassLoaderInfo loader) throws ClassParseException { + ClassFile cf = new ClassFile(data); + JVMAnnotationParser parser = new JVMAnnotationParser(cf); + + return new AnnotationInfo(typeName, loader, parser); + } + } + + protected JVMClassFileContainer (String name, String url) { + super(name, url); + } + + @Override + public String getClassURL (String typeName){ + return getURL() + typeName.replace('.', '/') + ".class"; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMClassInfo.java b/src/main/gov/nasa/jpf/jvm/JVMClassInfo.java new file mode 100644 index 0000000..3cd1214 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMClassInfo.java @@ -0,0 +1,950 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.util.Misc; +import gov.nasa.jpf.util.StringSetMatcher; +import gov.nasa.jpf.vm.*; + +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.LinkedHashMap; + +/** + * a ClassInfo that was created from a Java classfile + */ +public class JVMClassInfo extends ClassInfo { + + /** + * this is the inner class that does the actual ClassInfo initialization from ClassFile. It is an inner class so that + * (a) it can set ClassInfo fields, (b) it can extend ClassFileReaderAdapter, and (c) we don't clutter JVMClassInfo with + * fields that are only temporarily used during parsing + */ + class Initializer extends ClassFileReaderAdapter { + protected ClassFile cf; + protected JVMCodeBuilder cb; + + public Initializer (ClassFile cf, JVMCodeBuilder cb) throws ClassParseException { + this.cf = cf; + this.cb = cb; + + cf.parse(this); + } + + @Override + public void setClass (ClassFile cf, String clsName, String superClsName, int flags, int cpCount) throws ClassParseException { + JVMClassInfo.this.setClass(clsName, superClsName, flags, cpCount); + } + + @Override + public void setClassAttribute (ClassFile cf, int attrIndex, String name, int attrLength) { + if (name == ClassFile.SOURCE_FILE_ATTR) { + cf.parseSourceFileAttr(this, null); + + } else if (name == ClassFile.SIGNATURE_ATTR) { + cf.parseSignatureAttr(this, JVMClassInfo.this); + + } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) { + cf.parseAnnotationsAttr(this, JVMClassInfo.this); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) { + //cf.parseAnnotationsAttr(this, ClassInfo.this); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) { + cf.parseTypeAnnotationsAttr(this, JVMClassInfo.this); + + } else if (name == ClassFile.INNER_CLASSES_ATTR) { + cf.parseInnerClassesAttr(this, JVMClassInfo.this); + + } else if (name == ClassFile.ENCLOSING_METHOD_ATTR) { + cf.parseEnclosingMethodAttr(this, JVMClassInfo.this); + + } else if (name == ClassFile.BOOTSTRAP_METHOD_ATTR) { + cf.parseBootstrapMethodAttr(this, JVMClassInfo.this); + + } + } + + @Override + public void setBootstrapMethodCount (ClassFile cf, Object tag, int count) { + bootstrapMethods = new BootstrapMethodInfo[count]; + } + + @Override + public void setBootstrapMethod (ClassFile cf, Object tag, int idx, int refKind, String cls, String mth, String descriptor, int[] cpArgs) { + + int lambdaRefKind = cf.mhRefTypeAt(cpArgs[1]); + + int mrefIdx = cf.mhMethodRefIndexAt(cpArgs[1]); + String clsName = cf.methodClassNameAt(mrefIdx).replace('/', '.'); + ClassInfo eclosingLambdaCls; + + if(!clsName.equals(JVMClassInfo.this.getName())) { + eclosingLambdaCls = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); + } else { + eclosingLambdaCls = JVMClassInfo.this; + } + + assert (eclosingLambdaCls!=null); + + String mthName = cf.methodNameAt(mrefIdx); + String signature = cf.methodDescriptorAt(mrefIdx); + + MethodInfo lambdaBody = eclosingLambdaCls.getMethod(mthName + signature, false); + + String samDescriptor = cf.methodTypeDescriptorAt(cpArgs[2]); + + if(lambdaBody!=null) { + bootstrapMethods[idx] = new BootstrapMethodInfo(lambdaRefKind, JVMClassInfo.this, lambdaBody, samDescriptor); + } + } + + //--- inner/enclosing classes + @Override + public void setInnerClassCount (ClassFile cf, Object tag, int classCount) { + innerClassNames = new String[classCount]; + } + + @Override + public void setInnerClass (ClassFile cf, Object tag, int innerClsIndex, + String outerName, String innerName, String innerSimpleName, int accessFlags) { + // Ok, this is a total mess - some names are in dot notation, others use '/' + // and to make it even more confusing, some InnerClass attributes refer NOT + // to the currently parsed class, so we have to check if we are the outerName, + // but then 'outerName' can also be null instead of our own name. + // Oh, and there are also InnerClass attributes that have their own name as inner names + // (see java/lang/String$CaseInsensitiveComparator or ...System and java/lang/System$1 for instance) + if (outerName != null) { + outerName = Types.getClassNameFromTypeName(outerName); + } + + innerName = Types.getClassNameFromTypeName(innerName); + if (!innerName.equals(name)) { + innerClassNames[innerClsIndex] = innerName; + + } else { + // this refers to ourself, and can be a force fight with setEnclosingMethod + if (outerName != null) { // only set if this is a direct member, otherwise taken from setEnclosingMethod + setEnclosingClass(outerName); + } + } + } + + @Override + public void setEnclosingMethod (ClassFile cf, Object tag, String enclosingClassName, String enclosingMethodName, String descriptor) { + setEnclosingClass(enclosingClassName); + + if (enclosingMethodName != null) { + JVMClassInfo.this.setEnclosingMethod(enclosingMethodName + descriptor); + } + } + + @Override + public void setInnerClassesDone (ClassFile cf, Object tag) { + // we have to check if we allocated too many - see the mess above + for (int i = 0; i < innerClassNames.length; i++) { + innerClassNames = Misc.stripNullElements(innerClassNames); + } + } + + //--- source file + @Override + public void setSourceFile (ClassFile cf, Object tag, String fileName) { + JVMClassInfo.this.setSourceFile(fileName); + } + + //--- interfaces + @Override + public void setInterfaceCount (ClassFile cf, int ifcCount) { + interfaceNames = new String[ifcCount]; + } + + @Override + public void setInterface (ClassFile cf, int ifcIndex, String ifcName) { + interfaceNames[ifcIndex] = Types.getClassNameFromTypeName(ifcName); + } + + //--- fields + // unfortunately they are stored together in the ClassFile, i.e. we + // have to split them up once we are done + + protected FieldInfo[] fields; + protected FieldInfo curFi; // need to cache for attributes + + @Override + public void setFieldCount (ClassFile cf, int fieldCount) { + if (fieldCount > 0){ + fields = new FieldInfo[fieldCount]; + } else { + fields = null; + } + } + + @Override + public void setField (ClassFile cf, int fieldIndex, int accessFlags, String name, String descriptor) { + FieldInfo fi = FieldInfo.create(name, descriptor, accessFlags); + fields[fieldIndex] = fi; + curFi = fi; // for attributes + } + + @Override + public void setFieldAttribute (ClassFile cf, int fieldIndex, int attrIndex, String name, int attrLength) { + if (name == ClassFile.SIGNATURE_ATTR) { + cf.parseSignatureAttr(this, curFi); + + } else if (name == ClassFile.CONST_VALUE_ATTR) { + cf.parseConstValueAttr(this, curFi); + + } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) { + cf.parseAnnotationsAttr(this, curFi); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) { + cf.parseTypeAnnotationsAttr(this, curFi); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) { + //cf.parseAnnotationsAttr(this, curFi); + } + } + + @Override + public void setConstantValue (ClassFile cf, Object tag, Object constVal) { + curFi.setConstantValue(constVal); + } + + @Override + public void setFieldsDone (ClassFile cf) { + setFields(fields); + } + + //--- declaredMethods + protected MethodInfo curMi; + + @Override + public void setMethodCount (ClassFile cf, int methodCount) { + methods = new LinkedHashMap(); + } + + @Override + public void setMethod (ClassFile cf, int methodIndex, int accessFlags, String name, String signature) { + MethodInfo mi = MethodInfo.create(name, signature, accessFlags); + curMi = mi; + } + + @Override + public void setMethodDone (ClassFile cf, int methodIndex){ + curMi.setLocalVarAnnotations(); + + JVMClassInfo.this.setMethod(curMi); + } + + @Override + public void setMethodAttribute (ClassFile cf, int methodIndex, int attrIndex, String name, int attrLength) { + if (name == ClassFile.CODE_ATTR) { + cf.parseCodeAttr(this, curMi); + + } else if (name == ClassFile.SIGNATURE_ATTR) { + cf.parseSignatureAttr(this, curMi); + + } else if (name == ClassFile.EXCEPTIONS_ATTR) { + cf.parseExceptionAttr(this, curMi); + + } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) { + cf.parseAnnotationsAttr(this, curMi); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) { + //cf.parseAnnotationsAttr(this, curMi); + } else if (name == ClassFile.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR) { + cf.parseParameterAnnotationsAttr(this, curMi); + + } else if (name == ClassFile.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR) { + //cf.parseParameterAnnotationsAttr(this, curMi); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) { + cf.parseTypeAnnotationsAttr(this, curMi); + } + + } + + //--- current methods throws list + protected String[] exceptions; + + @Override + public void setExceptionCount (ClassFile cf, Object tag, int exceptionCount) { + exceptions = new String[exceptionCount]; + } + + @Override + public void setException (ClassFile cf, Object tag, int exceptionIndex, String exceptionType) { + exceptions[exceptionIndex] = Types.getClassNameFromTypeName(exceptionType); + } + + @Override + public void setExceptionsDone (ClassFile cf, Object tag) { + curMi.setThrownExceptions(exceptions); + } + + //--- current method exception handlers + protected ExceptionHandler[] handlers; + + @Override + public void setExceptionHandlerTableCount (ClassFile cf, Object tag, int exceptionTableCount) { + handlers = new ExceptionHandler[exceptionTableCount]; + } + + @Override + public void setExceptionHandler (ClassFile cf, Object tag, int handlerIndex, + int startPc, int endPc, int handlerPc, String catchType) { + ExceptionHandler xh = new ExceptionHandler(catchType, startPc, endPc, handlerPc); + handlers[handlerIndex] = xh; + } + + @Override + public void setExceptionHandlerTableDone (ClassFile cf, Object tag) { + curMi.setExceptionHandlers(handlers); + } + + //--- current method code + @Override + public void setCode (ClassFile cf, Object tag, int maxStack, int maxLocals, int codeLength) { + curMi.setMaxLocals(maxLocals); + curMi.setMaxStack(maxStack); + + cb.reset(cf, curMi); + + cf.parseBytecode(cb, tag, codeLength); + cb.installCode(); + } + + @Override + public void setCodeAttribute (ClassFile cf, Object tag, int attrIndex, String name, int attrLength) { + if (name == ClassFile.LINE_NUMBER_TABLE_ATTR) { + cf.parseLineNumberTableAttr(this, tag); + + } else if (name == ClassFile.LOCAL_VAR_TABLE_ATTR) { + cf.parseLocalVarTableAttr(this, tag); + + } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ + cf.parseTypeAnnotationsAttr(this, tag); + } + } + + //--- current method line numbers + protected int[] lines, startPcs; + + @Override + public void setLineNumberTableCount (ClassFile cf, Object tag, int lineNumberCount) { + lines = new int[lineNumberCount]; + startPcs = new int[lineNumberCount]; + } + + @Override + public void setLineNumber (ClassFile cf, Object tag, int lineIndex, int lineNumber, int startPc) { + lines[lineIndex] = lineNumber; + startPcs[lineIndex] = startPc; + } + + @Override + public void setLineNumberTableDone (ClassFile cf, Object tag) { + curMi.setLineNumbers(lines, startPcs); + } + + //--- current method local variables + protected LocalVarInfo[] localVars; + + @Override + public void setLocalVarTableCount (ClassFile cf, Object tag, int localVarCount) { + localVars = new LocalVarInfo[localVarCount]; + } + + @Override + public void setLocalVar (ClassFile cf, Object tag, int localVarIndex, + String varName, String descriptor, int scopeStartPc, int scopeEndPc, int slotIndex) { + LocalVarInfo lvi = new LocalVarInfo(varName, descriptor, "", scopeStartPc, scopeEndPc, slotIndex); + localVars[localVarIndex] = lvi; + } + + @Override + public void setLocalVarTableDone (ClassFile cf, Object tag) { + curMi.setLocalVarTable(localVars); + } + + //--- annotations + protected AnnotationInfo[] annotations; + protected AnnotationInfo curAi; + protected AnnotationInfo[][] parameterAnnotations; + protected Object[] values; + + //--- declaration annotations + + @Override + public void setAnnotationCount (ClassFile cf, Object tag, int annotationCount) { + annotations = new AnnotationInfo[annotationCount]; + } + + @Override + public void setAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) { + if (tag instanceof InfoObject) { + curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + annotations[annotationIndex] = curAi; + } + } + + @Override + public void setAnnotationsDone (ClassFile cf, Object tag) { + if (tag instanceof InfoObject) { + ((InfoObject) tag).addAnnotations(annotations); + } + } + + @Override + public void setParameterCount (ClassFile cf, Object tag, int parameterCount) { + parameterAnnotations = new AnnotationInfo[parameterCount][]; + } + + @Override + public void setParameterAnnotationCount (ClassFile cf, Object tag, int paramIndex, int annotationCount) { + annotations = new AnnotationInfo[annotationCount]; + parameterAnnotations[paramIndex] = annotations; + } + + @Override + public void setParameterAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) { + curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + annotations[annotationIndex] = curAi; + } + + @Override + public void setParametersDone (ClassFile cf, Object tag) { + curMi.setParameterAnnotations(parameterAnnotations); + } + + //--- Java 8 type annotations + + @Override + public void setTypeAnnotationCount(ClassFile cf, Object tag, int annotationCount){ + annotations = new AnnotationInfo[annotationCount]; + } + + @Override + public void setTypeParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int typeIndex, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new TypeParameterAnnotationInfo(base, targetType, typePath, typeIndex); + annotations[annotationIndex] = curAi; + } + @Override + public void setSuperTypeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int superTypeIdx, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new SuperTypeAnnotationInfo(base, targetType, typePath, superTypeIdx); + annotations[annotationIndex] = curAi; + } + @Override + public void setTypeParameterBoundAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int typeIndex, int boundIndex, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new TypeParameterBoundAnnotationInfo(base, targetType, typePath, typeIndex, boundIndex); + annotations[annotationIndex] = curAi; + } + @Override + public void setTypeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new TypeAnnotationInfo(base, targetType, typePath); + annotations[annotationIndex] = curAi; + } + @Override + public void setFormalParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int paramIndex, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new FormalParameterAnnotationInfo(base, targetType, typePath, paramIndex); + annotations[annotationIndex] = curAi; + } + @Override + public void setThrowsAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int throwsTypeIdx, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new ThrowsAnnotationInfo(base, targetType, typePath, throwsTypeIdx); + annotations[annotationIndex] = curAi; + } + @Override + public void setVariableAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + long[] scopeEntries, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + VariableAnnotationInfo vai = new VariableAnnotationInfo(base, targetType, typePath, scopeEntries); + curAi = vai; + annotations[annotationIndex] = curAi; + } + @Override + public void setExceptionParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int exceptionIndex, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi= new ExceptionParameterAnnotationInfo(base, targetType, typePath, exceptionIndex); + annotations[annotationIndex] = curAi; + } + @Override + public void setBytecodeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int offset, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new BytecodeAnnotationInfo(base, targetType, typePath, offset); + annotations[annotationIndex] = curAi; + } + @Override + public void setBytecodeTypeParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, + int offset, int typeArgIdx, short[] typePath, String annotationType){ + AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType)); + curAi = new BytecodeTypeParameterAnnotationInfo(base, targetType, typePath, offset, typeArgIdx); + annotations[annotationIndex] = curAi; + } + + @Override + public void setTypeAnnotationsDone(ClassFile cf, Object tag) { + if (tag instanceof InfoObject) { + int len = annotations.length; + AbstractTypeAnnotationInfo[] tais = new AbstractTypeAnnotationInfo[annotations.length]; + for (int i=0; i= 0) { + values[arrayIndex] = val; + } else { + curAi.setClonedEntryValue(elementName, val); + } + } + + @Override + public void setStringAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String val) { + if (arrayIndex >= 0) { + values[arrayIndex] = val; + } else { + curAi.setClonedEntryValue(elementName, val); + } + } + + @Override + public void setClassAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, + int arrayIndex, String typeName) { + Object val = AnnotationInfo.getClassValue(typeName); + if (arrayIndex >= 0) { + values[arrayIndex] = val; + } else { + curAi.setClonedEntryValue(elementName, val); + } + } + + @Override + public void setEnumAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int arrayIndex, String enumType, String enumValue) { + Object val = AnnotationInfo.getEnumValue(enumType, enumValue); + if (arrayIndex >= 0) { + values[arrayIndex] = val; + } else { + curAi.setClonedEntryValue(elementName, val); + } + } + + @Override + public void setAnnotationValueElementCount (ClassFile cf, Object tag, int annotationIndex, int valueIndex, + String elementName, int elementCount) { + values = new Object[elementCount]; + } + + @Override + public void setAnnotationValueElementsDone (ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName) { + curAi.setClonedEntryValue(elementName, values); + } + + //--- common attrs + @Override + public void setSignature (ClassFile cf, Object tag, String signature) { + if (tag instanceof GenericSignatureHolder) { + ((GenericSignatureHolder) tag).setGenericSignature(signature); + } + } + } + + // since nested class init locking can explode the state space, we make it optional and controllable + protected static boolean nestedInit; + protected static StringSetMatcher includeNestedInit; + protected static StringSetMatcher excludeNestedInit; + + protected static boolean init (Config config){ + nestedInit = config.getBoolean("jvm.nested_init", false); + if (nestedInit){ + includeNestedInit = StringSetMatcher.getNonEmpty(config.getStringArray("jvm.nested_init.include")); + excludeNestedInit = StringSetMatcher.getNonEmpty(config.getStringArray("jvm.nested_init.exclude")); + } + + return true; + } + + JVMClassInfo (String name, ClassLoaderInfo cli, ClassFile cf, String srcUrl, JVMCodeBuilder cb) throws ClassParseException { + super( name, cli, srcUrl); + + new Initializer( cf, cb); // we just need the ctor + + resolveAndLink(); + } + + + //--- for annotation classinfos + + // called on the annotation classinfo + @Override + protected ClassInfo createAnnotationProxy (String proxyName){ + return new JVMClassInfo (this, proxyName, classLoader, null); + } + + // concrete proxy ctor + protected JVMClassInfo (ClassInfo ciAnnotation, String proxyName, ClassLoaderInfo cli, String url) { + super( ciAnnotation, proxyName, cli, url); + } + + /** + * This is called on the functional interface type. It creates a synthetic type which + * implements the functional interface and contains a method capturing the behavior + * of the lambda expression. + */ + @Override + protected ClassInfo createFuncObjClassInfo (BootstrapMethodInfo bootstrapMethod, String name, String samUniqueName, String[] fieldTypesName) { + return new JVMClassInfo(this, bootstrapMethod, name, samUniqueName, fieldTypesName); + } + + protected JVMClassInfo (ClassInfo funcInterface, BootstrapMethodInfo bootstrapMethod, String name, String samUniqueName, String[] fieldTypesName) { + super(funcInterface, bootstrapMethod, name, fieldTypesName); + + // creating a method corresponding to the single abstract method of the functional interface + methods = new HashMap(); + + MethodInfo fiMethod = funcInterface.getInterfaceAbstractMethod(); + int modifiers = fiMethod.getModifiers() & (~Modifier.ABSTRACT); + int nLocals = fiMethod.getArgumentsSize(); + int nOperands = this.nInstanceFields + nLocals; + + MethodInfo mi = new MethodInfo(fiMethod.getName(), fiMethod.getSignature(), modifiers, nLocals, nOperands); + mi.linkToClass(this); + + methods.put(mi.getUniqueName(), mi); + + setLambdaDirectCallCode(mi, bootstrapMethod); + + try { + resolveAndLink(); + } catch (ClassParseException e) { + // we do not even get here - this a synthetic class, and at this point + // the interfaces are already loaded. + } + } + + /** + * perform initialization of this class and its not-yet-initialized superclasses (top down), + * which includes calling clinit() methods + * + * This is overridden here to model a questionable yet consequential behavior of hotspot, which + * is holding derived class locks when initializing base classes. The generic implementation in + * ClassInfo uses non-nested locks (i.e. A.clinit() only synchronizes on A.class) and hence cannot + * produce the same static init deadlocks as hotspot. In order to catch such defects we implement + * nested locking here. + * + * The main difference is that the generic implementation only pushes DCSFs for required clinits + * and otherwise doesn't lock anything. Here, we create one static init specific DCSF which wraps + * all clinits in nested monitorenter/exits. We create this even if there is no clinit so that we + * mimic hotspot locking. + * + * Note this scheme also enables us to get rid of the automatic clinit sync (they don't have + * a 0x20 sync modifier in classfiles) + * + * @return true if client needs to re-execute because we pushed DirectCallStackFrames + */ + @Override + public boolean initializeClass(ThreadInfo ti) { + if (needsInitialization(ti)) { + if (nestedInit && StringSetMatcher.isMatch(name, includeNestedInit, excludeNestedInit)) { + registerClass(ti); // this is recursively upwards + int nOps = 2 * (getNumberOfSuperClasses() + 1); // this is just an upper bound for the number of operands we need + + MethodInfo miInitialize = new MethodInfo("[initializeClass]", "()V", Modifier.STATIC, 0, nOps); + JVMDirectCallStackFrame frame = new JVMDirectCallStackFrame(miInitialize, null); + JVMCodeBuilder cb = getSystemCodeBuilder(null, miInitialize); + + addClassInit(ti, frame, cb); // this is recursively upwards until we hit a initialized superclass + cb.directcallreturn(); + cb.installCode(); + + // this is normally initialized in the ctor, but at that point we don't have the code yet + frame.setPC(miInitialize.getFirstInsn()); + + ti.pushFrame(frame); + return true; // client has to re-execute, we pushed a stackframe + + + } else { // use generic initialization without nested locks (directly calling clinits) + return super.initializeClass(ti); + } + + } else { + return false; // nothing to do + } + } + + protected void addClassInit (ThreadInfo ti, JVMDirectCallStackFrame frame, JVMCodeBuilder cb){ + int clsObjRef = getClassObjectRef(); + + frame.pushRef(clsObjRef); + cb.monitorenter(); + + if (superClass != null && superClass.needsInitialization(ti)) { + ((JVMClassInfo) superClass).addClassInit(ti, frame, cb); // go recursive + } + + if (getMethod("()V", false) != null) { // do we have a clinit + cb.invokeclinit(this); + } else { + cb.finishclinit(this); + // we can't just do call ci.setInitialized() since that has to be deferred + } + + frame.pushRef(clsObjRef); + cb.monitorexit(); + } + + //--- call processing + + protected JVMCodeBuilder getSystemCodeBuilder (ClassFile cf, MethodInfo mi){ + JVMSystemClassLoaderInfo sysCl = (JVMSystemClassLoaderInfo) ClassLoaderInfo.getCurrentSystemClassLoader(); + JVMCodeBuilder cb = sysCl.getSystemCodeBuilder(cf, mi); + + return cb; + } + + /** + * to be called from super proxy ctor + * this needs to be in the VM specific ClassInfo because we need to create code + */ + @Override + protected void setAnnotationValueGetterCode (MethodInfo pmi, FieldInfo fi){ + JVMCodeBuilder cb = getSystemCodeBuilder(null, pmi); + + cb.aload(0); + cb.getfield( pmi.getName(), name, pmi.getReturnType()); + if (fi.isReference()) { + cb.areturn(); + } else { + if (fi.getStorageSize() == 1) { + cb.ireturn(); + } else { + cb.lreturn(); + } + } + + cb.installCode(); + } + + @Override + protected void setDirectCallCode (MethodInfo miDirectCall, MethodInfo miCallee){ + JVMCodeBuilder cb = getSystemCodeBuilder(null, miDirectCall); + + String calleeName = miCallee.getName(); + String calleeSig = miCallee.getSignature(); + + if (miCallee.isStatic()){ + if (miCallee.isClinit()) { + cb.invokeclinit(this); + } else { + cb.invokestatic( name, calleeName, calleeSig); + } + } else if (name.equals("") || miCallee.isPrivate()){ + cb.invokespecial( name, calleeName, calleeSig); + } else { + cb.invokevirtual( name, calleeName, calleeSig); + } + + cb.directcallreturn(); + + cb.installCode(); + } + + @Override + protected void setNativeCallCode (NativeMethodInfo miNative){ + JVMCodeBuilder cb = getSystemCodeBuilder(null, miNative); + + cb.executenative(miNative); + cb.nativereturn(); + + cb.installCode(); + } + + @Override + protected void setRunStartCode (MethodInfo miStub, MethodInfo miRun){ + JVMCodeBuilder cb = getSystemCodeBuilder(null, miStub); + + cb.runStart( miStub); + cb.invokevirtual( name, miRun.getName(), miRun.getSignature()); + cb.directcallreturn(); + + cb.installCode(); + } + + /** + * This method creates the body of the function object method that captures the + * lambda behavior. + */ + @Override + protected void setLambdaDirectCallCode (MethodInfo miDirectCall, BootstrapMethodInfo bootstrapMethod) { + + MethodInfo miCallee = bootstrapMethod.getLambdaBody(); + String samSignature = bootstrapMethod.getSamDescriptor(); + JVMCodeBuilder cb = getSystemCodeBuilder(null, miDirectCall); + + String calleeName = miCallee.getName(); + String calleeSig = miCallee.getSignature(); + + ClassInfo callerCi = miDirectCall.getClassInfo(); + + // loading free variables, which are used in the body of the lambda + // expression and captured by the lexical scope. These variables + // are stored by the fields of the synthetic function object class + int n = callerCi.getNumberOfInstanceFields(); + for(int i=0; i these should use interface types to avoid hardwiring our own instruction classes + protected TableSwitchInstruction tableswitchInsn; + protected LookupSwitchInstruction lookupswitchInsn; + + protected ArrayList code; + + protected int pc; // bytecode position within method code + protected int idx; // instruction index within MethodInfo + + // flag to remember wide immediate operand modification + boolean isWide; + + //--- for testing purposes + protected JVMCodeBuilder (JVMInstructionFactory ifact){ + this.code = new ArrayList(64); + this.insnFactory = ifact; + } + + + + // this is dangerous - it enables reuse of CodeBuilders, but + // you better make sure this does not get recursive or is used concurrently + public void reset (ClassFile classFile, MethodInfo targetMethod){ + this.cf = classFile; + this.mi = targetMethod; + + pc = 0; + idx = 0; + isWide = false; + + tableswitchInsn = null; + lookupswitchInsn = null; + + code.clear(); + } + + protected void add(Instruction insn){ + insn.setMethodInfo(mi); + insn.setLocation(idx++, pc); + code.add(insn); + } + + public void installCode(){ + Instruction[] a = code.toArray( new Instruction[code.size()]); + mi.setCode(a); + } + + public int getCodeSize(){ + return code.size(); + } + + //--- the factory methods + + @Override public void aconst_null() { + add( insnFactory.aconst_null()); + pc++; + } + + @Override public void aload(int localVarIndex) { + add( insnFactory.aload(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void aload_0() { + add( insnFactory.aload(0)); + pc++; + } + + @Override public void aload_1() { + add( insnFactory.aload(1)); + pc++; + } + + @Override public void aload_2() { + add( insnFactory.aload(2)); + pc++; + } + + @Override public void aload_3() { + add( insnFactory.aload(3)); + pc++; + } + + @Override public void aaload() { + add( insnFactory.aaload()); + pc++; + } + + @Override public void astore(int localVarIndex) { + add( insnFactory.astore(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void astore_0() { + add( insnFactory.astore(0)); + pc++; + } + + @Override public void astore_1() { + add( insnFactory.astore(1)); + pc++; + } + + @Override public void astore_2() { + add( insnFactory.astore(2)); + pc++; + } + + @Override public void astore_3() { + add( insnFactory.astore(3)); + pc++; + } + + @Override public void aastore() { + add( insnFactory.aastore()); + pc++; + } + + @Override public void areturn() { + add( insnFactory.areturn()); + pc++; + } + + @Override public void anewarray(int cpClassIndex) { + String clsName = cf.classNameAt(cpClassIndex); + add( insnFactory.anewarray(clsName)); + pc+=3; + } + + @Override public void arraylength() { + add( insnFactory.arraylength()); + pc++; + } + + @Override public void athrow() { + add( insnFactory.athrow()); + pc++; + } + + @Override public void baload() { + add( insnFactory.baload()); + pc++; + } + + @Override public void bastore() { + add( insnFactory.bastore()); + pc++; + } + + @Override public void bipush(int b) { + add( insnFactory.bipush(b)); + pc+=2; + } + + @Override public void caload() { + add( insnFactory.caload()); + pc++; + } + + @Override public void castore() { + add( insnFactory.castore()); + pc++; + } + + @Override public void checkcast(int cpClassIndex) { + String clsName = cf.classNameAt(cpClassIndex); + add( insnFactory.checkcast(clsName)); + pc+=3; + } + + @Override public void d2f() { + add( insnFactory.d2f()); + pc++; + } + + @Override public void d2i() { + add( insnFactory.d2i()); + pc++; + } + + @Override public void d2l() { + add( insnFactory.d2l()); + pc++; + } + + @Override public void dadd() { + add( insnFactory.dadd()); + pc++; + } + + @Override public void daload() { + add( insnFactory.daload()); + pc++; + } + + @Override public void dastore() { + add( insnFactory.dastore()); + pc++; + } + + @Override public void dcmpg() { + add( insnFactory.dcmpg()); + pc++; + } + + @Override public void dcmpl() { + add( insnFactory.dcmpl()); + pc++; + } + + @Override public void dconst_0() { + add( insnFactory.dconst_0()); + pc++; + } + + @Override public void dconst_1() { + add( insnFactory.dconst_1()); + pc++; + } + + @Override public void ddiv() { + add( insnFactory.ddiv()); + pc++; + } + + @Override public void dload(int localVarIndex) { + add( insnFactory.dload(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void dload_0() { + add( insnFactory.dload(0)); + pc++; + } + + @Override public void dload_1() { + add( insnFactory.dload(1)); + pc++; + } + + @Override public void dload_2() { + add( insnFactory.dload(2)); + pc++; + } + + @Override public void dload_3() { + add( insnFactory.dload(3)); + pc++; + } + + @Override public void dmul() { + add( insnFactory.dmul()); + pc++; + } + + @Override public void dneg() { + add( insnFactory.dneg()); + pc++; + } + + @Override public void drem() { + add( insnFactory.drem()); + pc++; + } + + @Override public void dreturn() { + add( insnFactory.dreturn()); + pc++; + } + + @Override public void dstore(int localVarIndex) { + add( insnFactory.dstore(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void dstore_0() { + add( insnFactory.dstore(0)); + pc++; + } + + @Override public void dstore_1() { + add( insnFactory.dstore(1)); + pc++; + } + + @Override public void dstore_2() { + add( insnFactory.dstore(2)); + pc++; + } + + @Override public void dstore_3() { + add( insnFactory.dstore(3)); + pc++; + } + + @Override public void dsub() { + add( insnFactory.dsub()); + pc++; + } + + @Override public void dup() { + add( insnFactory.dup()); + pc++; + } + + @Override public void dup_x1() { + add( insnFactory.dup_x1()); + pc++; + } + + @Override public void dup_x2() { + add( insnFactory.dup_x2()); + pc++; + } + + @Override public void dup2() { + add( insnFactory.dup2()); + pc++; + } + + @Override public void dup2_x1() { + add( insnFactory.dup2_x1()); + pc++; + } + + @Override public void dup2_x2() { + add( insnFactory.dup2_x2()); + pc++; + } + + @Override public void f2d() { + add( insnFactory.f2d()); + pc++; + } + + @Override public void f2i() { + add( insnFactory.f2i()); + pc++; + } + + @Override public void f2l() { + add( insnFactory.f2l()); + pc++; + } + + @Override public void fadd() { + add( insnFactory.fadd()); + pc++; + } + + @Override public void faload() { + add( insnFactory.faload()); + pc++; + } + + @Override public void fastore() { + add( insnFactory.fastore()); + pc++; + } + + @Override public void fcmpg() { + add( insnFactory.fcmpg()); + pc++; + } + + @Override public void fcmpl() { + add( insnFactory.fcmpl()); + pc++; + } + + @Override public void fconst_0() { + add( insnFactory.fconst_0()); + pc++; + } + + @Override public void fconst_1() { + add( insnFactory.fconst_1()); + pc++; + } + + @Override public void fconst_2() { + add( insnFactory.fconst_2()); + pc++; + } + + @Override public void fdiv() { + add( insnFactory.fdiv()); + pc++; + } + + @Override public void fload(int localVarIndex) { + add( insnFactory.fload(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void fload_0() { + add( insnFactory.fload(0)); + pc++; + } + + @Override public void fload_1() { + add( insnFactory.fload(1)); + pc++; + } + + @Override public void fload_2() { + add( insnFactory.fload(2)); + pc++; + } + + @Override public void fload_3() { + add( insnFactory.fload(3)); + pc++; + } + + @Override public void fmul() { + add( insnFactory.fmul()); + pc++; + } + + @Override public void fneg() { + add( insnFactory.fneg()); + pc++; + } + + @Override public void frem() { + add( insnFactory.frem()); + pc++; + } + + @Override public void freturn() { + add( insnFactory.freturn()); + pc++; + } + + @Override public void fstore(int localVarIndex) { + add( insnFactory.fstore(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void fstore_0() { + add( insnFactory.fstore(0)); + pc++; + } + + @Override public void fstore_1() { + add( insnFactory.fstore(1)); + pc++; + } + + @Override public void fstore_2() { + add( insnFactory.fstore(2)); + pc++; + } + + @Override public void fstore_3() { + add( insnFactory.fstore(3)); + pc++; + } + + @Override public void fsub() { + add( insnFactory.fsub()); + pc++; + } + + @Override public void getfield(int cpFieldRefIndex) { + String fieldName = cf.fieldNameAt(cpFieldRefIndex); + String clsName = cf.fieldClassNameAt(cpFieldRefIndex); + String fieldDescriptor = cf.fieldDescriptorAt(cpFieldRefIndex); + + add( insnFactory.getfield(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + public void getfield(String fieldName, String clsName, String fieldDescriptor){ + add( insnFactory.getfield(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + + @Override public void getstatic(int cpFieldRefIndex) { + String fieldName = cf.fieldNameAt(cpFieldRefIndex); + String clsName = cf.fieldClassNameAt(cpFieldRefIndex); + String fieldDescriptor = cf.fieldDescriptorAt(cpFieldRefIndex); + + add( insnFactory.getstatic(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + public void getstatic(String fieldName, String clsName, String fieldDescriptor){ + add( insnFactory.getstatic(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + + @Override public void goto_(int pcOffset) { + add( insnFactory.goto_(pc + pcOffset)); + pc+=3; + } + + @Override public void goto_w(int pcOffset) { + add( insnFactory.goto_w(pc + pcOffset)); + pc+=5; + } + + @Override public void i2b() { + add( insnFactory.i2b()); + pc++; + } + + @Override public void i2c() { + add( insnFactory.i2c()); + pc++; + } + + @Override public void i2d() { + add( insnFactory.i2d()); + pc++; + } + + @Override public void i2f() { + add( insnFactory.i2f()); + pc++; + } + + @Override public void i2l() { + add( insnFactory.i2l()); + pc++; + } + + @Override public void i2s() { + add( insnFactory.i2s()); + pc++; + } + + @Override public void iadd() { + add( insnFactory.iadd()); + pc++; + } + + @Override public void iaload() { + add( insnFactory.iaload()); + pc++; + } + + @Override public void iand() { + add( insnFactory.iand()); + pc++; + } + + @Override public void iastore() { + add( insnFactory.iastore()); + pc++; + } + + @Override public void iconst_m1() { + add( insnFactory.iconst_m1()); + pc++; + } + + @Override public void iconst_0() { + add( insnFactory.iconst_0()); + pc++; + } + + @Override public void iconst_1() { + add( insnFactory.iconst_1()); + pc++; + } + + @Override public void iconst_2() { + add( insnFactory.iconst_2()); + pc++; + } + + @Override public void iconst_3() { + add( insnFactory.iconst_3()); + pc++; + } + + @Override public void iconst_4() { + add( insnFactory.iconst_4()); + pc++; + } + + @Override public void iconst_5() { + add( insnFactory.iconst_5()); + pc++; + } + + @Override public void idiv() { + add( insnFactory.idiv()); + pc++; + } + + @Override public void if_acmpeq(int pcOffset) { + add( insnFactory.if_acmpeq(pc + pcOffset)); + pc+=3; + } + + @Override public void if_acmpne(int pcOffset) { + add( insnFactory.if_acmpne(pc + pcOffset)); + pc+=3; + } + + @Override public void if_icmpeq(int pcOffset) { + add( insnFactory.if_icmpeq(pc + pcOffset)); + pc+=3; + } + + @Override public void if_icmpne(int pcOffset) { + add( insnFactory.if_icmpne(pc + pcOffset)); + pc+=3; + } + + @Override public void if_icmplt(int pcOffset) { + add( insnFactory.if_icmplt(pc + pcOffset)); + pc+=3; + } + + @Override public void if_icmpge(int pcOffset) { + add( insnFactory.if_icmpge(pc + pcOffset)); + pc+=3; + } + + @Override public void if_icmpgt(int pcOffset) { + add( insnFactory.if_icmpgt(pc + pcOffset)); + pc+=3; + } + + @Override public void if_icmple(int pcOffset) { + add( insnFactory.if_icmple(pc + pcOffset)); + pc+=3; + } + + @Override public void ifeq(int pcOffset) { + add( insnFactory.ifeq(pc + pcOffset)); + pc+=3; + } + + @Override public void ifne(int pcOffset) { + add( insnFactory.ifne(pc + pcOffset)); + pc+=3; + } + + @Override public void iflt(int pcOffset) { + add( insnFactory.iflt(pc + pcOffset)); + pc+=3; + } + + @Override public void ifge(int pcOffset) { + add( insnFactory.ifge(pc + pcOffset)); + pc+=3; + } + + @Override public void ifgt(int pcOffset) { + add( insnFactory.ifgt(pc + pcOffset)); + pc+=3; + } + + @Override public void ifle(int pcOffset) { + add( insnFactory.ifle(pc + pcOffset)); + pc+=3; + } + + @Override public void ifnonnull(int pcOffset) { + add( insnFactory.ifnonnull(pc + pcOffset)); + pc+=3; + } + + @Override public void ifnull(int pcOffset) { + add( insnFactory.ifnull(pc + pcOffset)); + pc+=3; + } + + @Override public void iinc(int localVarIndex, int incConstant) { + add( insnFactory.iinc(localVarIndex, incConstant)); + pc+=3; + if (isWide){ + pc+=2; + isWide = false; + } + } + + @Override public void iload(int localVarIndex) { + add( insnFactory.iload(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void iload_0() { + add( insnFactory.iload(0)); + pc++; + } + + @Override public void iload_1() { + add( insnFactory.iload(1)); + pc++; + } + + @Override public void iload_2() { + add( insnFactory.iload(2)); + pc++; + } + + @Override public void iload_3() { + add( insnFactory.iload(3)); + pc++; + } + + @Override public void imul() { + add( insnFactory.imul()); + pc++; + } + + @Override public void ineg() { + add( insnFactory.ineg()); + pc++; + } + + @Override public void instanceof_(int cpClassIndex) { + String clsName = cf.classNameAt(cpClassIndex); + add( insnFactory.instanceof_(clsName)); + pc+=3; + } + + @Override public void invokeinterface(int cpInterfaceMethodRefIndex, int count, int zero) { + String clsName = cf.interfaceMethodClassNameAt(cpInterfaceMethodRefIndex); + String methodName = cf.interfaceMethodNameAt(cpInterfaceMethodRefIndex); + String methodSignature = cf.interfaceMethodDescriptorAt(cpInterfaceMethodRefIndex); + + add( insnFactory.invokeinterface(clsName, methodName, methodSignature)); + pc+=5; + } + public void invokeinterface(String clsName, String methodName, String methodSignature){ + add( insnFactory.invokeinterface(clsName, methodName, methodSignature)); + pc+=5; + } + + @Override + public void invokedynamic (int cpInvokeDynamicIndex){ + int bootstrapMethodIndex = cf.bootstrapMethodIndex(cpInvokeDynamicIndex); + String samMethodName = cf.samMethodNameAt(cpInvokeDynamicIndex); + String callSiteDescriptor = cf.callSiteDescriptor(cpInvokeDynamicIndex); + add( insnFactory.invokedynamic(bootstrapMethodIndex, samMethodName, callSiteDescriptor)); + pc+=5; + } + + @Override public void invokespecial(int cpMethodRefIndex) { + String clsName = cf.methodClassNameAt(cpMethodRefIndex); + String methodName = cf.methodNameAt(cpMethodRefIndex); + String methodSignature = cf.methodDescriptorAt(cpMethodRefIndex); + + add( insnFactory.invokespecial(clsName, methodName, methodSignature)); + pc+=3; + } + public void invokespecial(String clsName, String methodName, String methodSignature){ + add( insnFactory.invokespecial(clsName, methodName, methodSignature)); + pc+=3; + } + + @Override public void invokestatic(int cpMethodRefIndex) { + String clsName = cf.methodClassNameAt(cpMethodRefIndex); + String methodName = cf.methodNameAt(cpMethodRefIndex); + String methodSignature = cf.methodDescriptorAt(cpMethodRefIndex); + + add( insnFactory.invokestatic(clsName, methodName, methodSignature)); + pc+=3; + } + public void invokestatic(String clsName, String methodName, String methodSignature){ + add( insnFactory.invokestatic(clsName, methodName, methodSignature)); + pc+=3; + } + + @Override public void invokevirtual(int cpMethodRefIndex) { + String clsName = cf.methodClassNameAt(cpMethodRefIndex); + String methodName = cf.methodNameAt(cpMethodRefIndex); + String methodSignature = cf.methodDescriptorAt(cpMethodRefIndex); + + add( insnFactory.invokevirtual(clsName, methodName, methodSignature)); + pc+=3; + } + public void invokevirtual(String clsName, String methodName, String methodSignature){ + add( insnFactory.invokevirtual(clsName, methodName, methodSignature)); + pc+=3; + } + + @Override public void ior() { + add( insnFactory.ior()); + pc++; + } + + @Override public void irem() { + add( insnFactory.irem()); + pc++; + } + + @Override public void ireturn() { + add( insnFactory.ireturn()); + pc++; + } + + @Override public void ishl() { + add( insnFactory.ishl()); + pc++; + } + + @Override public void ishr() { + add( insnFactory.ishr()); + pc++; + } + + @Override public void istore(int localVarIndex) { + add( insnFactory.istore(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void istore_0() { + add( insnFactory.istore(0)); + pc++; + } + + @Override public void istore_1() { + add( insnFactory.istore(1)); + pc++; + } + + @Override public void istore_2() { + add( insnFactory.istore(2)); + pc++; + } + + @Override public void istore_3() { + add( insnFactory.istore(3)); + pc++; + } + + @Override public void isub() { + add( insnFactory.isub()); + pc++; + } + + @Override public void iushr() { + add( insnFactory.iushr()); + pc++; + } + + @Override public void ixor() { + add( insnFactory.ixor()); + pc++; + } + + @Override public void jsr(int pcOffset) { + add( insnFactory.jsr(pc + pcOffset)); + pc+=3; + } + + @Override public void jsr_w(int pcOffset) { + add( insnFactory.jsr_w(pc + pcOffset)); + pc+=5; + } + + @Override public void l2d() { + add( insnFactory.l2d()); + pc++; + } + + @Override public void l2f() { + add( insnFactory.l2f()); + pc++; + } + + @Override public void l2i() { + add( insnFactory.l2i()); + pc++; + } + + @Override public void ladd() { + add( insnFactory.ladd()); + pc++; + } + + @Override public void laload() { + add( insnFactory.laload()); + pc++; + } + + @Override public void land() { + add( insnFactory.land()); + pc++; + } + + @Override public void lastore() { + add( insnFactory.lastore()); + pc++; + } + + @Override public void lcmp() { + add( insnFactory.lcmp()); + pc++; + } + + @Override public void lconst_0() { + add( insnFactory.lconst_0()); + pc++; + } + + @Override public void lconst_1() { + add( insnFactory.lconst_1()); + pc++; + } + + @Override public void ldc_(int cpIntOrFloatOrStringOrClassIndex) { + Object v = cf.getCpValue(cpIntOrFloatOrStringOrClassIndex); + switch (cf.getCpTag(cpIntOrFloatOrStringOrClassIndex)){ + case ClassFile.CONSTANT_INTEGER: + add( insnFactory.ldc((Integer)v)); break; + case ClassFile.CONSTANT_FLOAT: + add( insnFactory.ldc((Float)v)); break; + case ClassFile.CONSTANT_STRING: + add( insnFactory.ldc((String)v, false)); break; + case ClassFile.CONSTANT_CLASS: + add( insnFactory.ldc((String)v, true)); break; + } + pc+=2; + } + + @Override public void ldc_w_(int cpIntOrFloatOrStringOrClassIndex) { + Object v = cf.getCpValue(cpIntOrFloatOrStringOrClassIndex); + switch (cf.getCpTag(cpIntOrFloatOrStringOrClassIndex)){ + case ClassFile.CONSTANT_INTEGER: + add( insnFactory.ldc_w((Integer) v)); break; + case ClassFile.CONSTANT_FLOAT: + add( insnFactory.ldc_w((Float) v)); break; + case ClassFile.CONSTANT_STRING: + add( insnFactory.ldc_w((String) v, false)); break; + case ClassFile.CONSTANT_CLASS: + add( insnFactory.ldc_w((String) v, true)); break; + } + pc+=3; + } + + @Override public void ldc2_w(int cpLongOrDoubleIndex) { + Object v = cf.getCpValue(cpLongOrDoubleIndex); + if (v instanceof Long){ + add( insnFactory.ldc2_w((Long)v)); + } else { + add( insnFactory.ldc2_w((Double)v)); + } + pc+=3; + } + + @Override public void ldiv() { + add( insnFactory.ldiv()); + pc++; + } + + @Override public void lload(int localVarIndex) { + add( insnFactory.lload(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void lload_0() { + add( insnFactory.lload(0)); + pc++; + } + + @Override public void lload_1() { + add( insnFactory.lload(1)); + pc++; + } + + @Override public void lload_2() { + add( insnFactory.lload(2)); + pc++; + } + + @Override public void lload_3() { + add( insnFactory.lload(3)); + pc++; + } + + @Override public void lmul() { + add( insnFactory.lmul()); + pc++; + } + + @Override public void lneg() { + add( insnFactory.lneg()); + pc++; + } + + + @Override public void lookupswitch(int defaultPcOffset, int nEntries) { + Instruction insn = insnFactory.lookupswitch(pc + defaultPcOffset, nEntries); + add( insn); + + lookupswitchInsn = (LookupSwitchInstruction)insn; + + if (cf != null){ + cf.parseLookupSwitchEntries(this, nEntries); + } + + pc = ((pc+4)>>2)<<2; // opcode and padding + pc += 8 + nEntries*8; // arguments and lookup table + } + @Override public void lookupswitchEntry(int index, int match, int pcOffset) { + lookupswitchInsn.setTarget(index, match, pc + pcOffset); + } + + @Override public void lor() { + add( insnFactory.lor()); + pc++; + } + + @Override public void lrem() { + add( insnFactory.lrem()); + pc++; + } + + @Override public void lreturn() { + add( insnFactory.lreturn()); + pc++; + } + + @Override public void lshl() { + add( insnFactory.lshl()); + pc++; + } + + @Override public void lshr() { + add( insnFactory.lshr()); + pc++; + } + + @Override public void lstore(int localVarIndex) { + add( insnFactory.lstore(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void lstore_0() { + add( insnFactory.lstore(0)); + pc++; + } + + @Override public void lstore_1() { + add( insnFactory.lstore(1)); + pc++; + } + + @Override public void lstore_2() { + add( insnFactory.lstore(2)); + pc++; + } + + @Override public void lstore_3() { + add( insnFactory.lstore(3)); + pc++; + } + + @Override public void lsub() { + add( insnFactory.lsub()); + pc++; + } + + @Override public void lushr() { + add( insnFactory.lushr()); + pc++; + } + + @Override public void lxor() { + add( insnFactory.lxor()); + pc++; + } + + @Override public void monitorenter() { + add( insnFactory.monitorenter()); + pc++; + } + + @Override public void monitorexit() { + add( insnFactory.monitorexit()); + pc++; + } + + @Override public void multianewarray(int cpClassIndex, int dimensions) { + add( insnFactory.multianewarray(cf.classNameAt(cpClassIndex), dimensions)); + pc+=4; + } + + @Override public void new_(int cpClassIndex) { + add( insnFactory.new_(cf.classNameAt(cpClassIndex))); + pc+=3; + } + public void new_(String className) { + add( insnFactory.new_(className)); + pc+=3; + } + + @Override public void newarray(int typeCode) { + add( insnFactory.newarray(typeCode)); + pc+=2; + } + + @Override public void nop() { + add( insnFactory.nop()); + pc++; + } + + @Override public void pop() { + add( insnFactory.pop()); + pc++; + } + + @Override public void pop2() { + add( insnFactory.pop2()); + pc++; + } + + @Override public void putfield(int cpFieldRefIndex) { + String fieldName = cf.fieldNameAt(cpFieldRefIndex); + String clsName = cf.fieldClassNameAt(cpFieldRefIndex); + String fieldDescriptor = cf.fieldDescriptorAt(cpFieldRefIndex); + + add( insnFactory.putfield(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + public void putfield(String fieldName, String clsName, String fieldDescriptor){ + add( insnFactory.putfield(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + + + @Override public void putstatic(int cpFieldRefIndex) { + String fieldName = cf.fieldNameAt(cpFieldRefIndex); + String clsName = cf.fieldClassNameAt(cpFieldRefIndex); + String fieldDescriptor = cf.fieldDescriptorAt(cpFieldRefIndex); + + add( insnFactory.putstatic(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + public void putstatic(String fieldName, String clsName, String fieldDescriptor){ + add( insnFactory.putstatic(fieldName, clsName, fieldDescriptor)); + pc+=3; + } + + + @Override public void ret(int localVarIndex) { + add( insnFactory.ret(localVarIndex)); + pc+=2; + if (isWide){ + pc++; + isWide = false; + } + } + + @Override public void return_() { + add( insnFactory.return_()); + pc++; + } + + @Override public void saload() { + add( insnFactory.saload()); + pc++; + } + + @Override public void sastore() { + add( insnFactory.sastore()); + pc++; + } + + @Override public void sipush(int val) { + add( insnFactory.sipush(val)); + pc+=3; + } + + @Override public void swap() { + add( insnFactory.swap()); + pc++; + } + + @Override public void tableswitch(int defaultPcOffset, int low, int high) { + Instruction insn = insnFactory.tableswitch(pc + defaultPcOffset, low, high); + add( insn); + + tableswitchInsn = (TableSwitchInstruction)insn; + + if (cf != null){ + cf.parseTableSwitchEntries(this, low, high); + } + + pc = ((pc+4)>>2)<<2; // opcode and padding + pc+=12 + (high-low+1)*4; // the fixed args and jump table + } + + @Override public void tableswitchEntry(int value, int pcOffset) { + tableswitchInsn.setTarget(value, pc + pcOffset); + } + + @Override public void wide() { + add( insnFactory.wide()); + pc++; + isWide = true; + } + + @Override public void unknown(int bytecode) { + throw new JPFException("unknown bytecode: " + Integer.toHexString(bytecode)); + } + + + //--- the JPF specific ones (only used in synthetic methods) + public void invokecg(List invokes) { + add (insnFactory.invokecg(invokes)); + pc++; + } + + public void invokeclinit(ClassInfo ci) { + add( insnFactory.invokeclinit(ci)); + pc++; + } + + public void finishclinit (ClassInfo ci){ + add (insnFactory.finishclinit(ci)); + pc++; + } + + public void directcallreturn(){ + add( insnFactory.directcallreturn()); + pc++; + } + + public void executenative(NativeMethodInfo mi){ + add( insnFactory.executenative(mi)); + pc++; + } + + public void nativereturn(){ + add( insnFactory.nativereturn()); + pc++; + } + + public void runStart (MethodInfo mi){ + add( insnFactory.runstart(mi)); + pc++; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMDirectCallStackFrame.java b/src/main/gov/nasa/jpf/jvm/JVMDirectCallStackFrame.java new file mode 100644 index 0000000..6a27dba --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMDirectCallStackFrame.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.vm.DirectCallStackFrame; +import gov.nasa.jpf.vm.MethodInfo; + +/** + * a direct call stackframe that supports JVM calling conventions + */ +public class JVMDirectCallStackFrame extends DirectCallStackFrame { + + JVMDirectCallStackFrame (MethodInfo miDirectCall, MethodInfo callee){ + super( miDirectCall, callee); + } + + //--- return value handling + + @Override + public int getResult(){ + return pop(); + } + + @Override + public int getReferenceResult(){ + return pop(); + } + + @Override + public long getLongResult(){ + return popLong(); + } + + @Override + public Object getResultAttr(){ + return getOperandAttr(); + } + + @Override + public Object getLongResultAttr(){ + return getLongOperandAttr(); + } + + @Override + public void setExceptionReference (int exRef){ + clearOperandStack(); + pushRef( exRef); + } + + @Override + public int getExceptionReference(){ + return pop(); + } + + @Override + public void setExceptionReferenceAttribute (Object attr){ + setOperandAttr(attr); + } + + @Override + public Object getExceptionReferenceAttribute (){ + return getOperandAttr(); + } + + //--- direct call argument initialization + // NOTE - we don't support out-of-order arguments yet, i.e. the slotIdx is ignored + + + @Override + public int setArgument (int slotIdx, int v, Object attr){ + push(v); + if (attr != null){ + setOperandAttr(attr); + } + + return slotIdx+1; + } + + @Override + public int setReferenceArgument (int slotIdx, int ref, Object attr){ + pushRef(ref); + if (attr != null){ + setOperandAttr(attr); + } + + return slotIdx+1; + } + + @Override + public int setLongArgument (int slotIdx, long v, Object attr){ + pushLong(v); + if (attr != null){ + setLongOperandAttr(attr); + } + + return slotIdx+2; + } + + //--- DirectCallStackFrame methods don't have arguments + + @Override + public void setArgumentLocal (int argIdx, int v, Object attr){ + throw new UnsupportedOperationException("direct call methods don't have arguments"); + } + @Override + public void setReferenceArgumentLocal (int argIdx, int v, Object attr){ + throw new UnsupportedOperationException("direct call methods don't have arguments"); + } + @Override + public void setLongArgumentLocal (int argIdx, long v, Object attr){ + throw new UnsupportedOperationException("direct call methods don't have arguments"); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMInstructionFactory.java b/src/main/gov/nasa/jpf/jvm/JVMInstructionFactory.java new file mode 100644 index 0000000..7711b9c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMInstructionFactory.java @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.util.Invocation; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.NativeMethodInfo; + +import java.util.List; + +/** + * interface for bytecode creation + * + * this deliberately uses the abstract abstract public Instruction as return type to allow different instruction hierarchies in + * extensions. + * + * This shouldn't impose runtime overhead since mandatory parameters are now passed in as factory method arguments. The only + * drawback is that the compiler cannot check for abstract public Instruction class typos, but that seems less important than + * allowing extension specific abstract public Instruction class hierarchies + * + * <2do> there are still direct references of LOOKUPSWITCH, TABLESWITCH. Once these are removed, .jvm does not assume a particular + * abstract public Instruction hierarchy + */ +public abstract class JVMInstructionFactory implements Cloneable { + + protected static JVMInstructionFactory singleton; + + public static JVMInstructionFactory getFactory(){ + return singleton; + } + + protected JVMInstructionFactory(){ + // we should check the singleton first + singleton = this; + } + + + //--- the factory methods + abstract public Instruction aconst_null (); + + abstract public Instruction aload (int localVarIndex); + + abstract public Instruction aload_0 (); + + abstract public Instruction aload_1 (); + + abstract public Instruction aload_2 (); + + abstract public Instruction aload_3 (); + + abstract public Instruction aaload (); + + abstract public Instruction astore (int localVarIndex); + + abstract public Instruction astore_0 (); + + abstract public Instruction astore_1 (); + + abstract public Instruction astore_2 (); + + abstract public Instruction astore_3 (); + + abstract public Instruction aastore (); + + abstract public Instruction areturn (); + + abstract public Instruction anewarray (String clsName); + + abstract public Instruction arraylength (); + + abstract public Instruction athrow (); + + abstract public Instruction baload (); + + abstract public Instruction bastore (); + + abstract public Instruction bipush (int b); + + abstract public Instruction caload (); + + abstract public Instruction castore (); + + abstract public Instruction checkcast (String clsName); + + abstract public Instruction d2f (); + + abstract public Instruction d2i (); + + abstract public Instruction d2l (); + + abstract public Instruction dadd (); + + abstract public Instruction daload (); + + abstract public Instruction dastore (); + + abstract public Instruction dcmpg (); + + abstract public Instruction dcmpl (); + + abstract public Instruction dconst_0 (); + + abstract public Instruction dconst_1 (); + + abstract public Instruction ddiv (); + + abstract public Instruction dload (int localVarIndex); + + abstract public Instruction dload_0 (); + + abstract public Instruction dload_1 (); + + abstract public Instruction dload_2 (); + + abstract public Instruction dload_3 (); + + abstract public Instruction dmul (); + + abstract public Instruction dneg (); + + abstract public Instruction drem (); + + abstract public Instruction dreturn (); + + abstract public Instruction dstore (int localVarIndex); + + abstract public Instruction dstore_0 (); + + abstract public Instruction dstore_1 (); + + abstract public Instruction dstore_2 (); + + abstract public Instruction dstore_3 (); + + abstract public Instruction dsub (); + + abstract public Instruction dup (); + + abstract public Instruction dup_x1 (); + + abstract public Instruction dup_x2 (); + + abstract public Instruction dup2 (); + + abstract public Instruction dup2_x1 (); + + abstract public Instruction dup2_x2 (); + + abstract public Instruction f2d (); + + abstract public Instruction f2i (); + + abstract public Instruction f2l (); + + abstract public Instruction fadd (); + + abstract public Instruction faload (); + + abstract public Instruction fastore (); + + abstract public Instruction fcmpg (); + + abstract public Instruction fcmpl (); + + abstract public Instruction fconst_0 (); + + abstract public Instruction fconst_1 (); + + abstract public Instruction fconst_2 (); + + abstract public Instruction fdiv (); + + abstract public Instruction fload (int localVarIndex); + + abstract public Instruction fload_0 (); + + abstract public Instruction fload_1 (); + + abstract public Instruction fload_2 (); + + abstract public Instruction fload_3 (); + + abstract public Instruction fmul (); + + abstract public Instruction fneg (); + + abstract public Instruction frem (); + + abstract public Instruction freturn (); + + abstract public Instruction fstore (int localVarIndex); + + abstract public Instruction fstore_0 (); + + abstract public Instruction fstore_1 (); + + abstract public Instruction fstore_2 (); + + abstract public Instruction fstore_3 (); + + abstract public Instruction fsub (); + + abstract public Instruction getfield (String fieldName, String clsName, String fieldDescriptor); + + abstract public Instruction getstatic (String fieldName, String clsName, String fieldDescriptor); + + abstract public Instruction goto_ (int targetPc); + + abstract public Instruction goto_w (int targetPc); + + abstract public Instruction i2b (); + + abstract public Instruction i2c (); + + abstract public Instruction i2d (); + + abstract public Instruction i2f (); + + abstract public Instruction i2l (); + + abstract public Instruction i2s (); + + abstract public Instruction iadd (); + + abstract public Instruction iaload (); + + abstract public Instruction iand (); + + abstract public Instruction iastore (); + + abstract public Instruction iconst_m1 (); + + abstract public Instruction iconst_0 (); + + abstract public Instruction iconst_1 (); + + abstract public Instruction iconst_2 (); + + abstract public Instruction iconst_3 (); + + abstract public Instruction iconst_4 (); + + abstract public Instruction iconst_5 (); + + abstract public Instruction idiv (); + + abstract public Instruction if_acmpeq (int targetPc); + + abstract public Instruction if_acmpne (int targetPc); + + abstract public Instruction if_icmpeq (int targetPc); + + abstract public Instruction if_icmpne (int targetPc); + + abstract public Instruction if_icmplt (int targetPc); + + abstract public Instruction if_icmpge (int targetPc); + + abstract public Instruction if_icmpgt (int targetPc); + + abstract public Instruction if_icmple (int targetPc); + + abstract public Instruction ifeq (int targetPc); + + abstract public Instruction ifne (int targetPc); + + abstract public Instruction iflt (int targetPc); + + abstract public Instruction ifge (int targetPc); + + abstract public Instruction ifgt (int targetPc); + + abstract public Instruction ifle (int targetPc); + + abstract public Instruction ifnonnull (int targetPc); + + abstract public Instruction ifnull (int targetPc); + + abstract public Instruction iinc (int localVarIndex, int incConstant); + + abstract public Instruction iload (int localVarIndex); + + abstract public Instruction iload_0 (); + + abstract public Instruction iload_1 (); + + abstract public Instruction iload_2 (); + + abstract public Instruction iload_3 (); + + abstract public Instruction imul (); + + abstract public Instruction ineg (); + + abstract public Instruction instanceof_ (String clsName); + + abstract public Instruction invokeinterface (String clsName, String methodName, String methodSignature); + + abstract public Instruction invokespecial (String clsName, String methodName, String methodSignature); + + abstract public Instruction invokestatic (String clsName, String methodName, String methodSignature); + + abstract public Instruction invokevirtual (String clsName, String methodName, String methodSignature); + + abstract public Instruction invokedynamic (int bootstrapIndex, String samMethodName, String functionType); + + abstract public Instruction ior (); + + abstract public Instruction irem (); + + abstract public Instruction ireturn (); + + abstract public Instruction ishl (); + + abstract public Instruction ishr (); + + abstract public Instruction istore (int localVarIndex); + + abstract public Instruction istore_0 (); + + abstract public Instruction istore_1 (); + + abstract public Instruction istore_2 (); + + abstract public Instruction istore_3 (); + + abstract public Instruction isub (); + + abstract public Instruction iushr (); + + abstract public Instruction ixor (); + + abstract public Instruction jsr (int targetPc); + + abstract public Instruction jsr_w (int targetPc); + + abstract public Instruction l2d (); + + abstract public Instruction l2f (); + + abstract public Instruction l2i (); + + abstract public Instruction ladd (); + + abstract public Instruction laload (); + + abstract public Instruction land (); + + abstract public Instruction lastore (); + + abstract public Instruction lcmp (); + + abstract public Instruction lconst_0 (); + + abstract public Instruction lconst_1 (); + + abstract public Instruction ldc (int v); + + abstract public Instruction ldc (float v); + + abstract public Instruction ldc (String v, boolean isClass); + + abstract public Instruction ldc_w (int v); + + abstract public Instruction ldc_w (float v); + + abstract public Instruction ldc_w (String v, boolean isClass); + + abstract public Instruction ldc2_w (long v); + + abstract public Instruction ldc2_w (double v); + + abstract public Instruction ldiv (); + + abstract public Instruction lload (int localVarIndex); + + abstract public Instruction lload_0 (); + + abstract public Instruction lload_1 (); + + abstract public Instruction lload_2 (); + + abstract public Instruction lload_3 (); + + abstract public Instruction lmul (); + + abstract public Instruction lneg (); + + abstract public Instruction lookupswitch (int defaultTargetPc, int nEntries); + + abstract public Instruction lor (); + + abstract public Instruction lrem (); + + abstract public Instruction lreturn (); + + abstract public Instruction lshl (); + + abstract public Instruction lshr (); + + abstract public Instruction lstore (int localVarIndex); + + abstract public Instruction lstore_0 (); + + abstract public Instruction lstore_1 (); + + abstract public Instruction lstore_2 (); + + abstract public Instruction lstore_3 (); + + abstract public Instruction lsub (); + + abstract public Instruction lushr (); + + abstract public Instruction lxor (); + + abstract public Instruction monitorenter (); + + abstract public Instruction monitorexit (); + + abstract public Instruction multianewarray (String clsName, int dimensions); + + abstract public Instruction new_ (String clsName); + + abstract public Instruction newarray (int typeCode); + + abstract public Instruction nop (); + + abstract public Instruction pop (); + + abstract public Instruction pop2 (); + + abstract public Instruction putfield (String fieldName, String clsName, String fieldDescriptor); + + abstract public Instruction putstatic (String fieldName, String clsName, String fieldDescriptor); + + abstract public Instruction ret (int localVarIndex); + + abstract public Instruction return_ (); + + abstract public Instruction saload (); + + abstract public Instruction sastore (); + + abstract public Instruction sipush (int val); + + abstract public Instruction swap (); + + abstract public Instruction tableswitch (int defaultTargetPc, int low, int high); + + abstract public Instruction wide (); + + //--- the JPF specific ones (only used in synthetic methods) + abstract public Instruction invokecg (List invokes); + + abstract public Instruction invokeclinit (ClassInfo ci); + + abstract public Instruction directcallreturn (); + + abstract public Instruction executenative (NativeMethodInfo mi); + + abstract public Instruction nativereturn (); + + // this is never part of MethodInfo stored code + abstract public Instruction runstart (MethodInfo miRun); + + abstract public Instruction finishclinit (ClassInfo ci); +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMNativeStackFrame.java b/src/main/gov/nasa/jpf/jvm/JVMNativeStackFrame.java new file mode 100644 index 0000000..7daed55 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMNativeStackFrame.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.vm.NativeMethodInfo; +import gov.nasa.jpf.vm.NativeStackFrame; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + +/** + * a NativeStackFrame used for calling NativeMethods from Java bytecode + */ +public class JVMNativeStackFrame extends NativeStackFrame { + + public JVMNativeStackFrame (NativeMethodInfo callee){ + super(callee); + } + + public void setArguments (ThreadInfo ti){ + StackFrame callerFrame = ti.getTopFrame(); // we are not going to modify it + NativeMethodInfo nmi = (NativeMethodInfo) mi; + int nArgs = nmi.getNumberOfArguments(); + byte[] argTypes = nmi.getArgumentTypes(); + + Object[] a = new Object[nArgs+2]; + + int stackOffset; + int i, j, k; + int ival; + long lval; + + for (i = 0, stackOffset = 0, j = nArgs + 1, k = nArgs - 1; + i < nArgs; + i++, j--, k--) { + switch (argTypes[k]) { + case Types.T_BOOLEAN: + ival = callerFrame.peek(stackOffset); + a[j] = Boolean.valueOf(Types.intToBoolean(ival)); + + break; + + case Types.T_BYTE: + ival = callerFrame.peek(stackOffset); + a[j] = Byte.valueOf((byte) ival); + + break; + + case Types.T_CHAR: + ival = callerFrame.peek(stackOffset); + a[j] = Character.valueOf((char) ival); + + break; + + case Types.T_SHORT: + ival = callerFrame.peek(stackOffset); + a[j] = new Short((short) ival); + + break; + + case Types.T_INT: + ival = callerFrame.peek(stackOffset); + a[j] = new Integer(ival); + + break; + + case Types.T_LONG: + lval = callerFrame.peekLong(stackOffset); + stackOffset++; // 2 stack words + a[j] = new Long(lval); + + break; + + case Types.T_FLOAT: + ival = callerFrame.peek(stackOffset); + a[j] = new Float(Types.intToFloat(ival)); + + break; + + case Types.T_DOUBLE: + lval = callerFrame.peekLong(stackOffset); + stackOffset++; // 2 stack words + a[j] = new Double(Types.longToDouble(lval)); + + break; + + default: + // NOTE - we have to store T_REFERENCE as an Integer, because + // it shows up in our native method as an 'int' + ival = callerFrame.peek(stackOffset); + a[j] = new Integer(ival); + } + + stackOffset++; + } + + //--- set our standard MJI header arguments + a[0] = ti.getMJIEnv(); + + if (nmi.isStatic()) { + a[1] = new Integer( nmi.getClassInfo().getClassObjectRef()); + } else { + int thisRef = callerFrame.getCalleeThis(nmi); + a[1] = new Integer( thisRef); + + setThis(thisRef); + } + + setArgs(a); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/JVMStackFrame.java b/src/main/gov/nasa/jpf/jvm/JVMStackFrame.java new file mode 100644 index 0000000..d03eda8 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMStackFrame.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.util.FixedBitSet; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * a stackframe that is used for executing Java bytecode, supporting both + * locals and an operand stack. This is essentially the JVm stack machine + * implementation + */ +public class JVMStackFrame extends StackFrame { + + public JVMStackFrame (MethodInfo callee){ + super( callee); + } + + /** + * creates callerSlots dummy Stackframe for testing of operand/local operations + * NOTE - TESTING ONLY! this does not have callerSlots MethodInfo + */ + protected JVMStackFrame (int nLocals, int nOperands){ + super( nLocals, nOperands); + } + + /** + * this sets up arguments from a bytecode caller + */ + protected void setCallArguments (ThreadInfo ti){ + StackFrame caller = ti.getTopFrame(); + MethodInfo miCallee = mi; + int nArgSlots = miCallee.getArgumentsSize(); + + if (nArgSlots > 0){ + int[] calleeSlots = slots; + FixedBitSet calleeRefs = isRef; + int[] callerSlots = caller.getSlots(); + FixedBitSet callerRefs = caller.getReferenceMap(); + + for (int i = 0, j = caller.getTopPos() - nArgSlots + 1; i < nArgSlots; i++, j++) { + calleeSlots[i] = callerSlots[j]; + if (callerRefs.get(j)) { + calleeRefs.set(i); + } + Object a = caller.getSlotAttr(j); + if (a != null) { + setSlotAttr(i, a); + } + } + + if (!miCallee.isStatic()) { + thisRef = calleeSlots[0]; + } + } + } + + @Override + public void setExceptionReference (int exRef){ + clearOperandStack(); + pushRef( exRef); + } + + //--- these are for setting up arguments from a VM / listener caller + + /* + * to be used to initialize locals of a stackframe (only required for explicit construction without a caller, + * otherwise the Stackframe ctor/invoke insn will take care of copying the values from its caller) + */ + @Override + public void setArgumentLocal (int idx, int v, Object attr){ + setLocalVariable( idx, v); + if (attr != null){ + setLocalAttr( idx, attr); + } + } + @Override + public void setReferenceArgumentLocal (int idx, int ref, Object attr){ + setLocalReferenceVariable( idx, ref); + if (attr != null){ + setLocalAttr( idx, attr); + } + } + @Override + public void setLongArgumentLocal (int idx, long v, Object attr){ + setLongLocalVariable( idx, v); + if (attr != null){ + setLocalAttr( idx, attr); + } + } + +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/jvm/JVMSystemClassLoaderInfo.java b/src/main/gov/nasa/jpf/jvm/JVMSystemClassLoaderInfo.java new file mode 100644 index 0000000..29c40c1 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JVMSystemClassLoaderInfo.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.vm.ClassFileContainer; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ClassParseException; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.SystemClassLoaderInfo; +import gov.nasa.jpf.vm.VM; +import java.io.File; +import java.io.IOException; + +/** + * a SystemClassLoaderInfo that reads standard Java classfiles from *.class and *.jar files, and creates code using a concrete + * value JVM instruction set + */ +public class JVMSystemClassLoaderInfo extends SystemClassLoaderInfo { + + static JPFLogger log = JPF.getLogger("class"); + protected JVMCodeBuilder defaultCodeBuilder; + + public JVMSystemClassLoaderInfo (VM vm, int appId) { + super(vm, appId); + + defaultCodeBuilder = createDefaultCodeBuilder(config, appId); + + JVMClassInfo.init(config); + + // now we can notify + vm.registerClassLoader(this); + } + + /** + * override this if you need a different default CodeBuilder + */ + protected JVMCodeBuilder createDefaultCodeBuilder (Config config, int appId) { + String key = config.getIndexableKey("jvm.insn_factory.class", appId); + JVMInstructionFactory insnFactory = config.getEssentialInstance(key, JVMInstructionFactory.class); + return new JVMCodeBuilder(insnFactory); + } + + @Override + protected ClassFileContainer createClassFileContainer (String spec) { + int i = spec.indexOf(".jar"); + if (i > 0) { + // its a jar + int j = i + 4; + int len = spec.length(); + String jarPath; + String pathPrefix = null; + File jarFile; + if (j == len) { + // no path prefix, plain jar + jarPath = spec; + } else { + if (spec.charAt(j) == '/') { + pathPrefix = spec.substring(j); + jarPath = spec.substring(0, j); + } else { + return null; + } + } + jarFile = new File(jarPath); + if (jarFile.isFile()) { + try { + return new JarClassFileContainer(jarFile, pathPrefix); + } catch (IOException ix) { + return null; + } + } else { + return null; + } + + } else { + // a dir + File dir = new File(spec); + if (dir.isDirectory()) { + return new DirClassFileContainer(dir); + } else { + return null; + } + } + } + + protected void addSystemBootClassPath () { + String v = System.getProperty("sun.boot.class.path"); + if (v != null) { + for (String pn : v.split(File.pathSeparator)) { + if (pn != null && !pn.isEmpty()) { + ClassFileContainer cfc = createClassFileContainer(pn); + if (cfc != null) { + cp.addClassFileContainer(cfc); + } + } + } + } else { + // Hmm, maybe we are not executing on OpenJDK + } + } + + /** + * this is the main method to create the ClassPath, which is called from the ctor + */ + @Override + protected void initializeSystemClassPath (VM vm, int appId) { + Config conf = vm.getConfig(); + File[] pathElements; + + // explicit "classpath[.id]" settings have precedence + pathElements = getPathElements(conf, "classpath", appId); + if (pathElements != null) { + for (File f : pathElements) { + addClassPathElement(f.getAbsolutePath()); + } + } + + // we optionally append boot_classpath + pathElements = getPathElements(conf, "vm.boot_classpath", appId); + if (pathElements != null) { + for (File f : pathElements) { + if (f.getName().equals("")) { + addSystemBootClassPath(); + } else { + addClassPathElement( f.getAbsolutePath()); + } + } + } + + log.info("collected system classpath: ", cp); + } + + /** + * override this if you have different CodeBuilders for different types + * NOTE - this CodeBuilder is not completely initialized yet, clients still have to call startMethod(mi) on it + */ + protected JVMCodeBuilder getCodeBuilder (String clsName) { + return defaultCodeBuilder; + } + + /** + * used for automatically created code such as AnnotationProxies, direct calls, native calls and run starts + * NOTE - this cannot be called recursively or concurrently + */ + protected JVMCodeBuilder getSystemCodeBuilder (ClassFile cf, MethodInfo mi) { + defaultCodeBuilder.reset(cf, mi); + return defaultCodeBuilder; + } + + @Override + protected ClassInfo createClassInfo (String clsName, String url, byte[] data, ClassLoaderInfo definingLoader) throws ClassParseException { + ClassFile cf = new ClassFile(data); + JVMCodeBuilder cb = getCodeBuilder(clsName); + ClassInfo ci = new JVMClassInfo(clsName, definingLoader, cf, url, cb); + setAttributes(ci); + + return ci; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/JarClassFileContainer.java b/src/main/gov/nasa/jpf/jvm/JarClassFileContainer.java new file mode 100644 index 0000000..bace55a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/JarClassFileContainer.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.util.FileUtils; +import gov.nasa.jpf.vm.ClassFileMatch; +import gov.nasa.jpf.vm.ClassParseException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * a ClassFileContainer that loads classes from jar files + */ +public class JarClassFileContainer extends JVMClassFileContainer { + protected JarFile jar; + protected String pathPrefix; // optional + + static String getContainerUrl (File file){ + try { + return "jar:" + file.toURI().toURL().toString() + "!/"; + } catch (MalformedURLException x) { + return "jar:" + file.getAbsolutePath() + "!/"; + } + } + + public JarClassFileContainer (File file) throws IOException { + super(file.getPath(), getContainerUrl(file)); + jar = new JarFile(file); + } + + public JarClassFileContainer (File file, String pathPrefix) throws IOException { + super(getPath(file, pathPrefix), getContainerUrl(file)); + + jar = new JarFile(file); + this.pathPrefix = getNormalizedPathPrefix(pathPrefix); + } + + /** + * make sure the return value ends with '/', and does NOT start with '/'. If + * the supplied pathPrefix only contains '/' or an empty string, return null + */ + static String getNormalizedPathPrefix(String pathPrefix){ + if (pathPrefix != null){ + int len = pathPrefix.length(); + if (len > 0){ + if (pathPrefix.charAt(0) == '/'){ + if (len == 1){ + return null; // no need for storing a single '/' prefix + } else { + pathPrefix = pathPrefix.substring(1); // skip the heading '/' + len--; + } + } + + if (pathPrefix.charAt(len-1) != '/'){ + pathPrefix += '/'; + } + + return pathPrefix; + + } else { + return null; // empty prefix + } + } else { + return null; // null prefix + } + } + + /** + * return our string representation of the complete spec, which is + * + * /pathPrefix + */ + static String getPath(File file, String pathPrefix){ + String pn = file.getPath(); + + if (pathPrefix != null){ + int len = pathPrefix.length(); + if (len > 0){ + if (pathPrefix.charAt(0) == '/'){ + if (len == 1){ + return pn; // no need to store a single '/' + } + } else { + pn += '/'; + } + + pn += pathPrefix; + } + } + + return pn; + } + + @Override + public ClassFileMatch getMatch(String clsName) throws ClassParseException { + String pn = clsName.replace('.', '/') + ".class"; + + if (pathPrefix != null){ + pn = pathPrefix + pn; + } + + JarEntry e = jar.getJarEntry(pn); + + if (e != null) { + InputStream is = null; + try { + long len = e.getSize(); + if (len > Integer.MAX_VALUE) { + error("classfile too big: " + e.getName()); + } + + is = jar.getInputStream(e); + + byte[] data = new byte[(int) len]; + FileUtils.getContents(is, data); + + return new JVMClassFileMatch(clsName, getClassURL(clsName), data); + + } catch (IOException iox) { + error("error reading jar entry " + e.getName()); + + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException iox) { + error("cannot close input stream for file " + e.getName()); + } + } + } + } + + return null; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/AALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/AALOAD.java new file mode 100644 index 0000000..c5ac463 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/AALOAD.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Load reference from array + * ..., arrayref, index => ..., value + */ +public class AALOAD extends ArrayLoadInstruction { + + @Override + public boolean isReferenceArray() { + return true; + } + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + int value = ei.getReferenceElement(index); + frame.pushRef( value); + } + + + @Override + protected boolean isReference () { + return true; + } + + @Override + public int getByteCode () { + return 0x32; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/AASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/AASTORE.java new file mode 100644 index 0000000..da2ac8c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/AASTORE.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.util.InstructionState; +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Store into reference array + * ..., arrayref, index, value => ... + */ +public class AASTORE extends ArrayStoreInstruction { + + int value; + + @Override + public boolean isReferenceArray() { + return true; + } + + @Override + protected void popValue(StackFrame frame){ + value = frame.pop(); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setReferenceElement(index, value); + } + + /** + * overridden because AASTORE can cause ArrayStoreExceptions and exposure CGs + */ + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + int refValue = frame.peek(); + int idx = frame.peek(1); + int aref = frame.peek(2); + + value = aref; + index = idx; + + if (aref == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException"); + } + + ElementInfo eiArray = ti.getModifiableElementInfo(aref); + + if (!ti.isFirstStepInsn()){ // we only need to check this once + Instruction xInsn = checkArrayStoreException(ti, frame, eiArray); + if (xInsn != null){ + return xInsn; + } + } + + boolean checkExposure = false; + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedArrayCG(ti, this, eiArray, idx)){ + checkExposure = true; + eiArray = scheduler.updateArraySharedness(ti, eiArray, index); + if (scheduler.setsSharedArrayCG(ti, this, eiArray, idx)){ + return this; + } + } + + // check if this gets re-executed from an exposure CG + if (frame.getAndResetFrameAttr(InstructionState.class) == null){ + try { + Object attr = frame.getOperandAttr(); + eiArray.checkArrayBounds(idx); + eiArray.setReferenceElement(idx, refValue); + eiArray.setElementAttrNoClone(idx, attr); + + } catch (ArrayIndexOutOfBoundsExecutiveException ex) { // at this point, the AIOBX is already processed + return ex.getInstruction(); + } + + if (checkExposure) { + if (refValue != MJIEnv.NULL) { + ElementInfo eiExposed = ti.getElementInfo(refValue); + if (scheduler.setsSharedObjectExposureCG(ti, this, eiArray, null, eiArray)) { + frame.addFrameAttr( InstructionState.processed); + return this; + } + } + } + } + + frame.pop(3); + + return getNext(ti); + } + + protected Instruction checkArrayStoreException(ThreadInfo ti, StackFrame frame, ElementInfo ei){ + ClassInfo c = ei.getClassInfo(); + int refVal = frame.peek(); + + if (refVal != MJIEnv.NULL) { // no checks for storing 'null' + ClassInfo elementCi = ti.getClassInfo(refVal); + ClassInfo arrayElementCi = c.getComponentClassInfo(); + if (!elementCi.isInstanceOf(arrayElementCi)) { + String exception = "java.lang.ArrayStoreException"; + String exceptionDescription = elementCi.getName(); + return ti.createAndThrowException(exception, exceptionDescription); + } + } + + return null; + } + + + @Override + public int getByteCode () { + return 0x53; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ACONST_NULL.java b/src/main/gov/nasa/jpf/jvm/bytecode/ACONST_NULL.java new file mode 100644 index 0000000..7a86cea --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ACONST_NULL.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push null + * ... => ..., null + */ +public class ACONST_NULL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushRef(MJIEnv.NULL); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x01; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/ALOAD.java new file mode 100644 index 0000000..df997f1 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ALOAD.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Load reference from local variable + * ... => ..., objectref + */ +public class ALOAD extends JVMLocalVariableInstruction { + + public ALOAD(int index){ + super(index); + } + + /** + * for explicit construction + */ + public void setIndex (int index){ + this.index = index; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLocal(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; // immediate; opcode + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x2a; + case 1: return 0x2b; + case 2: return 0x2c; + case 3: return 0x2d; + } + + return 0x19; // ? wide versions + } + + @Override + public String getBaseMnemonic() { + return "aload"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ANEWARRAY.java b/src/main/gov/nasa/jpf/jvm/bytecode/ANEWARRAY.java new file mode 100644 index 0000000..8f13285 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ANEWARRAY.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Heap; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Create new array of reference + * ..., count => ..., arrayref + */ +public class ANEWARRAY extends NewArrayInstruction { + + public ANEWARRAY (String typeDescriptor){ + type = Types.getTypeSignature(typeDescriptor, true); + } + + @Override + public Instruction execute (ThreadInfo ti) { + // resolve the component class first + String compType = Types.getTypeName(type); + if(Types.isReferenceSignature(type)) { + try { + ti.resolveReferencedClass(compType); + } catch(LoadOnJPFRequired lre) { + return ti.getPC(); + } + } + + // there is no clinit for array classes, but we still have to create a class object + // since its a builtin class, we also don't have to bother with NoClassDefFoundErrors + String clsName = "[" + type; + ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); + + if (!ci.isRegistered()) { + ci.registerClass(ti); + ci.setInitialized(); + } + + StackFrame frame = ti.getModifiableTopFrame(); + + arrayLength = frame.pop(); + if (arrayLength < 0){ + return ti.createAndThrowException("java.lang.NegativeArraySizeException"); + } + + Heap heap = ti.getHeap(); + if (heap.isOutOfMemory()) { // simulate OutOfMemoryError + return ti.createAndThrowException("java.lang.OutOfMemoryError", + "trying to allocate new " + + Types.getTypeName(type) + + "[" + arrayLength + "]"); + } + + ElementInfo eiArray = heap.newArray(type, arrayLength, ti); + int aRef = eiArray.getObjectRef(); + + // pushes the object reference on the top stack frame + frame.push(aRef, true); + + return getNext(ti); + } + + @Override + public int getLength () { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xBD; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ARETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/ARETURN.java new file mode 100644 index 0000000..b703a93 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ARETURN.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.ReturnValueInstruction; + + +/** + * Return reference from method + * ..., objectref => [empty] + */ +public class ARETURN extends JVMReturnInstruction implements ReturnValueInstruction { + int ret; + + @Override + public int getReturnTypeSize() { + return 1; + } + + @Override + public int getValueSlot (StackFrame frame){ + return frame.getTopPos(); + } + + @Override + protected Object getReturnedOperandAttr (StackFrame frame) { + return frame.getOperandAttr(); + } + + @Override + protected void getAndSaveReturnValue (StackFrame frame) { + ret = frame.pop(); + } + + @Override + protected void pushReturnValue (StackFrame frame) { + frame.pushRef(ret); + } + + public int getReturnValue () { + return ret; + } + + @Override + public Object getReturnValue(ThreadInfo ti) { + if (!isCompleted(ti)) { // we have to pull it from the operand stack + StackFrame frame = ti.getTopFrame(); + ret = frame.peek(); + } + + if (ret == MJIEnv.NULL) { + return null; + } else { + return ti.getElementInfo(ret); + } + } + + @Override + public int getByteCode () { + return 0xB0; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ARRAYLENGTH.java b/src/main/gov/nasa/jpf/jvm/bytecode/ARRAYLENGTH.java new file mode 100644 index 0000000..4e02761 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ARRAYLENGTH.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Get length of array + * ..., arrayref => ..., length + */ +public class ARRAYLENGTH extends Instruction implements JVMInstruction { + + protected int arrayRef; + + /** + * only makes sense from an executeInstruction() or instructionExecuted() listener, + * it is undefined outside of insn exec notifications + */ + public int getArrayRef (ThreadInfo ti){ + if (ti.isPreExec()){ + return peekArrayRef(ti); + } else { + return arrayRef; + } + } + + public ElementInfo peekArrayElementInfo (ThreadInfo ti){ + int aref = getArrayRef(ti); + return ti.getElementInfo(aref); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + arrayRef = frame.pop(); + + if (arrayRef == MJIEnv.NULL){ + return ti.createAndThrowException("java.lang.NullPointerException", + "array length of null object"); + } + + ElementInfo ei = ti.getElementInfo(arrayRef); + frame.push(ei.arrayLength(), false); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0xBE; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + protected int peekArrayRef (ThreadInfo ti) { + return ti.getTopFrame().peek(); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/ASTORE.java new file mode 100644 index 0000000..14b4f21 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ASTORE.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Store reference into local variable + * ..., objref => ... + */ +public class ASTORE extends JVMLocalVariableInstruction implements StoreInstruction { + + public ASTORE(int index){ + super(index); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.storeOperand(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; // immediate; opcode + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x4b; + case 1: return 0x4c; + case 2: return 0x4d; + case 3: return 0x4e; + } + + return 0x3A; // ? wide versions ? + } + + @Override + public String getBaseMnemonic() { + return "astore"; + } + + + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ATHROW.java b/src/main/gov/nasa/jpf/jvm/bytecode/ATHROW.java new file mode 100644 index 0000000..7e8ff58 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ATHROW.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Throw exception or error + * ..., objectref => objectref + */ +public class ATHROW extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int objref = frame.pop(); + + if (objref == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException"); + } + + return ti.throwException(objref); + } + + @Override + public int getByteCode () { + return 0xBF; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ArrayLoadInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/ArrayLoadInstruction.java new file mode 100644 index 0000000..f0187d7 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ArrayLoadInstruction.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * abstraction for all array load instructions + * + * ..., array, index => ..., value + */ +public abstract class ArrayLoadInstruction extends JVMArrayElementInstruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + index = frame.peek(); + arrayRef = frame.peek(1); // ..,arrayRef,idx + if (arrayRef == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException"); + } + ElementInfo eiArray = ti.getElementInfo(arrayRef); + + indexOperandAttr = peekIndexAttr(ti); + arrayOperandAttr = peekArrayAttr(ti); + + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedArrayCG( ti, this, eiArray, index)){ // don't modify the frame before this + eiArray = scheduler.updateArraySharedness(ti, eiArray, index); + if (scheduler.setsSharedArrayCG( ti, this, eiArray, index)){ + return this; + } + } + + frame.pop(2); // now we can pop index and array reference + + try { + push(frame, eiArray, index); + + Object elementAttr = eiArray.getElementAttr(index); + if (elementAttr != null) { + if (getElementSize() == 1) { + frame.setOperandAttr(elementAttr); + } else { + frame.setLongOperandAttr(elementAttr); + } + } + + return getNext(ti); + + } catch (ArrayIndexOutOfBoundsExecutiveException ex) { + return ex.getInstruction(); + } + } + + protected boolean isReference () { + return false; + } + + /** + * only makes sense pre-exec + */ + @Override + public int peekArrayRef (ThreadInfo ti){ + return ti.getTopFrame().peek(1); + } + + @Override + public Object peekArrayAttr (ThreadInfo ti){ + return ti.getTopFrame().getOperandAttr(1); + } + + // wouldn't really be required for loads, but this is a general + // ArrayInstruction API + @Override + public int peekIndex (ThreadInfo ti){ + return ti.getTopFrame().peek(); + } + + @Override + public Object peekIndexAttr (ThreadInfo ti){ + return ti.getTopFrame().getOperandAttr(); + } + + protected abstract void push (StackFrame frame, ElementInfo e, int index) + throws ArrayIndexOutOfBoundsExecutiveException; + + + @Override + public boolean isRead() { + return true; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + } diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ArrayStoreInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/ArrayStoreInstruction.java new file mode 100644 index 0000000..a0b5f32 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ArrayStoreInstruction.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * abstraction for all array store instructions + * + * ... array, index, => ... + */ +public abstract class ArrayStoreInstruction extends JVMArrayElementInstruction implements StoreInstruction, JVMInstruction { + + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + int idx = peekIndex(ti); + int aref = peekArrayRef(ti); // need to be polymorphic, could be LongArrayStore + ElementInfo eiArray = ti.getElementInfo(aref); + + arrayOperandAttr = peekArrayAttr(ti); + indexOperandAttr = peekIndexAttr(ti); + + if (!ti.isFirstStepInsn()){ // first execution, top half + //--- runtime exceptions + if (aref == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException"); + } + + //--- shared access CG + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedArrayCG(ti, this, eiArray, idx)){ + eiArray = scheduler.updateArraySharedness(ti, eiArray, idx); + if (scheduler.setsSharedArrayCG(ti, this, eiArray, idx)){ + return this; + } + } + } + + try { + setArrayElement(ti, frame, eiArray); // this pops operands + } catch (ArrayIndexOutOfBoundsExecutiveException ex) { // at this point, the AIOBX is already processed + return ex.getInstruction(); + } + + return getNext(ti); + } + + protected void setArrayElement (ThreadInfo ti, StackFrame frame, ElementInfo eiArray) throws ArrayIndexOutOfBoundsExecutiveException { + int esize = getElementSize(); + Object attr = esize == 1 ? frame.getOperandAttr() : frame.getLongOperandAttr(); + + popValue(frame); + index = frame.pop(); + // don't set 'arrayRef' before we do the CG checks (would kill loop optimization) + arrayRef = frame.pop(); + + eiArray = eiArray.getModifiableInstance(); + setField(eiArray, index); + eiArray.setElementAttrNoClone(index,attr); // <2do> what if the value is the same but not the attr? + } + + /** + * this is for pre-exec use + */ + @Override + public int peekArrayRef(ThreadInfo ti) { + return ti.getTopFrame().peek(2); + } + + @Override + public int peekIndex(ThreadInfo ti){ + return ti.getTopFrame().peek(1); + } + + // override in LongArrayStoreInstruction + @Override + public Object peekArrayAttr (ThreadInfo ti){ + return ti.getTopFrame().getOperandAttr(2); + } + + @Override + public Object peekIndexAttr (ThreadInfo ti){ + return ti.getTopFrame().getOperandAttr(1); + } + + + protected abstract void popValue(StackFrame frame); + + protected abstract void setField (ElementInfo e, int index) + throws ArrayIndexOutOfBoundsExecutiveException; + + + @Override + public boolean isRead() { + return false; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/BALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/BALOAD.java new file mode 100644 index 0000000..f10901d --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/BALOAD.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.BooleanArrayFields; +import gov.nasa.jpf.vm.ByteArrayFields; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Fields; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Load byte or boolean from array + * ..., arrayref, index => ..., value + */ +public class BALOAD extends ArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + + int value = 0; + Fields f = ei.getFields(); + if (f instanceof ByteArrayFields){ + value = ei.getByteElement(index); + } else if (f instanceof BooleanArrayFields){ + value = ei.getBooleanElement(index) ? 1 : 0; + } + + frame.push( value); + } + + + @Override + public int getByteCode () { + return 0x33; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/BASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/BASTORE.java new file mode 100644 index 0000000..9590212 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/BASTORE.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.BooleanArrayFields; +import gov.nasa.jpf.vm.ByteArrayFields; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Fields; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Store into byte or boolean array + * ..., arrayref, index, value => ... + */ +public class BASTORE extends ArrayStoreInstruction { + + byte value; + + @Override + protected void popValue(StackFrame frame){ + value = (byte)frame.pop(); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + + Fields f = ei.getFields(); + + if (f instanceof ByteArrayFields){ + ei.setByteElement(index, value); + + } else if (f instanceof BooleanArrayFields){ + ei.setBooleanElement(index, value != 0 ? true : false); + } + + } + + @Override + public int getByteCode () { + return 0x54; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public byte getValue(){ + return value; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/BIPUSH.java b/src/main/gov/nasa/jpf/jvm/bytecode/BIPUSH.java new file mode 100644 index 0000000..4f63d86 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/BIPUSH.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push byte + * ... => ..., value + */ +public class BIPUSH extends Instruction implements JVMInstruction { + private int value; + + public BIPUSH() {} // this is going away + + public BIPUSH(int value){ + this.value = value; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.push(value); + + return getNext(ti); + } + + public int getValue(){ + return value; + } + + @Override + public int getLength() { + return 2; // opcode, byte + } + + @Override + public int getByteCode () { + return 0x10; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/CALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/CALOAD.java new file mode 100644 index 0000000..12984e1 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/CALOAD.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Load char from array + * ..., arrayref, index => ..., value + */ +public class CALOAD extends ArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo e, int index) throws ArrayIndexOutOfBoundsExecutiveException { + e.checkArrayBounds(index); + frame.push( e.getCharElement(index), isReference()); + } + + @Override + public int getByteCode () { + return 0x34; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/CASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/CASTORE.java new file mode 100644 index 0000000..ddb2918 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/CASTORE.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Store into char array + * ..., arrayref, index, value => ... + */ +public class CASTORE extends ArrayStoreInstruction { + + char value; + + @Override + protected void popValue(StackFrame frame){ + value = (char)frame.pop(); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setCharElement(index, value); + } + + @Override + public int getByteCode () { + return 0x55; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/CHECKCAST.java b/src/main/gov/nasa/jpf/jvm/bytecode/CHECKCAST.java new file mode 100644 index 0000000..b121da9 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/CHECKCAST.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Check whether object is of given type + * ..., objectref => ..., objectref + */ +public class CHECKCAST extends Instruction implements JVMInstruction { + String type; + + public CHECKCAST() {} // this is going away + + public CHECKCAST(String typeName){ + type = Types.getClassNameFromTypeName(typeName); + } + + public String getTypeName() { + return type; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getTopFrame(); + int objref = frame.peek(); + + if (objref == MJIEnv.NULL) { + // we can cast 'null' to anything + + } else { + boolean isValid = false; + + if(Types.isReferenceSignature(type)) { + String t; + if(Types.isArray(type)) { + // retrieve the component terminal + t = Types.getComponentTerminal(type); + } else { + t = type; + } + + // resolve the referenced class + try { + ti.resolveReferencedClass(t); + } catch(LoadOnJPFRequired lre) { + return ti.getPC(); + } + } + + ElementInfo e = ti.getElementInfo(objref); + ClassInfo eci = e.getClassInfo(); + + if (type.charAt(0) == '['){ // cast between array types + if (eci.isArray()) { + // check if the element types are compatible + ClassInfo cci = eci.getComponentClassInfo(); + isValid = cci.isInstanceOf(type.substring(1)); + } + + } else { // non-array types + isValid = e.getClassInfo().isInstanceOf(type); + } + + if (!isValid) { + return ti.createAndThrowException("java.lang.ClassCastException", + e.getClassInfo().getName() + " cannot be cast to " + type); + } + } + + return getNext(ti); + } + + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xC0; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/D2F.java b/src/main/gov/nasa/jpf/jvm/bytecode/D2F.java new file mode 100644 index 0000000..d7a5497 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/D2F.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert double to float + * ..., value => ..., result + */ +public class D2F extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v = frame.popDouble(); + frame.pushFloat( (float)v); + + return getNext(ti); + } + + + @Override + public int getByteCode () { + return 0x90; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/D2I.java b/src/main/gov/nasa/jpf/jvm/bytecode/D2I.java new file mode 100644 index 0000000..a13b46e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/D2I.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert double to int + * ..., value => ..., result + */ +public class D2I extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v = frame.popDouble(); + frame.push( (int)v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x8E; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/D2L.java b/src/main/gov/nasa/jpf/jvm/bytecode/D2L.java new file mode 100644 index 0000000..f28f37f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/D2L.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert double to long + * ..., value => ..., result + */ +public class D2L extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v = frame.popDouble(); + frame.pushLong( (long) v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x8F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DADD.java b/src/main/gov/nasa/jpf/jvm/bytecode/DADD.java new file mode 100644 index 0000000..76cc41c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DADD.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Add double + * ..., value1, value2 => ..., result + */ +public class DADD extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v1 = frame.popDouble(); + double v2 = frame.popDouble(); + + double r = v1 + v2; + + frame.pushDouble(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x63; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/DALOAD.java new file mode 100644 index 0000000..3cf2a4e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DALOAD.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Load double from array + * ..., arrayref, index => ..., value + */ +public class DALOAD extends LongArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + double value = ei.getDoubleElement(index); + frame.pushLong( Double.doubleToLongBits(value)); + } + + @Override + public int getByteCode () { + return 0x31; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/DASTORE.java new file mode 100644 index 0000000..25ac2bc --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DASTORE.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Store into double array + * ..., arrayref, index, value => ... + */ +public class DASTORE extends LongArrayStoreInstruction { + + double value; + + @Override + protected void popValue(StackFrame frame){ + value = Double.longBitsToDouble(frame.popLong()); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setDoubleElement(index, value); + } + + + @Override + public int getByteCode () { + return 0x52; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DCMPG.java b/src/main/gov/nasa/jpf/jvm/bytecode/DCMPG.java new file mode 100644 index 0000000..ca11dd1 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DCMPG.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + +/** + * Compare double + * ..., value1, value2 => ..., result + */ +public class DCMPG extends DoubleCompareInstruction { + + @Override + protected int conditionValue(double v1, double v2) { + if (Double.isNaN(v1) || Double.isNaN(v2)) { + return 1; + } else if (v1 == v2) { + return 0; + } else if (v2 > v1) { + return 1; + } else { + return -1; + } + } + + @Override + public int getByteCode () { + return 0x98; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DCMPL.java b/src/main/gov/nasa/jpf/jvm/bytecode/DCMPL.java new file mode 100644 index 0000000..09f97a4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DCMPL.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + + +/** + * Compare double + * ..., value1, value2 => ..., result + */ +public class DCMPL extends DoubleCompareInstruction { + + + @Override + protected int conditionValue(double v1, double v2) { + if (Double.isNaN(v1) || Double.isNaN(v2)) { + return -1; + } else if (v1 == v2) { + return 0; + } else if (v2 > v1) { + return 1; + } else { + return -1; + } + } + + @Override + public int getByteCode () { + return 0x97; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DCONST.java b/src/main/gov/nasa/jpf/jvm/bytecode/DCONST.java new file mode 100644 index 0000000..eb7660c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DCONST.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push double + * ... => ..., + */ +public class DCONST extends Instruction implements JVMInstruction { + private double value; + + public DCONST() {} // this is going away + + public DCONST (double d){ + value = d; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + frame.pushDouble(value); + + return getNext(ti); + } + + public double getValue(){ + return value; + } + + @Override + public int getByteCode () { + return 0x0E; // ? DCONST_0 0x0E , DCONST_1 0x0F + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DDIV.java b/src/main/gov/nasa/jpf/jvm/bytecode/DDIV.java new file mode 100644 index 0000000..4c20b68 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DDIV.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Divide double + * ..., value1, value2 => ..., result + */ +public class DDIV extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v1 = frame.popDouble(); + double v2 = frame.popDouble(); + + double r = v2 / v1; + + frame.pushDouble(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x6F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DIRECTCALLRETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/DIRECTCALLRETURN.java new file mode 100644 index 0000000..4561426 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DIRECTCALLRETURN.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.ReturnInstruction; + +/** + * this is used to return from a DirectCallStackFrame + * + * Note that it is NOT a ReturnInstruction, in case listeners monitor these + * and expect corresponding InvokeInstructions. Although this would seem intuitive, it + * would be pointless to derive because the ReturnInstruction.enter() does + * a lot of things we would have to cut off, i.e. it would require more effort + * to undo this (no sync, no return value, no pc advance on the returned-to + * stackframe etc.) + * + * However, having a dedicated direct call return instruction makes sense so + * that the ReturnInstruction of the called method does not have to handle + * direct calls specifically + */ +public class DIRECTCALLRETURN extends ReturnInstruction implements JVMInstruction { + + @Override + public boolean isExtendedInstruction() { + return true; + } + + public static final int OPCODE = 261; + + @Override + public int getByteCode () { + return OPCODE; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction execute (ThreadInfo ti) { + if (ti.getStackDepth() == 1){ // thread exit point + // this can execute several times because of the different locks involved + + if (!ti.exit()){ + return this; // repeat, we couldn't get the lock + } else { + return null; + } + + } else { + // pop the current frame but do not advance the new top frame, and do + // not touch its operand stack + + StackFrame frame = ti.popDirectCallFrame(); + return frame.getPC(); + } + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DLOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/DLOAD.java new file mode 100644 index 0000000..3e2df69 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DLOAD.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Load double from local variable + * ... => ..., value + */ +public class DLOAD extends JVMLocalVariableInstruction { + + public DLOAD (int localVarIndex){ + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLongLocal(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x26; + case 1: return 0x27; + case 2: return 0x28; + case 3: return 0x29; + } + + return 0x18; // wide version? + } + + @Override + public String getBaseMnemonic() { + return "dload"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DMUL.java b/src/main/gov/nasa/jpf/jvm/bytecode/DMUL.java new file mode 100644 index 0000000..a8232a6 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DMUL.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Multiply double + * ..., value1, value2 => ..., result + */ +public class DMUL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v1 = frame.popDouble(); + double v2 = frame.popDouble(); + + double r = v2 * v1; + + frame.pushDouble(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x6B; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DNEG.java b/src/main/gov/nasa/jpf/jvm/bytecode/DNEG.java new file mode 100644 index 0000000..5eb4ec3 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DNEG.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Negate double + * ..., value => ..., result + */ +public class DNEG extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v = frame.popDouble(); + frame.pushDouble(-v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x77; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DREM.java b/src/main/gov/nasa/jpf/jvm/bytecode/DREM.java new file mode 100644 index 0000000..1548f9f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DREM.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Remainder double + * ..., value1, value2 => ..., result + */ +public class DREM extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v1 = frame.popDouble(); + double v2 = frame.popDouble(); + + if (v1 == 0){ + return ti.createAndThrowException("java.lang.ArithmeticException","division by zero"); + } + + double r = v2 % v1; + + frame.pushDouble(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x73; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DRETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/DRETURN.java new file mode 100644 index 0000000..ec536d1 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DRETURN.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Return double from method + * ..., value => [empty] + */ +public class DRETURN extends LongReturn { + + + public double getReturnValue() { + return Types.longToDouble(ret); + } + + @Override + public Object getReturnValue(ThreadInfo ti) { + if (!isCompleted(ti)) { // we have to pull it from the operand stack + StackFrame frame = ti.getTopFrame(); + ret = frame.peekLong(); + } + + return new Double(Types.longToDouble(ret)); + } + + @Override + public int getByteCode () { + return 0xAF; + } + + @Override + public String toString() { + return "dreturn " + mi.getFullName(); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DSTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/DSTORE.java new file mode 100644 index 0000000..6f30fd0 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DSTORE.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * Store double into local variable + * ..., value => ... + */ +public class DSTORE extends JVMLocalVariableInstruction implements StoreInstruction { + + public DSTORE(int localVarIndex) { + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.storeLongOperand(index); + + return getNext(ti); + } + + @Override + public int getLength() { + return 2; // opcode, index + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x47; + case 1: return 0x48; + case 2: return 0x49; + case 3: return 0x4a; + } + + return 0x39; // ?? wide + } + + @Override + public String getBaseMnemonic() { + return "dstore"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DSUB.java b/src/main/gov/nasa/jpf/jvm/bytecode/DSUB.java new file mode 100644 index 0000000..ef34877 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DSUB.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Subtract double + * ..., value1, value2 => ..., result + */ +public class DSUB extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v1 = frame.popDouble(); + double v2 = frame.popDouble(); + + double r = v2 - v1; + + frame.pushDouble(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x67; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DUP.java b/src/main/gov/nasa/jpf/jvm/bytecode/DUP.java new file mode 100644 index 0000000..e5426f8 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DUP.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * duplicate topmost stack entry + * .., value -> .., value, value + */ +public class DUP extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo th) { + StackFrame frame = th.getModifiableTopFrame(); + + frame.dup(); + + return getNext(th); + } + + @Override + public int getByteCode () { + return 0x59; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DUP2.java b/src/main/gov/nasa/jpf/jvm/bytecode/DUP2.java new file mode 100644 index 0000000..13263b7 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DUP2.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Duplicate the top one or two operand stack values + * ..., value2, value1 => ..., value2, value1, value2, value1 + */ +public class DUP2 extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.dup2(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x5C; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X1.java b/src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X1.java new file mode 100644 index 0000000..55c9d2c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X1.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * DOCUMENT ME! + */ +public class DUP2_X1 extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.dup2_x1(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x5D; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X2.java b/src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X2.java new file mode 100644 index 0000000..25f5816 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DUP2_X2.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Duplicate the top operand stack value and insert two or three values down + * ... A B C D => ... C D.A B C D + */ +public class DUP2_X2 extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.dup2_x2(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x5E; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DUP_X1.java b/src/main/gov/nasa/jpf/jvm/bytecode/DUP_X1.java new file mode 100644 index 0000000..14e8da7 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DUP_X1.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Duplicate the top operand stack value and insert two values down + * ..., value2, value1 => ..., value1, value2, value1 + */ +public class DUP_X1 extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.dup_x1(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x5A; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DUP_X2.java b/src/main/gov/nasa/jpf/jvm/bytecode/DUP_X2.java new file mode 100644 index 0000000..d27a01c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DUP_X2.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * DOCUMENT ME! + */ +public class DUP_X2 extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.dup_x2(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x5B; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/DoubleCompareInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/DoubleCompareInstruction.java new file mode 100644 index 0000000..5e8d978 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/DoubleCompareInstruction.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * base class for double double compare instructions + */ +public abstract class DoubleCompareInstruction extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + double v1 = frame.popDouble(); + double v2 = frame.popDouble(); + + int condVal = conditionValue(v1, v2); + + frame.push( condVal); + + return getNext(ti); + } + + protected abstract int conditionValue (double v1, double v2); +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/EXECUTENATIVE.java b/src/main/gov/nasa/jpf/jvm/bytecode/EXECUTENATIVE.java new file mode 100644 index 0000000..843b934 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/EXECUTENATIVE.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.NativeMethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.lang.reflect.Method; + +/** + * this is a synthetic instruction to (re-)execute native methods + * + * Note that StackFrame and lock handling has to occur from within + * the corresponding NativeMethodInfo + */ +public class EXECUTENATIVE extends Instruction implements JVMInstruction { + + // unfortunately we can't null this in cleanupTransients(), but it is + // a potential leak for stored traces + protected NativeMethodInfo executedMethod; + + @Override + public boolean isExtendedInstruction() { + return true; + } + + public static final int OPCODE = 259; + + @Override + public int getByteCode () { + return OPCODE; + } + + public EXECUTENATIVE (){} + + public EXECUTENATIVE (NativeMethodInfo mi){ + executedMethod = mi; + } + + public void setExecutedMethod (NativeMethodInfo mi){ + executedMethod = mi; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction execute (ThreadInfo ti) { + + // we don't have to enter/leave or push/pop a frame, that's all done + // in NativeMethodInfo.execute() + // !! don't re-enter if this is reexecuted !! + return executedMethod.executeNative(ti); + } + + public MethodInfo getExecutedMethod() { + return executedMethod; + } + + public String getExecutedMethodName(){ + return executedMethod.getName(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("executenative"); + + if (executedMethod != null){ + Method m = executedMethod.getMethod(); + sb.append(' '); + sb.append( m.getDeclaringClass().getSimpleName()); + sb.append('.'); + sb.append( m.getName()); + } + + return sb.toString(); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/F2D.java b/src/main/gov/nasa/jpf/jvm/bytecode/F2D.java new file mode 100644 index 0000000..fcca517 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/F2D.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert float to double + * ..., value => ..., result + */ +public class F2D extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + float f = frame.popFloat(); + + frame.pushDouble(f); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x8D; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/F2I.java b/src/main/gov/nasa/jpf/jvm/bytecode/F2I.java new file mode 100644 index 0000000..6c88637 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/F2I.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert float to int + * ..., value => ..., result + */ +public class F2I extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + float v = frame.popFloat(); + + frame.push((int)v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x8B; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/F2L.java b/src/main/gov/nasa/jpf/jvm/bytecode/F2L.java new file mode 100644 index 0000000..00ebb5f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/F2L.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert float to long + * ..., value => ..., result + */ +public class F2L extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + float v = frame.popFloat(); + + frame.pushLong((long)v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x8C; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FADD.java b/src/main/gov/nasa/jpf/jvm/bytecode/FADD.java new file mode 100644 index 0000000..6089f63 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FADD.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Add float + * ..., value1, value2 => ..., result + */ +public class FADD extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + float r = v1 + v2; + frame.push( Types.floatToInt(r), false); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x62; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/FALOAD.java new file mode 100644 index 0000000..aa87d79 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FALOAD.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Load float from array + * ..., arrayref, index => ..., value + */ +public class FALOAD extends ArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + float value = ei.getFloatElement(index); + frame.push( Float.floatToIntBits(value)); + } + + @Override + public int getByteCode () { + return 0x30; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/FASTORE.java new file mode 100644 index 0000000..ee2dace --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FASTORE.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Store into float array + * ..., arrayref, index, value => ... + */ +public class FASTORE extends ArrayStoreInstruction { + + float value; + + @Override + protected void popValue(StackFrame frame){ + value = Float.intBitsToFloat(frame.pop()); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setFloatElement(index, value); + } + + + @Override + public int getByteCode () { + return 0x51; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FCMPG.java b/src/main/gov/nasa/jpf/jvm/bytecode/FCMPG.java new file mode 100644 index 0000000..823b599 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FCMPG.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Compare float + * ..., value1, value2 => ..., result + */ +public class FCMPG extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + frame.push(conditionValue(v1, v2), false); + + return getNext(ti); + } + + protected int conditionValue(float v1, float v2) { + if (Float.isNaN(v1) || Float.isNaN(v2)) { + return 1; + } else if (v1 == v2) { + return 0; + } else if (v2 > v1) { + return 1; + } else { + return -1; + } + } + + @Override + public int getByteCode () { + return 0x96; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FCMPL.java b/src/main/gov/nasa/jpf/jvm/bytecode/FCMPL.java new file mode 100644 index 0000000..91db159 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FCMPL.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Compare float + * ..., value1, value2 => ..., result + */ +public class FCMPL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + int condVal = conditionValue(v1, v2); + + frame.push(condVal); + + return getNext(ti); + } + + protected int conditionValue(float v1, float v2) { + if (Float.isNaN(v1) || Float.isNaN(v2)) { + return -1; + } else if (v1 == v2) { + return 0; + } else if (v2 > v1) { + return 1; + } else { + return -1; + } + } + + @Override + public int getByteCode () { + return 0x95; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FCONST.java b/src/main/gov/nasa/jpf/jvm/bytecode/FCONST.java new file mode 100644 index 0000000..3259e8f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FCONST.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push float + * ... => ..., + */ +public class FCONST extends Instruction implements JVMInstruction { + protected float value; + + + public FCONST(){} // this is going away + + public FCONST(float f){ + value = f; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushFloat(value); + + return getNext(ti); + } + + public float getValue(){ + return value; + } + + @Override + public int getByteCode () { + return 0x0B; // ?? FCONST_0, _1, _2 + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FDIV.java b/src/main/gov/nasa/jpf/jvm/bytecode/FDIV.java new file mode 100644 index 0000000..7b7fd34 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FDIV.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * divide float + * ..., value1, value2 => ..., result + */ +public class FDIV extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + float r = v2 / v1; + frame.push(Types.floatToInt(r), false); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x6E; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FINISHCLINIT.java b/src/main/gov/nasa/jpf/jvm/bytecode/FINISHCLINIT.java new file mode 100644 index 0000000..add2baf --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FINISHCLINIT.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * artificial bytecode to defer class status changes of classes that don't have + * a (), simulating native VM specific behavior that involves nested locking + * during class init + */ +public class FINISHCLINIT extends Instruction { + + protected ClassInfo ciInit; + + public FINISHCLINIT (ClassInfo ci){ + ciInit = ci; + } + + @Override + public Instruction execute (ThreadInfo ti) { + ciInit.setInitialized(); + return getNext(ti); + } + + @Override + public boolean isExtendedInstruction() { + return true; + } + + public static final int OPCODE = 262; + + @Override + public int getByteCode () { + return OPCODE; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FLOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/FLOAD.java new file mode 100644 index 0000000..a501de5 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FLOAD.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Load float from local variable + * ... => ..., value + */ +public class FLOAD extends JVMLocalVariableInstruction { + + public FLOAD(int localVarIndex){ + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLocal(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x22; + case 1: return 0x23; + case 2: return 0x24; + case 3: return 0x25; + } + + return 0x17; // ?? wide version + } + + @Override + public String getBaseMnemonic() { + return "fload"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FMUL.java b/src/main/gov/nasa/jpf/jvm/bytecode/FMUL.java new file mode 100644 index 0000000..34075e2 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FMUL.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Multiply float + * ..., value1, value2 => ..., result + */ +public class FMUL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + float r = v1 * v2; + frame.push(Types.floatToInt(r), false); + + return getNext(ti); + } + + + @Override + public int getByteCode () { + return 0x6A; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FNEG.java b/src/main/gov/nasa/jpf/jvm/bytecode/FNEG.java new file mode 100644 index 0000000..7fc7314 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FNEG.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Negate float + * ..., value => ..., result + */ +public class FNEG extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v = frame.popFloat(); + + frame.pushFloat( -v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x76; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FREM.java b/src/main/gov/nasa/jpf/jvm/bytecode/FREM.java new file mode 100644 index 0000000..69f9c8e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FREM.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Remainder float + * ..., value1, value2 => ..., result + */ +public class FREM extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + if (v1 == 0){ + return ti.createAndThrowException("java.lang.ArithmeticException","division by zero"); + } + + float r = v2 % v1; + + frame.pushFloat(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x72; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FRETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/FRETURN.java new file mode 100644 index 0000000..4609a76 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FRETURN.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Return float from method + * ..., value => [empty] + */ +public class FRETURN extends JVMReturnInstruction { + + float ret; + + @Override + public int getReturnTypeSize() { + return 1; + } + + @Override + protected Object getReturnedOperandAttr (StackFrame frame) { + return frame.getOperandAttr(); + } + + @Override + protected void getAndSaveReturnValue (StackFrame frame) { + ret = frame.popFloat(); + } + + @Override + protected void pushReturnValue (StackFrame frame) { + frame.pushFloat(ret); + } + + public float getReturnValue () { + return ret; + } + + @Override + public Float getReturnValue (ThreadInfo ti) { + if (!isCompleted(ti)) { // we have to pull it from the operand stack + StackFrame frame = ti.getTopFrame(); + ret = frame.peekFloat(); + } + + return new Float(ret); + } + + @Override + public int getByteCode () { + return 0xAE; + } + + @Override + public String toString() { + return "freturn " + mi.getFullName(); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FSTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/FSTORE.java new file mode 100644 index 0000000..617f205 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FSTORE.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Store float into local variable + * ..., value => ... + */ +public class FSTORE extends JVMLocalVariableInstruction implements StoreInstruction { + + public FSTORE(int localVarIndex) { + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.storeOperand(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x43; + case 1: return 0x44; + case 2: return 0x45; + case 3: return 0x46; + } + + return 0x38; // ?? wide + } + + @Override + public String getBaseMnemonic() { + return "fstore"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/FSUB.java b/src/main/gov/nasa/jpf/jvm/bytecode/FSUB.java new file mode 100644 index 0000000..f9291f4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/FSUB.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Subtract float + * ..., value1, value2 => ..., result + */ +public class FSUB extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + float v1 = frame.popFloat(); + float v2 = frame.popFloat(); + + float r = v2 - v1; + + frame.pushFloat(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x66; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/GETFIELD.java b/src/main/gov/nasa/jpf/jvm/bytecode/GETFIELD.java new file mode 100644 index 0000000..5627b12 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/GETFIELD.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.ReadInstruction; + + +/** + * Fetch field from object + * ..., objectref => ..., value + */ +public class GETFIELD extends JVMInstanceFieldInstruction implements ReadInstruction { + + public GETFIELD (String fieldName, String classType, String fieldDescriptor){ + super(fieldName, classType, fieldDescriptor); + } + + + @Override + public int getObjectSlot (StackFrame frame){ + return frame.getTopPos(); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + int objRef = frame.peek(); // don't pop yet, we might re-enter + lastThis = objRef; + + //--- check for obvious exceptions + if (objRef == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException", + "referencing field '" + fname + "' on null object"); + } + + ElementInfo eiFieldOwner = ti.getElementInfo(objRef); + FieldInfo fieldInfo = getFieldInfo(); + if (fieldInfo == null) { + return ti.createAndThrowException("java.lang.NoSuchFieldError", + "referencing field '" + fname + "' in " + eiFieldOwner); + } + + //--- check for potential transition breaks (be aware everything above gets re-executed) + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedObjectCG( ti, this, eiFieldOwner, fieldInfo)){ + eiFieldOwner = scheduler.updateObjectSharedness( ti, eiFieldOwner, fieldInfo); + if (scheduler.setsSharedObjectCG( ti, this, eiFieldOwner, fieldInfo)){ + return this; // re-execute + } + } + + frame.pop(); // Ok, now we can remove the object ref from the stack + Object fieldAttr = eiFieldOwner.getFieldAttr(fieldInfo); + + // We could encapsulate the push in ElementInfo, but not the GET, so we keep it at the same level + if (fieldInfo.getStorageSize() == 1) { // 1 slotter + int ival = eiFieldOwner.get1SlotField(fieldInfo); + lastValue = ival; + + if (fieldInfo.isReference()){ + frame.pushRef(ival); + + } else { + frame.push(ival); + } + + if (fieldAttr != null) { + frame.setOperandAttr(fieldAttr); + } + + } else { // 2 slotter + long lval = eiFieldOwner.get2SlotField(fieldInfo); + lastValue = lval; + + frame.pushLong( lval); + if (fieldAttr != null) { + frame.setLongOperandAttr(fieldAttr); + } + } + + return getNext(ti); + } + + @Override + public ElementInfo peekElementInfo (ThreadInfo ti) { + StackFrame frame = ti.getTopFrame(); + int objRef = frame.peek(); + ElementInfo ei = ti.getElementInfo(objRef); + return ei; + } + + @Override + public boolean isMonitorEnterPrologue(){ + return GetHelper.isMonitorEnterPrologue(mi, insnIndex); + } + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xB4; + } + + @Override + public boolean isRead() { + return true; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java b/src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java new file mode 100644 index 0000000..7b1aecb --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.ReadInstruction; + + +/** + * Get static fieldInfo from class + * ..., => ..., value + */ +public class GETSTATIC extends JVMStaticFieldInstruction implements ReadInstruction { + + public GETSTATIC(String fieldName, String clsDescriptor, String fieldDescriptor){ + super(fieldName, clsDescriptor, fieldDescriptor); + } + + @Override + public Instruction execute (ThreadInfo ti) { + FieldInfo fieldInfo; + + //--- check if this causes a class load by a user defined classloader + try { + fieldInfo = getFieldInfo(); + } catch (LoadOnJPFRequired lre) { + return ti.getPC(); + } + + if (fieldInfo == null) { + return ti.createAndThrowException("java.lang.NoSuchFieldError", + (className + '.' + fname)); + } + + //--- check if this has to trigger class initialization + ClassInfo ciField = fieldInfo.getClassInfo(); + if (!mi.isClinit(ciField) && ciField.initializeClass(ti)) { + // note - this returns the next insn in the topmost clinit that just got pushed + return ti.getPC(); + } + ElementInfo eiFieldOwner = ciField.getStaticElementInfo(); + + //--- check if this breaks the transition + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedClassCG( ti, this, eiFieldOwner, fieldInfo)){ + eiFieldOwner = scheduler.updateClassSharedness(ti, eiFieldOwner, fieldInfo); + if (scheduler.setsSharedClassCG( ti, this, eiFieldOwner, fieldInfo)){ + return this; // re-execute + } + } + + Object fieldAttr = eiFieldOwner.getFieldAttr(fieldInfo); + StackFrame frame = ti.getModifiableTopFrame(); + + if (size == 1) { + int ival = eiFieldOwner.get1SlotField(fieldInfo); + lastValue = ival; + + if (fieldInfo.isReference()) { + frame.pushRef(ival); + } else { + frame.push(ival); + } + + if (fieldAttr != null) { + frame.setOperandAttr(fieldAttr); + } + + } else { + long lval = eiFieldOwner.get2SlotField(fieldInfo); + lastValue = lval; + + frame.pushLong(lval); + + if (fieldAttr != null) { + frame.setLongOperandAttr(fieldAttr); + } + } + + return getNext(ti); + } + + @Override + public boolean isMonitorEnterPrologue(){ + return GetHelper.isMonitorEnterPrologue(mi, insnIndex); + } + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xB2; + } + + @Override + public boolean isRead() { + return true; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/GOTO.java b/src/main/gov/nasa/jpf/jvm/bytecode/GOTO.java new file mode 100644 index 0000000..51afe35 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/GOTO.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Branch always + * No change + * + * <2do> store this as code insnIndex, not as bytecode position + */ +public class GOTO extends Instruction implements JVMInstruction { + protected int targetPosition; + Instruction target; + + public GOTO (int targetPosition){ + this.targetPosition = targetPosition; + } + + @Override + public Instruction execute (ThreadInfo ti) { + if (isBackJump() && ti.maxTransitionLengthExceeded()){ + // this is a rather simplistic attempt to terminate the search in + // endless loops that do not change program state. + // <2do> this does not handle nested loops yet + if (ti.breakTransition("MAX_TRANSITION_LENGTH")){ + return this; // re-execute after giving state matching a chance to prune the search + } + } + + return getTarget(); + } + + @Override + public boolean isBackJump () { + return (targetPosition <= position); + } + + public Instruction getTarget() { + if (target == null) { + target = mi.getInstructionAt(targetPosition); + } + return target; + } + + @Override + public int getLength() { + return 3; // opcode, bb1, bb2 + } + + @Override + public int getByteCode () { + return 0xA7; + } + + @Override + public String toString () { + return getMnemonic() + " " + targetPosition; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction typeSafeClone(MethodInfo mi) { + GOTO clone = null; + + try { + clone = (GOTO) super.clone(); + + // reset the method that this insn belongs to + clone.mi = mi; + + clone.target = null; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return clone; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/GOTO_W.java b/src/main/gov/nasa/jpf/jvm/bytecode/GOTO_W.java new file mode 100644 index 0000000..47828a2 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/GOTO_W.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + +public class GOTO_W extends GOTO { + + public GOTO_W(int targetPos){ + super(targetPos); + } + + @Override + public int getLength() { + return 5; // opcode, bb1, bb2, bb3, bb4 + } + + @Override + public int getByteCode() { + return 0xc8; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/GetHelper.java b/src/main/gov/nasa/jpf/jvm/bytecode/GetHelper.java new file mode 100644 index 0000000..2ae43b4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/GetHelper.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; + +/** + * helper class to factor out common GET code + * + * <2do> This is going to be moved into a Java 8 interface with default methods + */ +public class GetHelper { + + /** + * do a little bytecode pattern analysis on the fly, to find out if a + * GETFIELD or GETSTATIC is just part of a "..synchronized (obj) {..} .." + * pattern, which usually translates into the following pattern: + * ... + * getfield / getstatic + * dup + * [astore] + * monitorenter + * ... + * + * If it does, there is no need to break the transition since the object + * reference is not used for anything that can cause violations between + * the get and the monitorenter. + * + * <2do> We might want to extend this in the future to also cover sync on + * local vars, like "Object o = myField; synchronized(o){..}..", but then + * the check becomes more expensive since we get interspersed aload/astore + * insns, and some of the locals could be used outside the sync block. Not + * sure if it buys much on the bottom line + * + * <2do> this relies on javac code patterns. The dup/astore could + * lead to subsequent use of the object reference w/o corresponding get/putfield + * insns (if it's not a volatile), but this access would be either a call + * or a get/putfield on a share object, i.e. would be checked separately + */ + protected static boolean isMonitorEnterPrologue(MethodInfo mi, int insnIndex){ + Instruction[] code = mi.getInstructions(); + int off = insnIndex+1; + + if (off < code.length-3) { + // we don't reach out further than 3 instructions + if (code[off] instanceof DUP) { + off++; + + if (code[off] instanceof ASTORE) { + off++; + } + + if (code[off] instanceof MONITORENTER) { + return true; + } + } + } + + return false; // if in doubt, we assume it is not part of a monitorenter code pattern + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/I2B.java b/src/main/gov/nasa/jpf/jvm/bytecode/I2B.java new file mode 100644 index 0000000..09cbf04 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/I2B.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert int to byte + * ..., value => ..., result + */ +public class I2B extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + int v = frame.pop(); + + frame.push((byte) v, false); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x91; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/I2C.java b/src/main/gov/nasa/jpf/jvm/bytecode/I2C.java new file mode 100644 index 0000000..b33b3a6 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/I2C.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert int to char + * ..., value => ..., result + */ +public class I2C extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + int v = frame.pop(); + + frame.push( (char)v, false); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x92; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/I2D.java b/src/main/gov/nasa/jpf/jvm/bytecode/I2D.java new file mode 100644 index 0000000..4e2968d --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/I2D.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert int to double + * ..., value => ..., result + */ +public class I2D extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int ival = frame.pop(); + + frame.pushDouble(ival); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x87; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/I2F.java b/src/main/gov/nasa/jpf/jvm/bytecode/I2F.java new file mode 100644 index 0000000..e5d21c8 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/I2F.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert int to float + * ..., value =>..., result + */ +public class I2F extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v = frame.pop(); + + frame.pushFloat(v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x86; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/I2L.java b/src/main/gov/nasa/jpf/jvm/bytecode/I2L.java new file mode 100644 index 0000000..0e0a3ab --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/I2L.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert int to long + * ..., value => ..., result + */ +public class I2L extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v = frame.pop(); + + frame.pushLong(v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x85; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/I2S.java b/src/main/gov/nasa/jpf/jvm/bytecode/I2S.java new file mode 100644 index 0000000..6a2cf69 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/I2S.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert int to short + * ..., value => ..., result + */ +public class I2S extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v = frame.pop(); + + frame.push((short)v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x93; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IADD.java b/src/main/gov/nasa/jpf/jvm/bytecode/IADD.java new file mode 100644 index 0000000..a931f94 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IADD.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Add int + * ..., value1, value2 =>..., result + */ +public class IADD extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v1 + v2); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x60; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/IALOAD.java new file mode 100644 index 0000000..9ee777a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IALOAD.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Load int from array + * ..., arrayref, index => ..., value + */ +public class IALOAD extends ArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + int value = ei.getIntElement(index); + frame.push( value); + } + + @Override + public int getByteCode () { + return 0x2E; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IAND.java b/src/main/gov/nasa/jpf/jvm/bytecode/IAND.java new file mode 100644 index 0000000..e3d08a7 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IAND.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Boolean AND int + * ..., value1, value2 => ..., result + */ +public class IAND extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v1 & v2); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x7E; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IASTORE.java new file mode 100644 index 0000000..94fe36d --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IASTORE.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Store into int array + * ..., arrayref, index, value => ... + */ +public class IASTORE extends ArrayStoreInstruction { + + int value; + + @Override + protected void popValue(StackFrame frame){ + value = frame.pop(); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setIntElement(index, value); + } + + + @Override + public int getByteCode () { + return 0x4F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ICONST.java b/src/main/gov/nasa/jpf/jvm/bytecode/ICONST.java new file mode 100644 index 0000000..deeb057 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ICONST.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push int constant + * ... => ..., + */ +public class ICONST extends Instruction implements JVMInstruction { + protected int value; + + public ICONST(int value){ + this.value = value; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.push(value); + + return getNext(ti); + } + + public int getValue() { + return value; + } + + @Override + public int getByteCode () { + assert ((value >= -1) && (value < 6)) : ("illegal iconst value: " + value); + + switch (value) { + case -1: return 0x2; + case 0: return 0x3; + case 1: return 0x4; + case 2: return 0x5; + case 3: return 0x6; + case 4: return 0x7; + case 5: return 0x8; + } + return 0; + } + + @Override + public String getMnemonic () { + String s = "iconst_"; + + if (value == -1) { + return s + "m1"; + } else { + return s + value; + } + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IDIV.java b/src/main/gov/nasa/jpf/jvm/bytecode/IDIV.java new file mode 100644 index 0000000..31b9ca7 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IDIV.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Divide int + * ..., value1, value2 =>..., result + */ +public class IDIV extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + if (v1 == 0) { + return ti.createAndThrowException("java.lang.ArithmeticException", + "division by zero"); + } + + frame.push(v2 / v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x6C; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFEQ.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFEQ.java new file mode 100644 index 0000000..cfdf693 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFEQ.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison with zero succeeds + * ..., value => ... + */ +public class IFEQ extends IfInstruction { + + public IFEQ(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() == 0); + } + + + @Override + public int getByteCode () { + return 0x99; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFGE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFGE.java new file mode 100644 index 0000000..9564fd2 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFGE.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison with zero succeeds + * ..., value => ... + */ +public class IFGE extends IfInstruction { + + public IFGE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() >= 0); + } + + @Override + public int getByteCode () { + return 0x9C; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFGT.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFGT.java new file mode 100644 index 0000000..a28feb8 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFGT.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison with zero succeeds + * ..., value => ... + */ +public class IFGT extends IfInstruction { + + public IFGT(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() > 0); + } + + @Override + public int getByteCode () { + return 0x9D; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFLE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFLE.java new file mode 100644 index 0000000..97c3e96 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFLE.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + +/** + * Branch if int comparison with zero succeeds + * ..., value => ... + */ +public class IFLE extends IfInstruction { + + public IFLE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() <= 0); + } + + @Override + public int getByteCode () { + return 0x9E; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFLT.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFLT.java new file mode 100644 index 0000000..7e2b10d --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFLT.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison with zero succeeds + * ..., value => ... + */ +public class IFLT extends IfInstruction { + + public IFLT(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() < 0); + } + + @Override + public int getByteCode () { + return 0x9B; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFNE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFNE.java new file mode 100644 index 0000000..bcd9649 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFNE.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison with zero succeeds + * ..., value => ... + */ +public class IFNE extends IfInstruction { + + public IFNE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() != 0); + } + + @Override + public int getByteCode () { + return 0x9A; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFNONNULL.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFNONNULL.java new file mode 100644 index 0000000..bac53c4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFNONNULL.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if reference not null + * ..., value => ..., result + */ +public class IFNONNULL extends IfInstruction { + + public IFNONNULL(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() != MJIEnv.NULL); + } + + @Override + public int getByteCode () { + return 0xC7; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IFNULL.java b/src/main/gov/nasa/jpf/jvm/bytecode/IFNULL.java new file mode 100644 index 0000000..26673ce --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IFNULL.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; + +/** + * branch instruction for null values + */ +public class IFNULL extends IfInstruction { + + public IFNULL(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + return (frame.pop() == MJIEnv.NULL); + } + + @Override + public int getByteCode () { + return 0xC6; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPEQ.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPEQ.java new file mode 100644 index 0000000..0ca55eb --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPEQ.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if reference comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ACMPEQ extends IfInstruction { + + public IF_ACMPEQ(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 == v2); + } + + @Override + public int getByteCode () { + return 0xA5; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPNE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPNE.java new file mode 100644 index 0000000..a0f02fc --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ACMPNE.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if reference comparison does not succeed + * ..., value1, value2 => ... + */ +public class IF_ACMPNE extends IfInstruction { + + public IF_ACMPNE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 != v2); + } + + @Override + public int getByteCode () { + return 0xA6; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPEQ.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPEQ.java new file mode 100644 index 0000000..8d3527f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPEQ.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ICMPEQ extends IfInstruction { + + public IF_ICMPEQ(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 == v2); + } + + @Override + public int getByteCode () { + return 0x9F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGE.java new file mode 100644 index 0000000..0631401 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGE.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ICMPGE extends IfInstruction { + + public IF_ICMPGE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 <= v2); + } + + @Override + public int getByteCode () { + return 0xA2; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGT.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGT.java new file mode 100644 index 0000000..7d75717 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPGT.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ICMPGT extends IfInstruction { + + public IF_ICMPGT(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 < v2); + } + + @Override + public int getByteCode () { + return 0xA3; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLE.java new file mode 100644 index 0000000..cbf322b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLE.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ICMPLE extends IfInstruction { + + public IF_ICMPLE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 >= v2); + } + + @Override + public int getByteCode () { + return 0xA4; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLT.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLT.java new file mode 100644 index 0000000..68b1517 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPLT.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ICMPLT extends IfInstruction { + + public IF_ICMPLT(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 > v2); + } + + @Override + public int getByteCode () { + return 0xA1; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPNE.java b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPNE.java new file mode 100644 index 0000000..85897c9 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IF_ICMPNE.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Branch if int comparison succeeds + * ..., value1, value2 => ... + */ +public class IF_ICMPNE extends IfInstruction { + + public IF_ICMPNE(int targetPc) { + super(targetPc); + } + + + @Override + public boolean popConditionValue (StackFrame frame) { + int v1 = frame.pop(); + int v2 = frame.pop(); + + return (v1 != v2); + } + + @Override + public int getByteCode () { + return 0xA0; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IINC.java b/src/main/gov/nasa/jpf/jvm/bytecode/IINC.java new file mode 100644 index 0000000..14b1bba --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IINC.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Increment local variable by constant + * No change + */ +public class IINC extends Instruction implements JVMInstruction { + + protected int index; + protected int increment; + + public IINC(int localVarIndex, int increment) { + this.index = localVarIndex; + this.increment = increment; + } + + @Override + public Instruction execute(ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v = frame.getLocalVariable(index); + v += increment; + + frame.setLocalVariable(index, v, false); + + return getNext(ti); + } + + @Override + public int getLength() { + return 3; // opcode, index, const + } + + @Override + public int getByteCode() { + return 0x84; // ?? wide + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getIndex() { + return index; + } + + public int getIncrement() { + return increment; + } + + @Override + public String toPostExecString() { + return "iinc " + index + ' ' + increment; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ILOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/ILOAD.java new file mode 100644 index 0000000..ff5e11a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ILOAD.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Load int from local variable + * ... => ..., value + */ +public class ILOAD extends JVMLocalVariableInstruction { + + public ILOAD(int localVarIndex){ + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLocal(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x1a; + case 1: return 0x1b; + case 2: return 0x1c; + case 3: return 0x1d; + } + + return 0x15; // ?? wide + } + + @Override + public String getBaseMnemonic() { + return "iload"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IMUL.java b/src/main/gov/nasa/jpf/jvm/bytecode/IMUL.java new file mode 100644 index 0000000..d59af99 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IMUL.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Multiply int + * ..., value1, value2 => ..., result + */ +public class IMUL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v1 * v2); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x68; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INEG.java b/src/main/gov/nasa/jpf/jvm/bytecode/INEG.java new file mode 100644 index 0000000..21b970c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INEG.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Negate int + * ..., value => ..., result + */ +public class INEG extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v = frame.pop(); + + frame.push(-v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x74; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INSTANCEOF.java b/src/main/gov/nasa/jpf/jvm/bytecode/INSTANCEOF.java new file mode 100644 index 0000000..e0efab4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INSTANCEOF.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Determine if object is of given type + * ..., objectref => ..., result + */ +public class INSTANCEOF extends Instruction implements JVMInstruction { + private String type; + + + /** + * typeName is of a/b/C notation + */ + public INSTANCEOF (String typeName){ + type = Types.getTypeSignature(typeName, false); + } + + @Override + public Instruction execute (ThreadInfo ti) { + if(Types.isReferenceSignature(type)) { + String t; + if(Types.isArray(type)) { + // retrieve the component terminal + t = Types.getComponentTerminal(type); + } else { + t = type; + } + + // resolve the referenced class + try { + ti.resolveReferencedClass(t); + } catch(LoadOnJPFRequired lre) { + return ti.getPC(); + } + } + + StackFrame frame = ti.getModifiableTopFrame(); + int objref = frame.pop(); + + if (objref == MJIEnv.NULL) { + frame.push(0); + } else if (ti.getElementInfo(objref).instanceOf(type)) { + frame.push(1); + } else { + frame.push(0); + } + + return getNext(ti); + } + + public String getType() { + return type; + } + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xC1; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKECG.java b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKECG.java new file mode 100644 index 0000000..45bc4b8 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKECG.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.jvm.JVMInstructionFactory; +import gov.nasa.jpf.util.Invocation; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ObjRef; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; +import gov.nasa.jpf.vm.choice.InvocationCG; + +import java.util.List; + +/** + * a sytnthetic INVOKE instruction that gets it's parameters from an + * InvocationCG. Whoever uses this better makes sure the frame this + * executes in has enough operand space (e.g. a DirectCallStackFrame). + * + */ +public class INVOKECG extends Instruction implements JVMInstruction { + + List invokes; + JVMInvokeInstruction realInvoke; + + public INVOKECG(List invokes){ + this.invokes = invokes; + } + + + public void setInvokes(List invokes) { + this.invokes = invokes; + } + + @Override + public Instruction execute (ThreadInfo ti) { + + if (!ti.isFirstStepInsn()) { + InvocationCG cg = new InvocationCG( "INVOKECG", invokes); + if (ti.getVM().setNextChoiceGenerator(cg)){ + return this; + } + + } else { + InvocationCG cg = ti.getVM().getCurrentChoiceGenerator( "INVOKECG", InvocationCG.class); + assert (cg != null) : "no current InvocationCG"; + + Invocation call = cg.getNextChoice(); + MethodInfo callee = call.getMethodInfo(); + JVMInstructionFactory insnFactory = JVMInstructionFactory.getFactory(); + + String clsName = callee.getClassInfo().getName(); + String mthName = callee.getName(); + String signature = callee.getSignature(); + + Instruction realInvoke; + if (callee.isStatic()){ + realInvoke = insnFactory.invokestatic(clsName, mthName, signature); + } else { + realInvoke = insnFactory.invokevirtual(clsName, mthName, signature); + } + + pushArguments(ti, call.getArguments(), call.getAttrs()); + + return realInvoke; + } + + return getNext(); + } + + void pushArguments (ThreadInfo ti, Object[] args, Object[] attrs){ + StackFrame frame = ti.getModifiableTopFrame(); + + if (args != null){ + for (int i=0; i calls, which are never in the loaded bytecode but always directly called by + * the VM. The most obvious difference is that execution does not trigger + * class initialization. + * A more subtle difference is that we save a wait() - if a class + * is concurrently initialized, both enter INVOKECLINIT (i.e. compete and sync for/on + * the class object lock), but once the second thread gets resumed and detects that the + * class is now initialized (by the first thread), it skips the method execution and + * returns right away (after deregistering as a lock contender). That's kind of hackish, + * but we have no method to do the wait in, unless we significantly complicate the + * direct call stubs, which would obfuscate observability (debugging dynamically + * generated code isn't very appealing). + */ +public class INVOKECLINIT extends INVOKESTATIC { + + public INVOKECLINIT (ClassInfo ci){ + super(ci.getSignature(), "", "()V"); + } + + @Override + public Instruction execute (ThreadInfo ti) { + MethodInfo callee = getInvokedMethod(ti); + ClassInfo ciClsObj = callee.getClassInfo(); + ElementInfo ei = ciClsObj.getClassObject(); + + if (ciClsObj.isInitialized()) { // somebody might have already done it if this is re-executed + if (ei.isRegisteredLockContender(ti)){ + ei = ei.getModifiableInstance(); + ei.unregisterLockContender(ti); + } + return getNext(); + } + + // not much use to update sharedness, clinits are automatically synchronized + if (reschedulesLockAcquisition(ti, ei)){ // this blocks or registers as lock contender + return this; + } + + // if we get here we still have to execute the clinit method + setupCallee( ti, callee); // this creates, initializes & pushes the callee StackFrame, then acquires the lock + ciClsObj.setInitializing(ti); + + return ti.getPC(); // we can't just return the first callee insn if a listener throws an exception + } + + @Override + public boolean isExtendedInstruction() { + return true; + } + + public static final int OPCODE = 256; + + @Override + public int getByteCode () { + return OPCODE; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java new file mode 100644 index 0000000..a071ece --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.BootstrapMethodInfo; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FunctionObjectFactory; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; +import gov.nasa.jpf.vm.VM; + +/** + * @author Nastaran Shafiei + * + * Invoke dynamic method. It allows dynamic linkage between a call site and a method implementation. + * + * ..., [arg1, [arg2 ...]] => ... + */ +public class INVOKEDYNAMIC extends Instruction { + + // index of a bootstrap method (index to the array bootstrapMethods[] declared in ClassInfo + // containing this bytecode instruction) + int bootstrapMethodIndex; + + // Free variables are those that are not defined within the lamabda body and + // are captured from the lexical scope. Note that for instance lambda methods + // the first captured variable always represents "this" + String[] freeVariableTypeNames; + byte[] freeVariableTypes; + + String functionalInterfaceName; + + String samMethodName; + + int funcObjRef = MJIEnv.NULL; + + ElementInfo lastFuncObj = null; + + public INVOKEDYNAMIC () {} + + protected INVOKEDYNAMIC (int bmIndex, String methodName, String descriptor){ + bootstrapMethodIndex = bmIndex; + samMethodName = methodName; + freeVariableTypeNames = Types.getArgumentTypeNames(descriptor); + freeVariableTypes = Types.getArgumentTypes(descriptor); + functionalInterfaceName = Types.getReturnTypeSignature(descriptor); + } + + @Override + public int getByteCode () { + return 0xBA; + } + + @Override + public String toString() { + String args = ""; + for(String type: freeVariableTypeNames) { + if(args.length()>0) { + type += ','+ type; + } + args += type; + } + return "invokedynamic " + bootstrapMethodIndex + " " + + samMethodName + '(' + args +"):" + functionalInterfaceName; + } + + /** + * For now, INVOKEDYNAMIC works only in the context of lambda expressions. + * Executing this returns an object that implements the functional interface + * and contains a method which captures the behavior of the lambda expression. + */ + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + ElementInfo ei = ti.getHeap().get(funcObjRef); + + if(ei==null || ei!=lastFuncObj || freeVariableTypes.length>0) { + ClassInfo fiClassInfo; + + // First, resolve the functional interface + try { + fiClassInfo = ti.resolveReferencedClass(functionalInterfaceName); + } catch(LoadOnJPFRequired lre) { + return ti.getPC(); + } + + if (fiClassInfo.initializeClass(ti)) { + return ti.getPC(); + } + + ClassInfo enclosingClass = this.getMethodInfo().getClassInfo(); + + BootstrapMethodInfo bmi = enclosingClass.getBootstrapMethodInfo(bootstrapMethodIndex); + + VM vm = VM.getVM(); + FunctionObjectFactory funcObjFactory = vm.getFunctionObjectFacotry(); + + Object[] freeVariableValues = frame.getArgumentsValues(ti, freeVariableTypes); + + funcObjRef = funcObjFactory.getFunctionObject(bootstrapMethodIndex, ti, fiClassInfo, samMethodName, bmi, freeVariableTypeNames, freeVariableValues); + lastFuncObj = ti.getHeap().get(funcObjRef); + } + + frame.pop(freeVariableTypes.length); + frame.pushRef(funcObjRef); + + return getNext(ti); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEINTERFACE.java b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEINTERFACE.java new file mode 100644 index 0000000..3a7c22a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEINTERFACE.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + +/** + * Invoke interface method + * ..., objectref, [arg1, [arg2 ...]] => ... + */ +public class INVOKEINTERFACE extends VirtualInvocation { + public INVOKEINTERFACE () {} + + protected INVOKEINTERFACE (String clsDescriptor, String methodName, String signature){ + super(clsDescriptor, methodName, signature); + } + + + @Override + public int getLength() { + return 5; // opcode, index1, index2, nargs, 0 + } + + @Override + public int getByteCode () { + return 0xB9; + } + + @Override + public String toString() { + // methodInfo not set outside real call context (requires target object) + return "invokeinterface " + cname + '.' + mname; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESPECIAL.java b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESPECIAL.java new file mode 100644 index 0000000..94f399c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESPECIAL.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Invoke instance method; special handling for superclass, private, + * and instance initialization method invocations + * ..., objectref, [arg1, [arg2 ...]] => ... + * + * invokedMethod is supposed to be constant (ClassInfo can't change) + */ +public class INVOKESPECIAL extends InstanceInvocation { + + public INVOKESPECIAL (String clsDescriptor, String methodName, String signature){ + super(clsDescriptor, methodName, signature); + } + + + @Override + public int getByteCode () { + return 0xB7; + } + + @Override + public Instruction execute (ThreadInfo ti) { + int argSize = getArgSize(); + int objRef = ti.getCalleeThis( argSize); + lastObj = objRef; + + // we don't have to check for NULL objects since this is either a ctor, a + // private method, or a super method + + MethodInfo callee; + try { + callee = getInvokedMethod(ti); + } catch(LoadOnJPFRequired rre) { + return ti.getPC(); + } + + if (callee == null){ + return ti.createAndThrowException("java.lang.NoSuchMethodException", "Calling " + cname + '.' + mname); + } + + ElementInfo ei = ti.getElementInfo(objRef); + if (callee.isSynchronized()){ + ei = ti.getScheduler().updateObjectSharedness(ti, ei, null); // locks most likely belong to shared objects + if (reschedulesLockAcquisition(ti, ei)){ + return this; + } + } + + setupCallee( ti, callee); // this creates, initializes and pushes the callee StackFrame + + return ti.getPC(); // we can't just return the first callee insn if a listener throws an exception + } + + /** + * If the current thread already owns the lock, then the current thread can go on. + * For example, this is a recursive acquisition. + */ + protected boolean isLockOwner(ThreadInfo ti, ElementInfo ei) { + return ei.getLockingThread() == ti; + } + + /** + * If the object will still be owned, then the current thread can go on. + * For example, all but the last monitorexit for the object. + */ + protected boolean isLastUnlock(ElementInfo ei) { + return ei.getLockCount() == 1; + } + + /** + * we can do some more caching here - the MethodInfo should be const + */ + @Override + public MethodInfo getInvokedMethod (ThreadInfo th) { + + // since INVOKESPECIAL is only used for private methods and ctors, + // we don't have to deal with null object calls + + if (invokedMethod == null) { + ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(cname); + boolean recursiveLookup = (mname.charAt(0) != '<'); // no hierarchy lookup for + invokedMethod = ci.getMethod(mname, recursiveLookup); + } + + return invokedMethod; // we can store internally + } + + @Override + public String toString() { + return ("invokespecial " + cname + '.' + mname); + } + + @Override + public Object getFieldValue (String id, ThreadInfo ti) { + int objRef = getCalleeThis(ti); + ElementInfo ei = ti.getElementInfo(objRef); + + Object v = ei.getFieldValueObject(id); + + if (v == null){ // try a static field + v = ei.getClassInfo().getStaticFieldValueObject(id); + } + + return v; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java new file mode 100644 index 0000000..0ff67ae --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StaticElementInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Invoke a class (static) method + * ..., [arg1, [arg2 ...]] => ... + */ +public class INVOKESTATIC extends JVMInvokeInstruction { + ClassInfo ci; + + protected INVOKESTATIC (String clsDescriptor, String methodName, String signature){ + super(clsDescriptor, methodName, signature); + } + + protected ClassInfo getClassInfo () { + if (ci == null) { + ci = ClassLoaderInfo.getCurrentResolvedClassInfo(cname); + } + return ci; + } + + @Override + public int getByteCode () { + return 0xB8; + } + + @Override + public String toPostExecString(){ + StringBuilder sb = new StringBuilder(); + sb.append(getMnemonic()); + sb.append(' '); + sb.append( invokedMethod.getFullName()); + + if (invokedMethod.isMJI()){ + sb.append(" [native]"); + } + + return sb.toString(); + + } + + public StaticElementInfo getStaticElementInfo (){ + return getClassInfo().getStaticElementInfo(); + } + + public int getClassObjectRef(){ + return getClassInfo().getStaticElementInfo().getClassObjectRef(); + } + + @Override + public Instruction execute (ThreadInfo ti) { + MethodInfo callee; + + try { + callee = getInvokedMethod(ti); + } catch (LoadOnJPFRequired lre) { + return ti.getPC(); + } + + if (callee == null) { + return ti.createAndThrowException("java.lang.NoSuchMethodException", cname + '.' + mname); + } + + // this can be actually different than (can be a base) + ClassInfo ciCallee = callee.getClassInfo(); + + if (ciCallee.initializeClass(ti)) { + // do class initialization before continuing + // note - this returns the next insn in the topmost clinit that just got pushed + return ti.getPC(); + } + + if (callee.isSynchronized()) { + ElementInfo ei = ciCallee.getClassObject(); + ei = ti.getScheduler().updateObjectSharedness(ti, ei, null); // locks most likely belong to shared objects + + if (reschedulesLockAcquisition(ti, ei)){ + return this; + } + } + + setupCallee( ti, callee); // this creates, initializes and pushes the callee StackFrame + + return ti.getPC(); // we can't just return the first callee insn if a listener throws an exception + } + + @Override + public MethodInfo getInvokedMethod(){ + if (invokedMethod != null){ + return invokedMethod; + } else { + // Hmm, this would be pre-exec, but if the current thread is not the one executing the insn + // this might result in false sharedness of the class object + return getInvokedMethod( ThreadInfo.getCurrentThread()); + } + } + + @Override + public MethodInfo getInvokedMethod (ThreadInfo ti){ + if (invokedMethod == null) { + ClassInfo clsInfo = getClassInfo(); + if (clsInfo != null){ + MethodInfo callee = clsInfo.getMethod(mname, true); + if (callee != null){ + ClassInfo ciCallee = callee.getClassInfo(); // might be a superclass of ci, i.e. not what is referenced in the insn + + if (!ciCallee.isRegistered()){ + // if it wasn't registered yet, classLoaded listeners didn't have a chance yet to modify it.. + ciCallee.registerClass(ti); + // .. and might replace/remove MethodInfos + callee = clsInfo.getMethod(mname, true); + } + invokedMethod = callee; + } + } + } + return invokedMethod; + } + + // can be different thatn the ci - method can be in a superclass + public ClassInfo getInvokedClassInfo(){ + return getInvokedMethod().getClassInfo(); + } + + public String getInvokedClassName(){ + return getInvokedClassInfo().getName(); + } + + @Override + public int getArgSize () { + if (argSize < 0) { + argSize = Types.getArgumentsSize(signature); + } + + return argSize; + } + + + @Override + public String toString() { + // methodInfo not set outside real call context (requires target object) + return "invokestatic " + cname + '.' + mname; + } + + @Override + public Object getFieldValue (String id, ThreadInfo ti) { + return getClassInfo().getStaticFieldValueObject(id); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction typeSafeClone(MethodInfo mi) { + INVOKESTATIC clone = null; + + try { + clone = (INVOKESTATIC) super.clone(); + + // reset the method that this insn belongs to + clone.mi = mi; + + clone.invokedMethod = null; + clone.lastObj = Integer.MIN_VALUE; + clone.ci = null; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return clone; + } +} + diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEVIRTUAL.java b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEVIRTUAL.java new file mode 100644 index 0000000..841b328 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEVIRTUAL.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + + +/** + * Invoke instance method; dispatch based on class + * ..., objectref, [arg1, [arg2 ...]] => ... + */ +public class INVOKEVIRTUAL extends VirtualInvocation { + public INVOKEVIRTUAL () {} + + protected INVOKEVIRTUAL (String clsDescriptor, String methodName, String signature){ + super(clsDescriptor, methodName, signature); + } + + + @Override + public int getByteCode () { + return 0xB6; + } + + @Override + public String toString() { + // methodInfo not set outside real call context (requires target object) + return "invokevirtual " + cname + '.' + mname; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IOR.java b/src/main/gov/nasa/jpf/jvm/bytecode/IOR.java new file mode 100644 index 0000000..80f4616 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IOR.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Boolean OR int + * ..., value1, value2 => ..., result + */ +public class IOR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v1 | v2); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x80; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IREM.java b/src/main/gov/nasa/jpf/jvm/bytecode/IREM.java new file mode 100644 index 0000000..013e977 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IREM.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Remainder int + * ..., value1, value2 => ..., result + */ +public class IREM extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + if (v1 == 0){ + return ti.createAndThrowException("java.lang.ArithmeticException", "division by zero"); + } + + frame.push(v2 % v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x70; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IRETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/IRETURN.java new file mode 100644 index 0000000..339280f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IRETURN.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Return int from method + * ..., value => [empty] + */ +public class IRETURN extends JVMReturnInstruction { + + int ret; + + @Override + public int getReturnTypeSize() { + return 1; + } + + @Override + protected Object getReturnedOperandAttr (StackFrame frame) { + return frame.getOperandAttr(); + } + + @Override + protected void getAndSaveReturnValue (StackFrame ti) { + ret = ti.pop(); + } + + @Override + protected void pushReturnValue (StackFrame ti) { + ti.push(ret); + } + + public int getReturnValue () { + return ret; + } + + @Override + public Object getReturnValue(ThreadInfo ti) { + if (!isCompleted(ti)) { // we have to pull it from the operand stack + StackFrame frame = ti.getTopFrame(); + ret = frame.peek(); + } + + return new Integer(ret); + } + + @Override + public int getByteCode () { + return 0xAC; + } + + @Override + public String toString() { + return "ireturn " + mi.getFullName(); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ISHL.java b/src/main/gov/nasa/jpf/jvm/bytecode/ISHL.java new file mode 100644 index 0000000..15f6455 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ISHL.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Shift left int + * ..., value1, value2 => ..., result + */ +public class ISHL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v2 << v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x78; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ISHR.java b/src/main/gov/nasa/jpf/jvm/bytecode/ISHR.java new file mode 100644 index 0000000..c3f46f5 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ISHR.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Arithmetic shift right int + * ..., value1, value2 => ..., result + */ +public class ISHR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v2 >> v1); + + return getNext( ti); + } + + @Override + public int getByteCode () { + return 0x7A; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ISTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/ISTORE.java new file mode 100644 index 0000000..9d99d25 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ISTORE.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Store int into local variable + * ..., value => ... + */ +public class ISTORE extends JVMLocalVariableInstruction implements StoreInstruction { + + public ISTORE(int localVarIndex){ + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.storeOperand(index); + + return getNext(ti); + + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // bytecode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x3b; + case 1: return 0x3c; + case 2: return 0x3d; + case 3: return 0x3e; + } + return 0x36; // ?? wide, ISTORE_n + } + + @Override + public String getBaseMnemonic() { + return "istore"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/ISUB.java b/src/main/gov/nasa/jpf/jvm/bytecode/ISUB.java new file mode 100644 index 0000000..28c195c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/ISUB.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Subtract int + * ..., value1, value2 => ..., result + */ +public class ISUB extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v2 - v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x64; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IUSHR.java b/src/main/gov/nasa/jpf/jvm/bytecode/IUSHR.java new file mode 100644 index 0000000..58a9176 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IUSHR.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Logical shift right int + * ..., value1, value2 => ..., result + */ +public class IUSHR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v2 >>> v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x7C; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IXOR.java b/src/main/gov/nasa/jpf/jvm/bytecode/IXOR.java new file mode 100644 index 0000000..de28b88 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IXOR.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Boolean XOR int + * ..., value1, value2 => ..., result + */ +public class IXOR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + int v2 = frame.pop(); + + frame.push(v1 ^ v2); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x82; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/IfInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/IfInstruction.java new file mode 100644 index 0000000..2993bc4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/IfInstruction.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.BooleanChoiceGenerator; +import gov.nasa.jpf.vm.KernelState; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.SystemState; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * abstraction for all comparison instructions + */ +public abstract class IfInstruction extends Instruction implements JVMInstruction { + protected int targetPosition; // insn position at jump insnIndex + protected Instruction target; // jump target + + protected boolean conditionValue; /** value of last evaluation of branch condition */ + + protected IfInstruction(int targetPosition){ + this.targetPosition = targetPosition; + } + + /** + * return which branch was taken. Only useful after instruction got executed + * WATCH OUT - 'true' means the jump condition is met, which logically is + * the 'false' branch + */ + public boolean getConditionValue() { + return conditionValue; + } + + /** + * Added so that SimpleIdleFilter can detect do-while loops when + * the while statement evaluates to true. + */ + @Override + public boolean isBackJump () { + return (conditionValue) && (targetPosition <= position); + } + + /** + * retrieve value of jump condition from operand stack + * (not ideal to have this public, but some listeners might need it for + * skipping the insn, plus we require it for subclass factorization) + */ + public abstract boolean popConditionValue(StackFrame frame); + + public Instruction getTarget() { + if (target == null) { + target = mi.getInstructionAt(targetPosition); + } + return target; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + conditionValue = popConditionValue(frame); + if (conditionValue) { + return getTarget(); + } else { + return getNext(ti); + } + } + + /** + * use this as a delegatee in overridden executes of derived IfInstructions + * (e.g. for symbolic execution) + */ + protected Instruction executeBothBranches (SystemState ss, KernelState ks, ThreadInfo ti){ + if (!ti.isFirstStepInsn()) { + BooleanChoiceGenerator cg = new BooleanChoiceGenerator(ti.getVM().getConfig(), "ifAll"); + if (ss.setNextChoiceGenerator(cg)){ + return this; + + } else { + StackFrame frame = ti.getModifiableTopFrame(); + // some listener did override the CG, fallback to normal operation + conditionValue = popConditionValue(frame); + if (conditionValue) { + return getTarget(); + } else { + return getNext(ti); + } + } + + } else { + BooleanChoiceGenerator cg = ss.getCurrentChoiceGenerator("ifAll", BooleanChoiceGenerator.class); + assert (cg != null) : "no BooleanChoiceGenerator"; + + StackFrame frame = ti.getModifiableTopFrame(); + popConditionValue(frame); // we are not interested in concrete values + + conditionValue = cg.getNextChoice(); + + if (conditionValue) { + return getTarget(); + } else { + return getNext(ti); + } + + } + } + + @Override + public String toString () { + return getMnemonic() + " " + targetPosition; + } + + @Override + public int getLength() { + return 3; // usually opcode, bb1, bb2 + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction typeSafeClone(MethodInfo mi) { + IfInstruction clone = null; + + try { + clone = (IfInstruction) super.clone(); + + // reset the method that this insn belongs to + clone.mi = mi; + + clone.target = null; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return clone; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/InstanceInvocation.java b/src/main/gov/nasa/jpf/jvm/bytecode/InstanceInvocation.java new file mode 100644 index 0000000..6b80869 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/InstanceInvocation.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; +import gov.nasa.jpf.vm.bytecode.InstanceInvokeInstruction; + +/** + * base class for INVOKEVIRTUAL, INVOKESPECIAL and INVOLEINTERFACE + */ +public abstract class InstanceInvocation extends JVMInvokeInstruction implements InstanceInvokeInstruction { + + protected InstanceInvocation() {} + + protected InstanceInvocation (String clsDescriptor, String methodName, String signature){ + super(clsDescriptor, methodName, signature); + } + + @Override + public int getArgSize () { + if (argSize < 0) { + argSize = Types.getArgumentsSize(signature) + 1; // 'this' + } + + return argSize; + } + + @Override + public int getCalleeThis (ThreadInfo ti) { + if (!ti.isPostExec()){ + // we have to dig out the 'this' reference from the callers stack + return ti.getCalleeThis( getArgSize()); + } else { + // enter() cached it + return lastObj; + } + } + + @Override + public int getObjectSlot (StackFrame frame){ + int top = frame.getTopPos(); + int argSize = getArgSize(); + + if (argSize == 1){ // object ref is on top + return top; + + } else { + return top - argSize -1; + } + } + + public ElementInfo getThisElementInfo (ThreadInfo ti) { + int thisRef = getCalleeThis(ti); + if (thisRef != MJIEnv.NULL) { + return ti.getElementInfo(thisRef); + } else { + return null; + } + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/InstructionFactory.java b/src/main/gov/nasa/jpf/jvm/bytecode/InstructionFactory.java new file mode 100644 index 0000000..3ede848 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/InstructionFactory.java @@ -0,0 +1,1120 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.JPFException; +import gov.nasa.jpf.jvm.JVMInstructionFactory; +import gov.nasa.jpf.util.Invocation; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.NativeMethodInfo; + +import java.util.List; + +/** + * this is the new JVMInstructionFactory + */ +public class InstructionFactory extends JVMInstructionFactory { + + public InstructionFactory(){ + // nothing here + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException cnsx){ + throw new JPFException("InstructionFactory " + this.getClass().getName() + " does not support cloning"); + } + } + + //--- the factory methods + @Override + public Instruction aconst_null() { + return new ACONST_NULL(); + } + + @Override + public Instruction aload(int localVarIndex) { + return new ALOAD(localVarIndex); + } + + @Override + public Instruction aload_0() { + return new ALOAD(0); + } + + @Override + public Instruction aload_1() { + return new ALOAD(1); + } + + @Override + public Instruction aload_2() { + return new ALOAD(2); + } + + @Override + public Instruction aload_3() { + return new ALOAD(3); + } + + @Override + public Instruction aaload() { + return new AALOAD(); + } + + @Override + public Instruction astore(int localVarIndex) { + return new ASTORE(localVarIndex); + } + + @Override + public Instruction astore_0() { + return new ASTORE(0); + } + + @Override + public Instruction astore_1() { + return new ASTORE(1); + } + + @Override + public Instruction astore_2() { + return new ASTORE(2); + } + + @Override + public Instruction astore_3() { + return new ASTORE(3); + } + + @Override + public Instruction aastore() { + return new AASTORE(); + } + + @Override + public Instruction areturn() { + return new ARETURN(); + } + + @Override + public Instruction anewarray(String clsName){ + return new ANEWARRAY(clsName); + } + + @Override + public Instruction arraylength() { + return new ARRAYLENGTH(); + } + + @Override + public Instruction athrow() { + return new ATHROW(); + } + + @Override + public Instruction baload() { + return new BALOAD(); + } + + @Override + public Instruction bastore() { + return new BASTORE(); + } + + @Override + public Instruction bipush(int b) { + return new BIPUSH(b); + } + + @Override + public Instruction caload() { + return new CALOAD(); + } + + @Override + public Instruction castore() { + return new CASTORE(); + } + + @Override + public Instruction checkcast(String clsName){ + return new CHECKCAST(clsName); + } + + @Override + public Instruction d2f() { + return new D2F(); + } + + @Override + public Instruction d2i() { + return new D2I(); + } + + @Override + public Instruction d2l() { + return new D2L(); + } + + @Override + public Instruction dadd() { + return new DADD(); + } + + @Override + public Instruction daload() { + return new DALOAD(); + } + + @Override + public Instruction dastore() { + return new DASTORE(); + } + + @Override + public Instruction dcmpg() { + return new DCMPG(); + } + + @Override + public Instruction dcmpl() { + return new DCMPL(); + } + + @Override + public Instruction dconst_0() { + return new DCONST(0.0); + } + + @Override + public Instruction dconst_1() { + return new DCONST(1.0); + } + + @Override + public Instruction ddiv() { + return new DDIV(); + } + + @Override + public Instruction dload(int localVarIndex) { + return new DLOAD(localVarIndex); + } + + @Override + public Instruction dload_0() { + return new DLOAD(0); + } + + @Override + public Instruction dload_1() { + return new DLOAD(1); + } + + @Override + public Instruction dload_2() { + return new DLOAD(2); + } + + @Override + public Instruction dload_3() { + return new DLOAD(3); + } + + @Override + public Instruction dmul() { + return new DMUL(); + } + + @Override + public Instruction dneg() { + return new DNEG(); + } + + @Override + public Instruction drem() { + return new DREM(); + } + + @Override + public Instruction dreturn() { + return new DRETURN(); + } + + @Override + public Instruction dstore(int localVarIndex) { + return new DSTORE(localVarIndex); + } + + @Override + public Instruction dstore_0() { + return new DSTORE(0); + } + + @Override + public Instruction dstore_1() { + return new DSTORE(1); + } + + @Override + public Instruction dstore_2() { + return new DSTORE(2); + } + + @Override + public Instruction dstore_3() { + return new DSTORE(3); + } + + @Override + public Instruction dsub() { + return new DSUB(); + } + + @Override + public Instruction dup() { + return new DUP(); + } + + @Override + public Instruction dup_x1() { + return new DUP_X1(); + } + + @Override + public Instruction dup_x2() { + return new DUP_X2(); + } + + @Override + public Instruction dup2() { + return new DUP2(); + } + + @Override + public Instruction dup2_x1() { + return new DUP2_X1(); + } + + @Override + public Instruction dup2_x2() { + return new DUP2_X2(); + } + + @Override + public Instruction f2d() { + return new F2D(); + } + + @Override + public Instruction f2i() { + return new F2I(); + } + + @Override + public Instruction f2l() { + return new F2L(); + } + + @Override + public Instruction fadd() { + return new FADD(); + } + + @Override + public Instruction faload() { + return new FALOAD(); + } + + @Override + public Instruction fastore() { + return new FASTORE(); + } + + @Override + public Instruction fcmpg() { + return new FCMPG(); + } + + @Override + public Instruction fcmpl() { + return new FCMPL(); + } + + @Override + public Instruction fconst_0() { + return new FCONST(0.0f); + } + + @Override + public Instruction fconst_1() { + return new FCONST(1.0f); + } + + @Override + public Instruction fconst_2() { + return new FCONST(2.0f); + } + + @Override + public Instruction fdiv() { + return new FDIV(); + } + + @Override + public Instruction fload(int localVarIndex) { + return new FLOAD(localVarIndex); + } + + @Override + public Instruction fload_0() { + return new FLOAD(0); + } + + @Override + public Instruction fload_1() { + return new FLOAD(1); + } + + @Override + public Instruction fload_2() { + return new FLOAD(2); + } + + @Override + public Instruction fload_3() { + return new FLOAD(3); + } + + @Override + public Instruction fmul() { + return new FMUL(); + } + + @Override + public Instruction fneg() { + return new FNEG(); + } + + @Override + public Instruction frem() { + return new FREM(); + } + + @Override + public Instruction freturn() { + return new FRETURN(); + } + + @Override + public Instruction fstore(int localVarIndex) { + return new FSTORE(localVarIndex); + } + + @Override + public Instruction fstore_0() { + return new FSTORE(0); + } + + @Override + public Instruction fstore_1() { + return new FSTORE(1); + } + + @Override + public Instruction fstore_2() { + return new FSTORE(2); + } + + @Override + public Instruction fstore_3() { + return new FSTORE(3); + } + + @Override + public Instruction fsub() { + return new FSUB(); + } + + @Override + public Instruction getfield(String fieldName, String clsName, String fieldDescriptor){ + return new GETFIELD(fieldName, clsName, fieldDescriptor); + } + + @Override + public Instruction getstatic(String fieldName, String clsName, String fieldDescriptor){ + return new GETSTATIC(fieldName, clsName, fieldDescriptor); + } + + + @Override + public Instruction goto_(int targetPc) { + return new GOTO(targetPc); + } + + @Override + public Instruction goto_w(int targetPc) { + return new GOTO_W(targetPc); + } + + @Override + public Instruction i2b() { + return new I2B(); + } + + @Override + public Instruction i2c() { + return new I2C(); + } + + @Override + public Instruction i2d() { + return new I2D(); + } + + @Override + public Instruction i2f() { + return new I2F(); + } + + @Override + public Instruction i2l() { + return new I2L(); + } + + @Override + public Instruction i2s() { + return new I2S(); + } + + @Override + public Instruction iadd() { + return new IADD(); + } + + @Override + public Instruction iaload() { + return new IALOAD(); + } + + @Override + public Instruction iand() { + return new IAND(); + } + + @Override + public Instruction iastore() { + return new IASTORE(); + } + + @Override + public Instruction iconst_m1() { + return new ICONST(-1); + } + + @Override + public Instruction iconst_0() { + return new ICONST(0); + } + + @Override + public Instruction iconst_1() { + return new ICONST(1); + } + + @Override + public Instruction iconst_2() { + return new ICONST(2); + } + + @Override + public Instruction iconst_3() { + return new ICONST(3); + } + + @Override + public Instruction iconst_4() { + return new ICONST(4); + } + + @Override + public Instruction iconst_5() { + return new ICONST(5); + } + + @Override + public Instruction idiv() { + return new IDIV(); + } + + @Override + public Instruction if_acmpeq(int targetPc) { + return new IF_ACMPEQ(targetPc); + } + + @Override + public Instruction if_acmpne(int targetPc) { + return new IF_ACMPNE(targetPc); + } + + @Override + public Instruction if_icmpeq(int targetPc) { + return new IF_ICMPEQ(targetPc); + } + + @Override + public Instruction if_icmpne(int targetPc) { + return new IF_ICMPNE(targetPc); + } + + @Override + public Instruction if_icmplt(int targetPc) { + return new IF_ICMPLT(targetPc); + } + + @Override + public Instruction if_icmpge(int targetPc) { + return new IF_ICMPGE(targetPc); + } + + @Override + public Instruction if_icmpgt(int targetPc) { + return new IF_ICMPGT(targetPc); + } + + @Override + public Instruction if_icmple(int targetPc) { + return new IF_ICMPLE(targetPc); + } + + @Override + public Instruction ifeq(int targetPc) { + return new IFEQ(targetPc); + } + + @Override + public Instruction ifne(int targetPc) { + return new IFNE(targetPc); + } + + @Override + public Instruction iflt(int targetPc) { + return new IFLT(targetPc); + } + + @Override + public Instruction ifge(int targetPc) { + return new IFGE(targetPc); + } + + @Override + public Instruction ifgt(int targetPc) { + return new IFGT(targetPc); + } + + @Override + public Instruction ifle(int targetPc) { + return new IFLE(targetPc); + } + + @Override + public Instruction ifnonnull(int targetPc) { + return new IFNONNULL(targetPc); + } + + @Override + public Instruction ifnull(int targetPc) { + return new IFNULL(targetPc); + } + + @Override + public Instruction iinc(int localVarIndex, int incConstant) { + return new IINC(localVarIndex, incConstant); + } + + @Override + public Instruction iload(int localVarIndex) { + return new ILOAD(localVarIndex); + } + + @Override + public Instruction iload_0() { + return new ILOAD(0); + } + + @Override + public Instruction iload_1() { + return new ILOAD(1); + } + + @Override + public Instruction iload_2() { + return new ILOAD(2); + } + + @Override + public Instruction iload_3() { + return new ILOAD(3); + } + + @Override + public Instruction imul() { + return new IMUL(); + } + + @Override + public Instruction ineg() { + return new INEG(); + } + + @Override + public Instruction instanceof_(String clsName){ + return new INSTANCEOF(clsName); + } + + @Override + public Instruction invokeinterface(String clsName, String methodName, String methodSignature){ + return new INVOKEINTERFACE(clsName, methodName, methodSignature); + } + + @Override + public Instruction invokespecial(String clsName, String methodName, String methodSignature){ + return new INVOKESPECIAL(clsName, methodName, methodSignature); + } + + @Override + public Instruction invokestatic(String clsName, String methodName, String methodSignature){ + return new INVOKESTATIC(clsName, methodName, methodSignature); + } + + @Override + public Instruction invokevirtual(String clsName, String methodName, String methodSignature){ + return new INVOKEVIRTUAL(clsName, methodName, methodSignature); + } + + @Override + public Instruction invokedynamic(int bootstrapIndex, String samMethodName, String functionType){ + return new INVOKEDYNAMIC(bootstrapIndex, samMethodName, functionType); + } + + @Override + public Instruction ior() { + return new IOR(); + } + + @Override + public Instruction irem() { + return new IREM(); + } + + @Override + public Instruction ireturn() { + return new IRETURN(); + } + + @Override + public Instruction ishl() { + return new ISHL(); + } + + @Override + public Instruction ishr() { + return new ISHR(); + } + + @Override + public Instruction istore(int localVarIndex) { + return new ISTORE(localVarIndex); + } + + @Override + public Instruction istore_0() { + return new ISTORE(0); + } + + @Override + public Instruction istore_1() { + return new ISTORE(1); + } + + @Override + public Instruction istore_2() { + return new ISTORE(2); + } + + @Override + public Instruction istore_3() { + return new ISTORE(3); + } + + @Override + public Instruction isub() { + return new ISUB(); + } + + @Override + public Instruction iushr() { + return new IUSHR(); + } + + @Override + public Instruction ixor() { + return new IXOR(); + } + + @Override + public Instruction jsr(int targetPc) { + return new JSR(targetPc); + } + + @Override + public Instruction jsr_w(int targetPc) { + return new JSR_W(targetPc); + } + + @Override + public Instruction l2d() { + return new L2D(); + } + + @Override + public Instruction l2f() { + return new L2F(); + } + + @Override + public Instruction l2i() { + return new L2I(); + } + + @Override + public Instruction ladd() { + return new LADD(); + } + + @Override + public Instruction laload() { + return new LALOAD(); + } + + @Override + public Instruction land() { + return new LAND(); + } + + @Override + public Instruction lastore() { + return new LASTORE(); + } + + @Override + public Instruction lcmp() { + return new LCMP(); + } + + @Override + public Instruction lconst_0() { + return new LCONST(0); + } + + @Override + public Instruction lconst_1() { + return new LCONST(1L); + } + + @Override + public Instruction ldc(int v){ + return new LDC(v); + } + @Override + public Instruction ldc(float v){ + return new LDC(v); + } + @Override + public Instruction ldc(String v, boolean isClass){ + return new LDC(v, isClass); + } + + + @Override + public Instruction ldc_w(int v){ + return new LDC_W(v); + } + @Override + public Instruction ldc_w(float v){ + return new LDC_W(v); + } + @Override + public Instruction ldc_w(String v, boolean isClass){ + return new LDC_W(v, isClass); + } + + @Override + public Instruction ldc2_w(long v){ + return new LDC2_W(v); + } + @Override + public Instruction ldc2_w(double v){ + return new LDC2_W(v); + } + + @Override + public Instruction ldiv() { + return new LDIV(); + } + + @Override + public Instruction lload(int localVarIndex) { + return new LLOAD(localVarIndex); + } + + @Override + public Instruction lload_0() { + return new LLOAD(0); + } + + @Override + public Instruction lload_1() { + return new LLOAD(1); + } + + @Override + public Instruction lload_2() { + return new LLOAD(2); + } + + @Override + public Instruction lload_3() { + return new LLOAD(3); + } + + @Override + public Instruction lmul() { + return new LMUL(); + } + + @Override + public Instruction lneg() { + return new LNEG(); + } + + @Override + public Instruction lookupswitch(int defaultTargetPc, int nEntries) { + return new LOOKUPSWITCH(defaultTargetPc, nEntries); + } + + @Override + public Instruction lor() { + return new LOR(); + } + + @Override + public Instruction lrem() { + return new LREM(); + } + + @Override + public Instruction lreturn() { + return new LRETURN(); + } + + @Override + public Instruction lshl() { + return new LSHL(); + } + + @Override + public Instruction lshr() { + return new LSHR(); + } + + @Override + public Instruction lstore(int localVarIndex) { + return new LSTORE(localVarIndex); + } + + @Override + public Instruction lstore_0() { + return new LSTORE(0); + } + + @Override + public Instruction lstore_1() { + return new LSTORE(1); + } + + @Override + public Instruction lstore_2() { + return new LSTORE(2); + } + + @Override + public Instruction lstore_3() { + return new LSTORE(3); + } + + @Override + public Instruction lsub() { + return new LSUB(); + } + + @Override + public Instruction lushr() { + return new LUSHR(); + } + + @Override + public Instruction lxor() { + return new LXOR(); + } + + @Override + public Instruction monitorenter() { + return new MONITORENTER(); + } + + @Override + public Instruction monitorexit() { + return new MONITOREXIT(); + } + + @Override + public Instruction multianewarray(String clsName, int dimensions){ + return new MULTIANEWARRAY(clsName, dimensions); + } + + @Override + public Instruction new_(String clsName) { + return new NEW(clsName); + } + + @Override + public Instruction newarray(int typeCode) { + return new NEWARRAY(typeCode); + } + + @Override + public Instruction nop() { + return new NOP(); + } + + @Override + public Instruction pop() { + return new POP(); + } + + @Override + public Instruction pop2() { + return new POP2(); + } + + @Override + public Instruction putfield(String fieldName, String clsName, String fieldDescriptor){ + return new PUTFIELD(fieldName, clsName, fieldDescriptor); + } + + @Override + public Instruction putstatic(String fieldName, String clsName, String fieldDescriptor){ + return new PUTSTATIC(fieldName, clsName, fieldDescriptor); + } + + @Override + public Instruction ret(int localVarIndex) { + return new RET(localVarIndex); + } + + @Override + public Instruction return_() { + return new RETURN(); + } + + @Override + public Instruction saload() { + return new SALOAD(); + } + + @Override + public Instruction sastore() { + return new SASTORE(); + } + + @Override + public Instruction sipush(int val) { + return new SIPUSH(val); + } + + @Override + public Instruction swap() { + return new SWAP(); + } + + @Override + public Instruction tableswitch(int defaultTargetPc, int low, int high) { + return new TABLESWITCH(defaultTargetPc, low, high); + } + + @Override + public Instruction wide() { + return new WIDE(); + } + + + //--- the JPF specific ones (only used in synthetic methods) + @Override + public Instruction invokecg(List invokes) { + return new INVOKECG(invokes); + } + + @Override + public Instruction invokeclinit(ClassInfo ci) { + return new INVOKECLINIT(ci); + } + + @Override + public Instruction directcallreturn(){ + return new DIRECTCALLRETURN(); + } + + @Override + public Instruction executenative(NativeMethodInfo mi){ + return new EXECUTENATIVE(mi); + } + + @Override + public Instruction nativereturn(){ + return new NATIVERETURN(); + } + + // this is never part of MethodInfo stored code + @Override + public Instruction runstart(MethodInfo miRun){ + return new RUNSTART(); + } + + @Override + public Instruction finishclinit(ClassInfo ci) { + return new FINISHCLINIT(ci); + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JSR.java b/src/main/gov/nasa/jpf/jvm/bytecode/JSR.java new file mode 100644 index 0000000..8649b65 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JSR.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Jump subroutine + * ... => ..., address + */ +public class JSR extends Instruction implements JVMInstruction { + private int target; + + public JSR(int targetPc){ + target = targetPc; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int tgtAdr = getNext(ti).getPosition(); + + frame.push( tgtAdr); + + return mi.getInstructionAt(target); + } + + @Override + public int getLength() { + return 3; // opcode, bb1, bb2 + } + + @Override + public int getByteCode () { + return 0xA8; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getTarget() { + return target; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JSR_W.java b/src/main/gov/nasa/jpf/jvm/bytecode/JSR_W.java new file mode 100644 index 0000000..b0d2052 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JSR_W.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Jump subroutine (wide insnIndex) + * ... => ..., address + */ +public class JSR_W extends Instruction implements JVMInstruction { + protected int target; + + public JSR_W(int targetPc){ + target = targetPc; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int tgtAdr = getNext(ti).getPosition(); + + frame.push(tgtAdr); + + return mi.getInstructionAt(target); + } + + @Override + public int getLength() { + return 5; // opcode, bb1, bb2, bb3, bb4 + } + + @Override + public int getByteCode () { + return 0xC9; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getTarget() { + return target; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMArrayElementInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMArrayElementInstruction.java new file mode 100644 index 0000000..0dee592 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMArrayElementInstruction.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.ArrayElementInstruction; + +/** + * abstract class for operations that access elements of arrays + */ +public abstract class JVMArrayElementInstruction extends ArrayElementInstruction { + + protected int arrayRef; + protected int index; // the accessed element + + // we cache these to avoid the need for executeInstruction() listening + // if attrs are processed in instructionExecuted() + protected Object arrayOperandAttr; + protected Object indexOperandAttr; + + // we need this to be abstract because of the LongArrayStore insns + @Override + abstract public int peekIndex (ThreadInfo ti); + abstract public int peekArrayRef (ThreadInfo ti); + + abstract public Object peekIndexAttr (ThreadInfo ti); + abstract public Object peekArrayAttr (ThreadInfo ti); + + public boolean isReferenceArray() { + return false; + } + + @Override + public ElementInfo getElementInfo (ThreadInfo ti){ + if (isCompleted(ti)){ + return ti.getElementInfo(arrayRef); + } else { + int ref = peekArrayRef(ti); + return ti.getElementInfo(arrayRef); + } + } + + /** + * only makes sense from an executeInstruction() or instructionExecuted() listener, + * it is undefined outside of insn exec notifications + */ + public int getArrayRef (ThreadInfo ti){ + if (ti.isPreExec()){ + return peekArrayRef(ti); + } else { + return arrayRef; + } + } + + public Object getArrayOperandAttr (ThreadInfo ti){ + if (ti.isPreExec()) { + return peekArrayAttr(ti); + } else { + return arrayOperandAttr; + } + } + + public Object getIndexOperandAttr (ThreadInfo ti){ + if (ti.isPreExec()) { + return peekIndexAttr(ti); + } else { + return indexOperandAttr; + } + } + + + @Override + public ElementInfo peekArrayElementInfo (ThreadInfo ti){ + int aref = getArrayRef(ti); + return ti.getElementInfo(aref); + } + + public int getIndex (ThreadInfo ti){ + if (!isCompleted(ti)){ + return peekIndex(ti); + } else { + return index; + } + } + + /** + * return size of array elements in stack words (long,double: 2, all other: 1) + * e.g. used to determine where the object reference is on the stack + * + * should probably be abstract, but there are lots of subclasses and only LongArrayLoad/Store insns have different size + */ + protected int getElementSize () { + return 1; + } + + @Override + public abstract boolean isRead(); + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMFieldInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMFieldInstruction.java new file mode 100644 index 0000000..a9dfcc2 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMFieldInstruction.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.ElementInfo; + +/** + * common type for all GET/PUT insns + */ +public interface JVMFieldInstruction extends JVMInstruction { + + FieldInfo getFieldInfo(); + + long getLastValue(); + + String getFieldName(); + + boolean isReferenceField(); + + ElementInfo peekElementInfo (ThreadInfo ti); +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstanceFieldInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstanceFieldInstruction.java new file mode 100644 index 0000000..0830e0e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstanceFieldInstruction.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.InstanceFieldInstruction; + +/** + * common super type of GETFIELD, PUTFIELD + */ +public abstract class JVMInstanceFieldInstruction extends InstanceFieldInstruction implements JVMFieldInstruction { + + protected JVMInstanceFieldInstruction (String fieldName, String classType, String fieldDescriptor){ + super(fieldName, classType, fieldDescriptor); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} + diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstruction.java new file mode 100644 index 0000000..5412010 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstruction.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.InstructionInterface; + +/** + * common type for all JVM instructions + * + * this can't be a abstract class since this would not allow us to + * have machine independent instruction types + */ +public interface JVMInstruction extends InstructionInterface { + + public void accept(JVMInstructionVisitor insVisitor); +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitor.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitor.java new file mode 100644 index 0000000..d5305b0 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitor.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; + +public interface JVMInstructionVisitor { + + public void visit(Instruction ins); + public void visit(AALOAD ins); + public void visit(AASTORE ins); + public void visit(ACONST_NULL ins); + public void visit(ALOAD ins); + public void visit(ANEWARRAY ins); + public void visit(ARETURN ins); + public void visit(JVMArrayElementInstruction ins); + public void visit(ARRAYLENGTH ins); + public void visit(ArrayLoadInstruction ins); + public void visit(ArrayStoreInstruction ins); + public void visit(ASTORE ins); + public void visit(ATHROW ins); + public void visit(BALOAD ins); + public void visit(BASTORE ins); + public void visit(BIPUSH ins); + public void visit(CALOAD ins); + public void visit(CASTORE ins); + public void visit(CHECKCAST ins); + public void visit(D2F ins); + public void visit(D2I ins); + public void visit(D2L ins); + public void visit(DADD ins); + public void visit(DALOAD ins); + public void visit(DASTORE ins); + public void visit(DCMPG ins); + public void visit(DCMPL ins); + public void visit(DCONST ins); + public void visit(DDIV ins); + public void visit(DIRECTCALLRETURN ins); + public void visit(DLOAD ins); + public void visit(DMUL ins); + public void visit(DNEG ins); + public void visit(DREM ins); + public void visit(DRETURN ins); + public void visit(DSTORE ins); + public void visit(DSUB ins); + public void visit(DUP_X1 ins); + public void visit(DUP_X2 ins); + public void visit(DUP ins); + public void visit(DUP2_X1 ins); + public void visit(DUP2_X2 ins); + public void visit(DUP2 ins); + public void visit(EXECUTENATIVE ins); + public void visit(F2D ins); + public void visit(F2I ins); + public void visit(FADD ins); + public void visit(FALOAD ins); + public void visit(FASTORE ins); + public void visit(FCMPL ins); + public void visit(FCONST ins); + public void visit(FDIV ins); + public void visit(JVMFieldInstruction ins); + public void visit(FLOAD ins); + public void visit(FMUL ins); + public void visit(FNEG ins); + public void visit(FREM ins); + public void visit(FRETURN ins); + public void visit(FSTORE ins); + public void visit(FSUB ins); + public void visit(GETFIELD ins); + public void visit(GETSTATIC ins); + public void visit(GOTO_W ins); + public void visit(GOTO ins); + public void visit(I2B ins); + public void visit(I2C ins); + public void visit(I2D ins); + public void visit(I2F ins); + public void visit(I2L ins); + public void visit(I2S ins); + public void visit(IADD ins); + public void visit(IALOAD ins); + public void visit(IAND ins); + public void visit(IASTORE ins); + public void visit(ICONST ins); + public void visit(IDIV ins); + public void visit(IF_ACMPEQ ins); + public void visit(IF_ACMPNE ins); + public void visit(IF_ICMPEQ ins); + public void visit(IF_ICMPGE ins); + public void visit(IF_ICMPGT ins); + public void visit(IF_ICMPLE ins); + public void visit(IF_ICMPLT ins); + public void visit(IF_ICMPNE ins); + public void visit(IFEQ ins); + public void visit(IFGE ins); + public void visit(IFGT ins); + public void visit(IfInstruction ins); + public void visit(IFLE ins); + public void visit(IFLT ins); + public void visit(IFNE ins); + public void visit(IFNONNULL ins); + public void visit(IFNULL ins); + public void visit(IINC ins); + public void visit(ILOAD ins); + public void visit(IMUL ins); + public void visit(INEG ins); + public void visit(JVMInstanceFieldInstruction ins); + public void visit(InstanceInvocation ins); + public void visit(INSTANCEOF ins); + public void visit(INVOKECG ins); + public void visit(INVOKECLINIT ins); + public void visit(JVMInvokeInstruction ins); + public void visit(INVOKEINTERFACE ins); + public void visit(INVOKESPECIAL ins); + public void visit(INVOKESTATIC ins); + public void visit(INVOKEVIRTUAL ins); + public void visit(IOR ins); + public void visit(IREM ins); + public void visit(IRETURN ins); + public void visit(ISHL ins); + public void visit(ISHR ins); + public void visit(ISTORE ins); + public void visit(ISUB ins); + public void visit(IUSHR ins); + public void visit(IXOR ins); + public void visit(JSR_W ins); + public void visit(JSR ins); + public void visit(L2D ins); + public void visit(L2F ins); + public void visit(L2I ins); + public void visit(LADD ins); + public void visit(LALOAD ins); + public void visit(LAND ins); + public void visit(LASTORE ins); + public void visit(LCMP ins); + public void visit(LCONST ins); + public void visit(LDC_W ins); + public void visit(LDC ins); + public void visit(LDC2_W ins); + public void visit(LDIV ins); + public void visit(LLOAD ins); + public void visit(LMUL ins); + public void visit(LNEG ins); + public void visit(JVMLocalVariableInstruction ins); + public void visit(LockInstruction ins); + public void visit(LongArrayLoadInstruction ins); + public void visit(LongArrayStoreInstruction ins); + public void visit(LOOKUPSWITCH ins); + public void visit(LOR ins); + public void visit(LREM ins); + public void visit(LRETURN ins); + public void visit(LSHL ins); + public void visit(LSHR ins); + public void visit(LSTORE ins); + public void visit(LSUB ins); + public void visit(LUSHR ins); + public void visit(LXOR ins); + public void visit(MONITORENTER ins); + public void visit(MONITOREXIT ins); + public void visit(MULTIANEWARRAY ins); + public void visit(NATIVERETURN ins); + public void visit(NEW ins); + public void visit(NEWARRAY ins); + public void visit(NOP ins); + public void visit(POP ins); + public void visit(POP2 ins); + public void visit(PUTFIELD ins); + public void visit(PUTSTATIC ins); + public void visit(RET ins); + public void visit(RETURN ins); + public void visit(JVMReturnInstruction ins); + public void visit(SALOAD ins); + public void visit(SASTORE ins); + public void visit(SIPUSH ins); + public void visit(JVMStaticFieldInstruction ins); + /**public void visit(StoreInstruction ins);**/ // neha: this is just an interface, not implemented + public void visit(SWAP ins); + public void visit(SwitchInstruction ins); + public void visit(TABLESWITCH ins); + /**public void visit(VariableAccessor ins);**/ // neha: this is just an interface, not implemented + public void visit(VirtualInvocation ins); + public void visit(WIDE ins); +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitorAdapter.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitorAdapter.java new file mode 100644 index 0000000..24794a8 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInstructionVisitorAdapter.java @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; + +public abstract class JVMInstructionVisitorAdapter + implements JVMInstructionVisitor { + + @Override public void visit(Instruction ins) {} + + @Override public void visit(AALOAD ins) {} + + @Override public void visit(AASTORE ins) {} + + @Override public void visit(ACONST_NULL ins) {} + + @Override public void visit(ALOAD ins) {} + + @Override public void visit(ANEWARRAY ins) {} + + @Override public void visit(ARETURN ins) {} + + @Override public void visit(JVMArrayElementInstruction ins) {} + + @Override public void visit(ARRAYLENGTH ins) {} + + @Override public void visit(ArrayLoadInstruction ins) {} + + @Override public void visit(ArrayStoreInstruction ins) {} + + @Override public void visit(ASTORE ins) {} + + @Override public void visit(ATHROW ins) {} + + @Override public void visit(BALOAD ins) {} + + @Override public void visit(BASTORE ins) {} + + @Override public void visit(BIPUSH ins) {} + + @Override public void visit(CALOAD ins) {} + + @Override public void visit(CASTORE ins) {} + + @Override public void visit(CHECKCAST ins) {} + + @Override public void visit(D2F ins) {} + + @Override public void visit(D2I ins) {} + + @Override public void visit(D2L ins) {} + + @Override public void visit(DADD ins) {} + + @Override public void visit(DALOAD ins) {} + + @Override public void visit(DASTORE ins) {} + + @Override public void visit(DCMPG ins) {} + + @Override public void visit(DCMPL ins) {} + + @Override public void visit(DCONST ins) {} + + @Override public void visit(DDIV ins) {} + + @Override public void visit(DIRECTCALLRETURN ins) {} + + @Override public void visit(DLOAD ins) {} + + @Override public void visit(DMUL ins) {} + + @Override public void visit(DNEG ins) {} + + @Override public void visit(DREM ins) {} + + @Override public void visit(DRETURN ins) {} + + @Override public void visit(DSTORE ins) {} + + @Override public void visit(DSUB ins) {} + + @Override public void visit(DUP_X1 ins) {} + + @Override public void visit(DUP_X2 ins) {} + + @Override public void visit(DUP ins) {} + + @Override public void visit(DUP2_X1 ins) {} + + @Override public void visit(DUP2_X2 ins) {} + + @Override public void visit(DUP2 ins) {} + + @Override public void visit(F2D ins) {} + + @Override public void visit(F2I ins) {} + + @Override public void visit(FADD ins) {} + + @Override public void visit(FALOAD ins) {} + + @Override public void visit(FASTORE ins) {} + + @Override public void visit(FCMPL ins) {} + + @Override public void visit(FCONST ins) {} + + @Override public void visit(FDIV ins) {} + + @Override public void visit(JVMFieldInstruction ins) {} + + @Override public void visit(FLOAD ins) {} + + @Override public void visit(FMUL ins) {} + + @Override public void visit(FNEG ins) {} + + @Override public void visit(FREM ins) {} + + @Override public void visit(FRETURN ins) {} + + @Override public void visit(FSTORE ins) {} + + @Override public void visit(FSUB ins) {} + + @Override public void visit(GETFIELD ins) {} + + @Override public void visit(GETSTATIC ins) {} + + @Override public void visit(GOTO_W ins) {} + + @Override public void visit(GOTO ins) {} + + @Override public void visit(I2B ins) {} + + @Override public void visit(I2C ins) {} + + @Override public void visit(I2D ins) {} + + @Override public void visit(I2F ins) {} + + @Override public void visit(I2L ins) {} + + @Override public void visit(I2S ins) {} + + @Override public void visit(IADD ins) {} + + @Override public void visit(IALOAD ins) {} + + @Override public void visit(IAND ins) {} + + @Override public void visit(IASTORE ins) {} + + @Override public void visit(ICONST ins) {} + + @Override public void visit(IDIV ins) {} + + @Override public void visit(IF_ACMPEQ ins) {} + + @Override public void visit(IF_ACMPNE ins) {} + + @Override public void visit(IF_ICMPEQ ins) {} + + @Override public void visit(IF_ICMPGE ins) {} + + @Override public void visit(IF_ICMPGT ins) {} + + @Override public void visit(IF_ICMPLE ins) {} + + @Override public void visit(IF_ICMPLT ins) {} + + @Override public void visit(IF_ICMPNE ins) {} + + @Override public void visit(IFEQ ins) {} + + @Override public void visit(IFGE ins) {} + + @Override public void visit(IFGT ins) {} + + @Override public void visit(IfInstruction ins) {} + + @Override public void visit(IFLE ins) {} + + @Override public void visit(IFLT ins) {} + + @Override public void visit(IFNE ins) {} + + @Override public void visit(IFNONNULL ins) {} + + @Override public void visit(IFNULL ins) {} + + @Override public void visit(IINC ins) {} + + @Override public void visit(ILOAD ins) {} + + @Override public void visit(IMUL ins) {} + + @Override public void visit(INEG ins) {} + + @Override public void visit(JVMInstanceFieldInstruction ins) {} + + @Override public void visit(InstanceInvocation ins){} + + @Override public void visit(INSTANCEOF ins){} + + @Override public void visit(INVOKECG ins){} + + @Override public void visit(INVOKECLINIT ins){} + + @Override public void visit(JVMInvokeInstruction ins){} + + @Override public void visit(INVOKEINTERFACE ins){} + + @Override public void visit(INVOKESPECIAL ins){} + + @Override public void visit(INVOKESTATIC ins){} + + @Override public void visit(INVOKEVIRTUAL ins){} + + @Override public void visit(EXECUTENATIVE ins){} + + @Override public void visit(IOR ins){} + + @Override public void visit(IREM ins){} + + @Override public void visit(IRETURN ins){} + + @Override public void visit(ISHL ins){} + + @Override public void visit(ISHR ins){} + + @Override public void visit(ISTORE ins){} + + @Override public void visit(ISUB ins){} + + @Override public void visit(IUSHR ins){} + + @Override public void visit(IXOR ins){} + + @Override public void visit(JSR_W ins){} + + @Override public void visit(JSR ins){} + + @Override public void visit(L2D ins){} + + @Override public void visit(L2F ins){} + + @Override public void visit(L2I ins){} + + @Override public void visit(LADD ins){} + + @Override public void visit(LALOAD ins){} + + @Override public void visit(LAND ins){} + + @Override public void visit(LASTORE ins){} + + @Override public void visit(LCMP ins){} + + @Override public void visit(LCONST ins){} + + @Override public void visit(LDC_W ins){} + + @Override public void visit(LDC ins){} + + @Override public void visit(LDC2_W ins){} + + @Override public void visit(LDIV ins){} + + @Override public void visit(LLOAD ins){} + + @Override public void visit(LMUL ins){} + + @Override public void visit(LNEG ins){} + + @Override public void visit(JVMLocalVariableInstruction ins){} + + @Override public void visit(LockInstruction ins){} + + @Override public void visit(LongArrayLoadInstruction ins){} + + @Override public void visit(LongArrayStoreInstruction ins){} + + @Override public void visit(LOOKUPSWITCH ins){} + + @Override public void visit(LOR ins){} + + @Override public void visit(LREM ins){} + + @Override public void visit(LRETURN ins){} + + @Override public void visit(LSHL ins){} + + @Override public void visit(LSHR ins){} + + @Override public void visit(LSTORE ins){} + + @Override public void visit(LSUB ins){} + + @Override public void visit(LUSHR ins){} + + @Override public void visit(LXOR ins){} + + @Override public void visit(MONITORENTER ins){} + + @Override public void visit(MONITOREXIT ins){} + + @Override public void visit(MULTIANEWARRAY ins){} + + @Override public void visit(NATIVERETURN ins) {} + + @Override public void visit(NEW ins){} + + @Override public void visit(NEWARRAY ins){} + + @Override public void visit(NOP ins){} + + @Override public void visit(POP ins){} + + @Override public void visit(POP2 ins){} + + @Override public void visit(PUTFIELD ins){} + + @Override public void visit(PUTSTATIC ins){} + + @Override public void visit(RET ins){} + + @Override public void visit(RETURN ins){} + + @Override public void visit(JVMReturnInstruction ins){} + + @Override public void visit(SALOAD ins){} + + @Override public void visit(SASTORE ins){} + + @Override public void visit(SIPUSH ins){} + + @Override public void visit(JVMStaticFieldInstruction ins){} + + @Override public void visit(SWAP ins){} + + @Override public void visit(SwitchInstruction ins){} + + @Override public void visit(TABLESWITCH ins){} + + @Override public void visit(VirtualInvocation ins){} + + @Override public void visit(WIDE ins){} + +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMInvokeInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInvokeInstruction.java new file mode 100644 index 0000000..3dda5a5 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMInvokeInstruction.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LocalVarInfo; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; +import gov.nasa.jpf.vm.bytecode.InvokeInstruction; + + +/** + * abstraction for all invoke instructions + */ +public abstract class JVMInvokeInstruction extends InvokeInstruction implements JVMInstruction { + /* Those are all straight from the class file. + * Note that we can't directly resolve to MethodInfo objects because + * the corresponding class might not be loaded yet (has to be done + * on execution) + */ + protected String cname; + protected String mname; + protected String signature; + + protected int argSize = -1; + + /** to cache the last callee object */ + protected int lastObj = Integer.MIN_VALUE; + + /** + * watch out - this is only const for static and special invocation + * all virtuals will use it only as a cache + */ + protected MethodInfo invokedMethod; + + protected Object[] arguments; // temporary cache for arg values (for listeners) + + protected JVMInvokeInstruction (String clsName, String methodName, String signature){ + this.cname = Types.getClassNameFromTypeName(clsName); + this.signature = signature; + this.mname = MethodInfo.getUniqueName(methodName, signature); + } + + protected JVMInvokeInstruction () {} + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + // only useful from post-exec notifications + public int getLastObjRef() { + return lastObj; + } + + /** + * this is for explicit initialization (not BCEL) + */ + public void setInvokedMethod (String clsName, String mthName, String sig) { + cname = clsName; + mname = mthName + sig; + signature = sig; + } + + /** + * be aware of that this might differ from getInvokedMethod(), since it only + * denotes the target type info we have at the static point of the call, i.e. + * before dynamic dispatching + */ + @Override + public String getInvokedMethodClassName() { + return cname; + } + + @Override + public String getInvokedMethodSignature() { + return signature; + } + + @Override + public String getInvokedMethodName () { + return mname; + } + + public abstract MethodInfo getInvokedMethod (ThreadInfo ti); + + @Override + public MethodInfo getInvokedMethod () { + if (invokedMethod == null){ + invokedMethod = getInvokedMethod(ThreadInfo.getCurrentThread()); + } + + return invokedMethod; + } + + @Override + public boolean isCompleted(ThreadInfo ti) { + Instruction nextPc = ti.getNextPC(); + + if (nextPc == null || nextPc == this){ + return false; + } + + if (invokedMethod != null){ + MethodInfo topMethod = ti.getTopFrame().getMethodInfo(); + if (invokedMethod.isMJI() && (topMethod == mi)) { + // same frame -> this was a native method that already returned + return true; + } + + if (topMethod == invokedMethod){ + return true; + } + } + + // <2do> how do we account for exceptions? + + return false; + } + + StackFrame getCallerFrame (ThreadInfo ti, MethodInfo callee) { + return ti.getStackFrameExecuting(this, 0); + } + + //--- invocation processing + + protected void setupCallee (ThreadInfo ti, MethodInfo callee){ + ClassInfo ciCaller = callee.getClassInfo(); + StackFrame frame = ciCaller.createStackFrame( ti, callee); + + ti.pushFrame(frame); + ti.enter(); + } + + /** + * this is a little helper to find out about call argument values from listeners that + * don't want to dig through MethodInfos and Types. Reference arguments are returned as + * either ElementInfos or 'null', all others are boxed (i.e. a 'double' is returned as + * a 'Double' object). + * It goes without saying that this method can only be called during an executeInstruction() + * or instructionExecuted() notification for the corresponding JVMInvokeInstruction + * We use the caller frame to retrieve the arguments (instead of the locals of + * the callee) since that works for both pre- and post-exec notification + */ + public Object[] getArgumentValues (ThreadInfo ti) { + MethodInfo callee = getInvokedMethod(ti); + StackFrame frame = getCallerFrame(ti, callee); + + assert frame != null : "can't find caller stackframe for: " + this; + return frame.getCallArguments(ti); + } + + public Object[] getArgumentAttrs (ThreadInfo ti) { + MethodInfo callee = getInvokedMethod(ti); + StackFrame frame = getCallerFrame(ti, callee); + + assert frame != null : "can't find caller stackframe for: " + this; + return frame.getArgumentAttrs(callee); + } + + + /** + * check if there is any argument attr of the specified type + * (use this before using any of the more expensive retrievers) + */ + public boolean hasArgumentAttr (ThreadInfo ti, Class type){ + MethodInfo callee = getInvokedMethod(ti); + StackFrame frame = getCallerFrame(ti, callee); + + assert frame != null : "no caller stackframe for: " + this; + return frame.hasArgumentAttr(callee,type); + } + + /** + * do we have a reference argument that has an object attribute? + * less efficient, but still without object creation + */ + public boolean hasArgumentObjectAttr (ThreadInfo ti, Class type){ + MethodInfo callee = getInvokedMethod(ti); + StackFrame frame = getCallerFrame(ti, callee); + + assert frame != null : "no caller stackframe for: " + this; + return frame.hasArgumentObjectAttr(ti,callee,type); + } + + /** + * this is slot size, i.e. includes 'this' for InstanceInvocations + */ + abstract public int getArgSize(); + + public int getReturnType() { + return Types.getReturnBuiltinType(signature); + } + + public boolean isReferenceReturnType() { + int r = Types.getReturnBuiltinType(signature); + return ((r == Types.T_REFERENCE) || (r == Types.T_ARRAY)); + } + + public String getReturnTypeName() { + return Types.getReturnTypeName(signature); + } + + public Object getFieldOrArgumentValue (String id, ThreadInfo ti){ + Object v = null; + + if ((v = getArgumentValue(id,ti)) == null){ + v = getFieldValue(id, ti); + } + + return v; + } + + public abstract Object getFieldValue (String id, ThreadInfo ti); + + + /** + * <2do> - this relies on same order of arguments and LocalVariableTable entries, which + * seems to hold for javac, but is not required by the VM spec, which only + * says that arguments are stored in consecutive slots starting at 0 + */ + public Object getArgumentValue (String id, ThreadInfo ti){ + MethodInfo mi = getInvokedMethod(); + LocalVarInfo localVars[] = mi.getLocalVars(); + Object[] args = getArgumentValues(ti); + + if (localVars != null){ + int j = mi.isStatic() ? 0 : 1; + + for (int i=0; i type){ + StackFrame frame = ti.getTopFrame(); + return frame.hasOperandAttr(type); + } + + /** + * this returns all of them - use either if you know there will be only + * one attribute at a time, or check/process result with ObjectList + * + * obviously, this only makes sense from an instructionExecuted(), since + * the value is pushed during the enter(). Use ObjectList to access values + */ + public Object getReturnAttr (ThreadInfo ti){ + StackFrame frame = ti.getTopFrame(); + return frame.getOperandAttr(); + } + + /** + * this replaces all of them - use only if you know + * - there will be only one attribute at a time + * - you obtained the value you set by a previous getXAttr() + * - you constructed a multi value list with ObjectList.createList() + * + * we don't clone since pushing a return value already changed the caller frame + */ + public void setReturnAttr (ThreadInfo ti, Object a){ + StackFrame frame = ti.getModifiableTopFrame(); + frame.setOperandAttr(a); + } + + public void addReturnAttr (ThreadInfo ti, Object attr){ + StackFrame frame = ti.getModifiableTopFrame(); + frame.addOperandAttr(attr); + } + + /** + * this only returns the first attr of this type, there can be more + * if you don't use client private types or the provided type is too general + */ + public T getReturnAttr (ThreadInfo ti, Class type){ + StackFrame frame = ti.getTopFrame(); + return frame.getOperandAttr(type); + } + public T getNextReturnAttr (ThreadInfo ti, Class type, Object prev){ + StackFrame frame = ti.getTopFrame(); + return frame.getNextOperandAttr(type, prev); + } + public Iterator returnAttrIterator (ThreadInfo ti){ + StackFrame frame = ti.getTopFrame(); + return frame.operandAttrIterator(); + } + public Iterator returnAttrIterator (ThreadInfo ti, Class type){ + StackFrame frame = ti.getTopFrame(); + return frame.operandAttrIterator(type); + } + + // -- end attribute accessors -- + + @Override + public Instruction execute (ThreadInfo ti) { + boolean didUnblock = false; + + if (!ti.isFirstStepInsn()) { + didUnblock = ti.leave(); // takes care of unlocking before potentially creating a CG + } + + if (mi.isSynchronized()) { + int objref = mi.isStatic() ? mi.getClassInfo().getClassObjectRef() : ti.getThis(); + ElementInfo ei = ti.getElementInfo(objref); + + if (ei.getLockCount() == 0) { + if (ti.getScheduler().setsLockReleaseCG(ti, ei, didUnblock)){ + return this; + } + } + } + + StackFrame frame = ti.getModifiableTopFrame(); + returnFrame = frame; + Object attr = getReturnedOperandAttr(frame); // the return attr - get this before we pop + getAndSaveReturnValue(frame); + + // note that this is never the first frame, since we start all threads (incl. main) + // through a direct call + frame = ti.popAndGetModifiableTopFrame(); + + // remove args, push return value and continue with next insn + // (DirectCallStackFrames don't use this) + frame.removeArguments(mi); + pushReturnValue(frame); + + if (attr != null) { + setReturnAttr(ti, attr); + } + + return frame.getPC().getNext(); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public String toPostExecString() { + return getMnemonic() + " [" + mi.getFullName() + ']'; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/JVMStaticFieldInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/JVMStaticFieldInstruction.java new file mode 100644 index 0000000..60741ed --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/JVMStaticFieldInstruction.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.bytecode.StaticFieldInstruction; + +/** + * common super type of GETSTATIC and PUTSTATIC + */ +public abstract class JVMStaticFieldInstruction extends StaticFieldInstruction implements JVMFieldInstruction { + + protected JVMStaticFieldInstruction(String fieldName, String clsDescriptor, String fieldDescriptor){ + super(fieldName, clsDescriptor, fieldDescriptor); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction typeSafeClone(MethodInfo mi) { + JVMStaticFieldInstruction clone = null; + + try { + clone = (JVMStaticFieldInstruction) super.clone(); + + // reset the method that this insn belongs to + clone.mi = mi; + clone.fi = null; // ClassInfo is going to be different + + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return clone; + } +} + diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/L2D.java b/src/main/gov/nasa/jpf/jvm/bytecode/L2D.java new file mode 100644 index 0000000..720ad2b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/L2D.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert long to double + * ..., value => ..., result + */ +public class L2D extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v = frame.popLong(); + frame.pushDouble( v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x8A; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/L2F.java b/src/main/gov/nasa/jpf/jvm/bytecode/L2F.java new file mode 100644 index 0000000..10b961a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/L2F.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert long to float + * ..., value => ..., result + */ +public class L2F extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v = frame.popLong(); + frame.pushFloat( v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x89; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/L2I.java b/src/main/gov/nasa/jpf/jvm/bytecode/L2I.java new file mode 100644 index 0000000..9c32e9b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/L2I.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Convert long to int + * ..., value => ..., result + */ +public class L2I extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v = frame.popLong(); + frame.push( (int)v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x88; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LADD.java b/src/main/gov/nasa/jpf/jvm/bytecode/LADD.java new file mode 100644 index 0000000..a60adbc --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LADD.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Add long + * ..., value1, value2 => ..., result + */ +public class LADD extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v1 + v2; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x61; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/LALOAD.java new file mode 100644 index 0000000..889d03f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LALOAD.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Load long from array + * ..., arrayref, index => ..., value + */ +public class LALOAD extends LongArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + long value = ei.getLongElement(index); + frame.pushLong( value); + } + + + @Override + public int getByteCode () { + return 0x2F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LAND.java b/src/main/gov/nasa/jpf/jvm/bytecode/LAND.java new file mode 100644 index 0000000..3fa57f9 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LAND.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Boolean AND long + * ..., value1, value2 => ..., result + */ +public class LAND extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v1 & v2; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x7F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/LASTORE.java new file mode 100644 index 0000000..fc6fba6 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LASTORE.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * Store into long array + * ..., arrayref, index, value => ... + */ +public class LASTORE extends LongArrayStoreInstruction { + + long value; + + @Override + protected void popValue(StackFrame frame){ + value = frame.popLong(); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setLongElement(index, value); + } + + + @Override + public int getByteCode () { + return 0x50; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LCMP.java b/src/main/gov/nasa/jpf/jvm/bytecode/LCMP.java new file mode 100644 index 0000000..1fcaea3 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LCMP.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Compare long + * ..., value1, value2 => ..., result + */ +public class LCMP extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + int condVal = conditionValue( v1, v2); + + frame.push(condVal); + + return getNext(ti); + } + + protected int conditionValue(long v1, long v2) { + if (v1 == v2) { + return 0; + } else if (v2 > v1) { + return 1; + } else { + return -1; + } + } + + @Override + public int getByteCode () { + return 0x94; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LCONST.java b/src/main/gov/nasa/jpf/jvm/bytecode/LCONST.java new file mode 100644 index 0000000..1bc982f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LCONST.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push long constant + * ... => ..., + */ +public class LCONST extends Instruction implements JVMInstruction { + protected long value; + + + public LCONST(long value){ + this.value = value; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLong(value); + + return getNext(ti); + } + + @Override + public int getByteCode () { + if (value == 0) { + return 0x09; + } else { + return 0x0a; + } + } + + @Override + public String getMnemonic () { + if (value == 0) { + return "lconst_0"; + } else { + return "lconst_1"; + } + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public long getValue() { + return value; + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LDC.java b/src/main/gov/nasa/jpf/jvm/bytecode/LDC.java new file mode 100644 index 0000000..73d3971 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LDC.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Push item from runtime constant pool + * ... => ..., value + */ +public class LDC extends Instruction implements JVMInstruction { + + public enum Type {STRING, CLASS, INT, FLOAT}; + + Type type; + + protected String string; // the string value if Type.STRING, classname if Type.CLASS + protected int value; + + public LDC() {} + + public LDC (String s, boolean isClass){ + if (isClass){ + string = Types.getClassNameFromTypeName(s); + type = Type.CLASS; + } else { + string = s; + type = Type.STRING; + } + } + + public LDC (int v){ + value = v; + type = Type.INT; + } + + public LDC (float f){ + value = Float.floatToIntBits(f); + type = Type.FLOAT; + } + + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + switch (type){ + case STRING: + // too bad we can't cache it, since location might change between different paths + ElementInfo eiValue = ti.getHeap().newInternString(string, ti); + value = eiValue.getObjectRef(); + frame.pushRef(value); + break; + + case INT: + case FLOAT: + frame.push(value); + break; + + case CLASS: + ClassInfo ci; + // resolve the referenced class + try { + ci = ti.resolveReferencedClass(string); + } catch(LoadOnJPFRequired lre) { + return frame.getPC(); + } + + // LDC doesn't cause a - we only register all required classes + // to make sure we have class objects. s are called prior to + // GET/PUT or INVOKE + if (!ci.isRegistered()) { + ci.registerClass(ti); + } + + frame.pushRef( ci.getClassObjectRef()); + + break; + } + + return getNext(ti); + } + + @Override + public int getLength() { + return 2; // opcode, index + } + + @Override + public int getByteCode () { + return 0x12; + } + + public int getValue() { + return value; + } + + public Type getType() { + return type; + } + + public boolean isString() { + return (type == Type.STRING); + } + + public float getFloatValue(){ + if(type!=Type.FLOAT){ + throw new IllegalStateException(); + } + + return Float.intBitsToFloat(value); + } + + public String getStringValue() { // if it is a String (not acquired from the class const pool) + if (type == Type.STRING) { + return string; + } else { + return null; + } + } + + public String getClassValue() { // if it is the name of a Class (acquired from the class const pool) + if (type == Type.CLASS) { + return string; + } else { + return null; + } + } + + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LDC2_W.java b/src/main/gov/nasa/jpf/jvm/bytecode/LDC2_W.java new file mode 100644 index 0000000..1a9a37a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LDC2_W.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push long or double from runtime constant pool (wide index) + * ... => ..., value + */ +public class LDC2_W extends Instruction implements JVMInstruction { + + public enum Type {LONG, DOUBLE}; + + protected Type type; + protected long value; + + public LDC2_W(long l){ + value = l; + type = Type.LONG; + } + + public LDC2_W(double d){ + value = Double.doubleToLongBits(d); + type = Type.DOUBLE; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLong(value); + return getNext(ti); + } + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0x14; + } + + public Type getType() { + return type; + } + + public double getDoubleValue(){ + if(type!=Type.DOUBLE){ + throw new IllegalStateException(); + } + + return Double.longBitsToDouble(value); + } + + public long getValue() { + return value; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LDC_W.java b/src/main/gov/nasa/jpf/jvm/bytecode/LDC_W.java new file mode 100644 index 0000000..1ad0a78 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LDC_W.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + +/** + * Push item from runtime constant pool (wide index) + * ... => ..., value + */ +public class LDC_W extends LDC { + + public LDC_W() {} + + public LDC_W (String s, boolean isClass){ + super(s,isClass); + } + + public LDC_W (int v){ + super(v); + } + + public LDC_W (float f){ + super(f); + } + + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0x13; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LDIV.java b/src/main/gov/nasa/jpf/jvm/bytecode/LDIV.java new file mode 100644 index 0000000..e21a035 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LDIV.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Divide long + * ..., value1, value2 => ..., result + */ +public class LDIV extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + if (v1 == 0) { + return ti.createAndThrowException("java.lang.ArithmeticException", "long division by zero"); + } + + long r = v2 / v1; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x6D; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LLOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/LLOAD.java new file mode 100644 index 0000000..8d9ec48 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LLOAD.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Load long from local variable + * ... => ..., value + */ +public class LLOAD extends JVMLocalVariableInstruction { + + public LLOAD(int localVarIndex){ + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pushLongLocal(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x1e; + case 1: return 0x1f; + case 2: return 0x20; + case 3: return 0x21; + } + + return 0x16; // ?? wide + } + + @Override + public String getBaseMnemonic() { + return "lload"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LMUL.java b/src/main/gov/nasa/jpf/jvm/bytecode/LMUL.java new file mode 100644 index 0000000..b80643e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LMUL.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Multiply long + * ..., value1, value2 => ..., result + */ +public class LMUL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v1 * v2; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x69; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LNEG.java b/src/main/gov/nasa/jpf/jvm/bytecode/LNEG.java new file mode 100644 index 0000000..d12a2d5 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LNEG.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Negate long + * ..., value => ..., result + */ +public class LNEG extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v = frame.popLong(); + frame.pushLong(-v); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x75; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LOOKUPSWITCH.java b/src/main/gov/nasa/jpf/jvm/bytecode/LOOKUPSWITCH.java new file mode 100644 index 0000000..18d1894 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LOOKUPSWITCH.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + + +/** + * Access jump table by key match and jump + * ..., key => ... + */ +public class LOOKUPSWITCH extends SwitchInstruction implements gov.nasa.jpf.vm.bytecode.LookupSwitchInstruction { + + public LOOKUPSWITCH (int defaultTarget, int numberOfTargets) { + super(defaultTarget, numberOfTargets); + } + + @Override + public void setTarget (int index, int match, int target){ + targets[index] = target; + matches[index] = match; + } + + + @Override + public int getLength() { + return 10 + 2*(matches.length); // <2do> NOT RIGHT: padding!! + } + + @Override + public int getByteCode () { + return 0xAB; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LOR.java b/src/main/gov/nasa/jpf/jvm/bytecode/LOR.java new file mode 100644 index 0000000..1f99d96 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LOR.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Boolean OR long + * ..., value1, value2 => ..., result + */ +public class LOR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v1 | v2; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x81; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LREM.java b/src/main/gov/nasa/jpf/jvm/bytecode/LREM.java new file mode 100644 index 0000000..7c64f8b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LREM.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Remainder long + * ..., value1, value2 => ..., result + */ +public class LREM extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v2 % v1; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x71; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LRETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/LRETURN.java new file mode 100644 index 0000000..c41b915 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LRETURN.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Return long from method + * ..., value => [empty] + */ +public class LRETURN extends LongReturn { + + public long getReturnValue () { + return ret; + } + + @Override + public Object getReturnValue(ThreadInfo ti) { + if (!isCompleted(ti)) { // we have to pull it from the operand stack + StackFrame frame = ti.getTopFrame(); + ret = frame.peekLong(); + } + + return new Long(ret); + } + + @Override + public int getByteCode () { + return 0xAD; + } + + @Override + public String toString() { + return "lreturn " + mi.getFullName(); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LSHL.java b/src/main/gov/nasa/jpf/jvm/bytecode/LSHL.java new file mode 100644 index 0000000..3322ce4 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LSHL.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Shift left + * ..., value1, value2 =>..., result + */ +public class LSHL extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + long v2 = frame.popLong(); + + frame.pushLong(v2 << v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x79; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LSHR.java b/src/main/gov/nasa/jpf/jvm/bytecode/LSHR.java new file mode 100644 index 0000000..03c55c9 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LSHR.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Arithmetic shift right long + * ..., value1, value2 =>..., result + */ +public class LSHR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + long v2 = frame.popLong(); + + frame.pushLong(v2 >> v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x7B; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LSTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/LSTORE.java new file mode 100644 index 0000000..7fa122f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LSTORE.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Store long into local variable + * ..., value => ... + */ +public class LSTORE extends JVMLocalVariableInstruction implements StoreInstruction { + + public LSTORE(int localVarIndex){ + super(localVarIndex); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.storeLongOperand(index); + + return getNext(ti); + } + + @Override + public int getLength() { + if (index > 3){ + return 2; // opcode, index + } else { + return 1; + } + } + + @Override + public int getByteCode () { + switch (index) { + case 0: return 0x3f; + case 1: return 0x40; + case 2: return 0x41; + case 3: return 0x42; + } + return 0x37; // ?? wide, LSTORE_n + } + + @Override + public String getBaseMnemonic() { + return "lstore"; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LSUB.java b/src/main/gov/nasa/jpf/jvm/bytecode/LSUB.java new file mode 100644 index 0000000..9990348 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LSUB.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Subtract long + * ..., value1, value2 => ..., result + */ +public class LSUB extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v2 - v1; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x65; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LUSHR.java b/src/main/gov/nasa/jpf/jvm/bytecode/LUSHR.java new file mode 100644 index 0000000..2ad1797 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LUSHR.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Logical shift right long + * ..., value1, value2 =>..., result + */ +public class LUSHR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + int v1 = frame.pop(); + long v2 = frame.popLong(); + + frame.pushLong(v2 >>> v1); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x7D; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LXOR.java b/src/main/gov/nasa/jpf/jvm/bytecode/LXOR.java new file mode 100644 index 0000000..79514af --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LXOR.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Boolean XOR long + * ..., value1, value2 => ..., result + */ +public class LXOR extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + long v1 = frame.popLong(); + long v2 = frame.popLong(); + + long r = v1 ^ v2; + + frame.pushLong(r); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x83; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LockInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/LockInstruction.java new file mode 100644 index 0000000..9187c8f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LockInstruction.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; + + +/** + * common root for MONITORENTER/EXIT + */ +public abstract class LockInstruction extends Instruction implements JVMInstruction { + int lastLockRef = MJIEnv.NULL; + + /** + * only useful post-execution (in an instructionExecuted() notification) + */ + public int getLastLockRef () { + return lastLockRef; + } + + @Override + public String toPostExecString(){ + StringBuilder sb = new StringBuilder(); + sb.append(getMnemonic()); + sb.append(" @"); + sb.append( Integer.toHexString(lastLockRef)); + + return sb.toString(); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LongArrayLoadInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/LongArrayLoadInstruction.java new file mode 100644 index 0000000..350214b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LongArrayLoadInstruction.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * abstraction for long array loads + */ +public abstract class LongArrayLoadInstruction extends ArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo e, int index) + throws ArrayIndexOutOfBoundsExecutiveException { + e.checkArrayBounds(index); + frame.pushLong(e.getLongElement(index)); + } + + @Override + protected int getElementSize () { + return 2; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LongArrayStoreInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/LongArrayStoreInstruction.java new file mode 100644 index 0000000..a962cfa --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LongArrayStoreInstruction.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * absraction for long array stores + * + * ... array, index, long-value => ... + */ +public abstract class LongArrayStoreInstruction extends ArrayStoreInstruction { + protected void setField (ElementInfo e, int index, long value) + throws ArrayIndexOutOfBoundsExecutiveException { + e.checkArrayBounds(index); + e.setLongElement(index, value); + } + + @Override + protected int getElementSize () { + return 2; + } + + protected long getValue (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + return frame.popLong(); + } + + @Override + public int peekArrayRef(ThreadInfo ti) { + return ti.getTopFrame().peek(3); // ..,ref,idx,long(value) + } + + @Override + public int peekIndex(ThreadInfo ti){ + return ti.getTopFrame().peek(2); + } + + @Override + public Object peekArrayAttr (ThreadInfo ti){ + return ti.getTopFrame().getOperandAttr(3); + } + + @Override + public Object peekIndexAttr (ThreadInfo ti){ + return ti.getTopFrame().getOperandAttr(2); + } + + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/LongReturn.java b/src/main/gov/nasa/jpf/jvm/bytecode/LongReturn.java new file mode 100644 index 0000000..5fe236e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/LongReturn.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.util.Iterator; + +/** + * common base for DRETURN and LRETURN + */ +public abstract class LongReturn extends JVMReturnInstruction { + + protected long ret; + + @Override + public int getReturnTypeSize() { + return 2; + } + + @Override + protected Object getReturnedOperandAttr (StackFrame frame) { + return frame.getLongOperandAttr(); + } + + @Override + protected void getAndSaveReturnValue (StackFrame frame) { + ret = frame.popLong(); + } + + @Override + protected void pushReturnValue (StackFrame frame) { + frame.pushLong(ret); + } + + //--- attribute accessors + + @Override + public boolean hasReturnAttr (ThreadInfo ti){ + StackFrame frame = ti.getTopFrame(); + return frame.hasLongOperandAttr(); + } + @Override + public boolean hasReturnAttr (ThreadInfo ti, Class type){ + StackFrame frame = ti.getTopFrame(); + return frame.hasLongOperandAttr(type); + } + + /** + * this returns all of them - use either if you know there will be only + * one attribute at a time, or check/process result with ObjectList + * + * obviously, this only makes sense from an instructionExecuted(), since + * the value is pushed during the enter(). Use ObjectList to access values + */ + @Override + public Object getReturnAttr (ThreadInfo ti){ + StackFrame frame = ti.getTopFrame(); + return frame.getLongOperandAttr(); + } + + /** + * this replaces all of them - use only if you know + * - there will be only one attribute at a time + * - you obtained the value you set by a previous getXAttr() + * - you constructed a multi value list with ObjectList.createList() + * + * we don't clone since pushing a return value already changed the caller frame + */ + @Override + public void setReturnAttr (ThreadInfo ti, Object a){ + StackFrame frame = ti.getModifiableTopFrame(); + frame.setLongOperandAttr(a); + } + + /** + * this only returns the first attr of this type, there can be more + * if you don't use client private types or the provided type is too general + */ + @Override + public T getReturnAttr (ThreadInfo ti, Class type){ + StackFrame frame = ti.getTopFrame(); + return frame.getLongOperandAttr(type); + } + @Override + public T getNextReturnAttr (ThreadInfo ti, Class type, Object prev){ + StackFrame frame = ti.getTopFrame(); + return frame.getNextLongOperandAttr(type, prev); + } + @Override + public Iterator returnAttrIterator (ThreadInfo ti){ + StackFrame frame = ti.getTopFrame(); + return frame.longOperandAttrIterator(); + } + @Override + public Iterator returnAttrIterator (ThreadInfo ti, Class type){ + StackFrame frame = ti.getTopFrame(); + return frame.longOperandAttrIterator(type); + } + + @Override + public void addReturnAttr (ThreadInfo ti, Object attr){ + StackFrame frame = ti.getModifiableTopFrame(); + frame.addLongOperandAttr(attr); + } + + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/MONITORENTER.java b/src/main/gov/nasa/jpf/jvm/bytecode/MONITORENTER.java new file mode 100644 index 0000000..b365c5e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/MONITORENTER.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.JPFException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Enter monitor for object + * ..., objectref => ... + */ +public class MONITORENTER extends LockInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + Scheduler scheduler = ti.getScheduler(); + StackFrame frame = ti.getTopFrame(); + + int objref = frame.peek(); // Don't pop yet before we know we really enter + if (objref == MJIEnv.NULL){ + return ti.createAndThrowException("java.lang.NullPointerException", "Attempt to acquire lock for null object"); + } + + lastLockRef = objref; + ElementInfo ei = ti.getModifiableElementInfo(objref); + ei = scheduler.updateObjectSharedness(ti, ei, null); // locks most likely belong to shared objects + + if (!ti.isLockOwner(ei)){ // we only need to register, block and/or reschedule if this is not a recursive lock + if (ei.canLock(ti)) { + // record that this thread would lock the object upon next execution if we break the transition + // (note this doesn't re-add if already registered) + ei.registerLockContender(ti); + if (scheduler.setsLockAcquisitionCG(ti, ei)) { // optional scheduling point + return this; + } + + } else { // we need to block + ei.block(ti); // this means we only re-execute once we can acquire the lock + if (scheduler.setsBlockedThreadCG(ti, ei)){ // mandatory scheduling point + return this; + } + throw new JPFException("blocking MONITORENTER without transition break"); + } + } + + //--- bottom half or lock acquisition succeeded without transition break + frame = ti.getModifiableTopFrame(); // now we need to modify it + frame.pop(); + + ei.lock(ti); // mark object as locked, increment the lockCount, and set the thread as owner + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0xC2; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/MONITOREXIT.java b/src/main/gov/nasa/jpf/jvm/bytecode/MONITOREXIT.java new file mode 100644 index 0000000..c6ea604 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/MONITOREXIT.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * Exit monitor for object + * ..., objectref => ... + */ +public class MONITOREXIT extends LockInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + boolean didUnblock = false; + StackFrame frame = ti.getTopFrame(); + Scheduler scheduler = ti.getScheduler(); + + int objref = frame.peek(); + if (objref == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException", "attempt to release lock for null object"); + } + + lastLockRef = objref; + ElementInfo ei = ti.getElementInfo(objref); + ei = scheduler.updateObjectSharedness(ti, ei, null); // locks most likely belong to shared objects + + if (!ti.isFirstStepInsn()){ + ei = ei.getModifiableInstance(); + // we only do this in the top half of the first execution, but before potentially creating + // a CG so that blocked threads are runnable again + didUnblock = ei.unlock(ti); + } + + if (ei.getLockCount() == 0) { // might still be recursively locked, which wouldn't be a release + if (scheduler.setsLockReleaseCG(ti, ei, didUnblock)){ // scheduling point + return this; + } + } + + // bottom half or monitorexit proceeded + frame = ti.getModifiableTopFrame(); + frame.pop(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0xC3; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/MULTIANEWARRAY.java b/src/main/gov/nasa/jpf/jvm/bytecode/MULTIANEWARRAY.java new file mode 100644 index 0000000..fb2c81f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/MULTIANEWARRAY.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Heap; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Create new multidimensional array + * ..., count1, [count2, ...] => ..., arrayref + */ +public class MULTIANEWARRAY extends Instruction implements JVMInstruction { + protected String type; + + protected int dimensions; + protected int[] arrayLengths; + + public MULTIANEWARRAY (String typeName, int dimensions){ + this.type = Types.getClassNameFromTypeName(typeName); + this.dimensions = dimensions; + } + + public static int allocateArray (Heap heap, String type, int[] dim, ThreadInfo ti, int d) { + int l = dim[d]; + ElementInfo eiArray = heap.newArray(type.substring(d + 1), l, ti); + + if (dim.length > (d + 1)) { + for (int i = 0; i < l; i++) { + eiArray.setReferenceElement(i, allocateArray(heap, type, dim, ti, d + 1)); + } + } + + return eiArray.getObjectRef(); + } + + @Override + public Instruction execute (ThreadInfo ti) { + String compType = Types.getComponentTerminal(type); + + // resolve the component class first + if(Types.isReferenceSignature(type)) { + try { + ti.resolveReferencedClass(compType); + } catch(LoadOnJPFRequired lre) { + return ti.getPC(); + } + } + + arrayLengths = new int[dimensions]; + StackFrame frame = ti.getModifiableTopFrame(); + + for (int i = dimensions - 1; i >= 0; i--) { + arrayLengths[i] = frame.pop(); + } + + // there is no clinit for array classes, but we still have to create a class object + // since its a builtin class, we also don't have to bother with NoClassDefFoundErrors + ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(type); + if (!ci.isRegistered()) { + ci.registerClass(ti); + ci.setInitialized(); + } + + int arrayRef = allocateArray(ti.getHeap(), type, arrayLengths, ti, 0); + + // put the result (the array reference) on the stack + frame.pushRef(arrayRef); + + return getNext(ti); + } + + @Override + public int getLength() { + return 4; // opcode, index1, index2, dimensions + } + + @Override + public int getByteCode () { + return 0xC5; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public String getType(){ + return type; + } + + public int getDimensions() { + return dimensions; + } + + public int getArrayLength (int dimension){ + if (dimension < dimensions && arrayLengths != null){ + return arrayLengths[dimension]; + } else { + return -1; + } + } + + @Override + public void cleanupTransients(){ + arrayLengths= null; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/NATIVERETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/NATIVERETURN.java new file mode 100644 index 0000000..95682ef --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/NATIVERETURN.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.NativeStackFrame; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + +/** + * synthetic return instruction for native method invocations, so that + * we don't have to do special provisions to copy the caller args in case + * a post exec listener wants them. + */ +public class NATIVERETURN extends JVMReturnInstruction { + + Object ret; + Object retAttr; + Byte retType; + + // this is more simple than a normal JVMReturnInstruction because NativeMethodInfos + // are not synchronized, and NativeStackFrames are never the first frame in a thread + @Override + public Instruction execute (ThreadInfo ti) { + if (!ti.isFirstStepInsn()) { + ti.leave(); // takes care of unlocking before potentially creating a CG + // NativeMethodInfo is never synchronized, so no thread CG here + } + + StackFrame frame = ti.getModifiableTopFrame(); + getAndSaveReturnValue(frame); + + // NativeStackFrame can never can be the first stack frame, so no thread CG + + frame = ti.popAndGetModifiableTopFrame(); + + // remove args, push return value and continue with next insn + frame.removeArguments(mi); + pushReturnValue(frame); + + if (retAttr != null) { + setReturnAttr(ti, retAttr); + } + + if (mi.isClinit()) { + // this is in the clinit RETURN insn for non-MJIs so we have to duplicate here + // Duplication could be avoided in DIRECTCALLRETURN, but there is no reliable + // way to check if the direct call did return from a clinit since the corresponding + // synthetic method could do anything + mi.getClassInfo().setInitialized(); + } + + return frame.getPC().getNext(); + } + + @Override + public void cleanupTransients(){ + ret = null; + retAttr = null; + returnFrame = null; + } + + @Override + public boolean isExtendedInstruction() { + return true; + } + + public static final int OPCODE = 260; + + @Override + public int getByteCode () { + return OPCODE; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + protected void getAndSaveReturnValue (StackFrame frame) { + // it's got to be a NativeStackFrame since this insn is created by JPF + NativeStackFrame nativeFrame = (NativeStackFrame)frame; + + returnFrame = nativeFrame; + + ret = nativeFrame.getReturnValue(); + retAttr = nativeFrame.getReturnAttr(); + retType = nativeFrame.getMethodInfo().getReturnTypeCode(); + } + + @Override + public int getReturnTypeSize() { + switch (retType) { + case Types.T_BOOLEAN: + case Types.T_BYTE: + case Types.T_CHAR: + case Types.T_SHORT: + case Types.T_INT: + case Types.T_FLOAT: + return 1; + + case Types.T_LONG: + case Types.T_DOUBLE: + return 2; + + default: + return 1; + } + } + + // this is only called internally right before we return + @Override + protected Object getReturnedOperandAttr (StackFrame frame) { + return retAttr; + } + + // <2do> this should use the getResult..() methods of NativeStackFrame + + @Override + protected void pushReturnValue (StackFrame fr) { + int ival; + long lval; + int retSize = 1; + + // in case of a return type mismatch, we get a ClassCastException, which + // is handled in executeMethod() and reported as a InvocationTargetException + // (not completely accurate, but we rather go with safety) + if (ret != null) { + switch (retType) { + case Types.T_BOOLEAN: + ival = Types.booleanToInt(((Boolean) ret).booleanValue()); + fr.push(ival); + break; + + case Types.T_BYTE: + fr.push(((Byte) ret).byteValue()); + break; + + case Types.T_CHAR: + fr.push(((Character) ret).charValue()); + break; + + case Types.T_SHORT: + fr.push(((Short) ret).shortValue()); + break; + + case Types.T_INT: + fr.push(((Integer) ret).intValue()); + break; + + case Types.T_LONG: + fr.pushLong(((Long)ret).longValue()); + retSize=2; + break; + + case Types.T_FLOAT: + ival = Types.floatToInt(((Float) ret).floatValue()); + fr.push(ival); + break; + + case Types.T_DOUBLE: + lval = Types.doubleToLong(((Double) ret).doubleValue()); + fr.pushLong(lval); + retSize=2; + break; + + default: + // everything else is supposed to be a reference + fr.push(((Integer) ret).intValue(), true); + } + + if (retAttr != null) { + if (retSize == 1) { + fr.setOperandAttr(retAttr); + } else { + fr.setLongOperandAttr(retAttr); + } + } + } + } + + @Override + public Object getReturnAttr (ThreadInfo ti) { + if (isCompleted(ti)){ + return retAttr; + } else { + NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame(); + return nativeFrame.getReturnAttr(); + } + } + + + @Override + public Object getReturnValue(ThreadInfo ti) { + if (isCompleted(ti)){ + return ret; + } else { + NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame(); + return nativeFrame.getReturnValue(); + } + } + + @Override + public String toString(){ + StringBuilder sb = new StringBuilder(); + sb.append("nativereturn "); + sb.append(mi.getFullName()); + + return sb.toString(); + } + +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/NEW.java b/src/main/gov/nasa/jpf/jvm/bytecode/NEW.java new file mode 100644 index 0000000..482c21a --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/NEW.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.NewInstruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Heap; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Create new object + * ... => ..., objectref + */ +public class NEW extends NewInstruction implements JVMInstruction { + protected String cname; + protected int newObjRef = MJIEnv.NULL; + + public NEW (String clsDescriptor){ + cname = Types.getClassNameFromTypeName(clsDescriptor); + } + + public String getClassName(){ // Needed for Java Race Finder + return(cname); + } + + @Override + public Instruction execute (ThreadInfo ti) { + Heap heap = ti.getHeap(); + ClassInfo ci; + + // resolve the referenced class + try { + ci = ti.resolveReferencedClass(cname); + } catch(LoadOnJPFRequired lre) { + return ti.getPC(); + } + + if (ci.initializeClass(ti)){ + // continue with the topframe and re-exec this insn once the clinits are done + return ti.getPC(); + } + + if (heap.isOutOfMemory()) { // simulate OutOfMemoryError + return ti.createAndThrowException("java.lang.OutOfMemoryError", + "trying to allocate new " + cname); + } + + ElementInfo ei = heap.newObject(ci, ti); + int objRef = ei.getObjectRef(); + newObjRef = objRef; + + // pushes the return value onto the stack + StackFrame frame = ti.getModifiableTopFrame(); + frame.pushRef( objRef); + + return getNext(ti); + } + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xBB; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getNewObjectRef() { + return newObjRef; + } + + @Override + public String toString() { + if (newObjRef != MJIEnv.NULL){ + return "new " + cname + '@' + Integer.toHexString(newObjRef); + + } else { + return "new " + cname; + } + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/NEWARRAY.java b/src/main/gov/nasa/jpf/jvm/bytecode/NEWARRAY.java new file mode 100644 index 0000000..0152d2b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/NEWARRAY.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Heap; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + + +/** + * Create new array + * ..., count => ..., arrayref + */ +public class NEWARRAY extends NewArrayInstruction { + + public NEWARRAY(int typeCode) { + type = Types.getElementDescriptorOfType(typeCode); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + arrayLength = frame.pop(); + Heap heap = ti.getHeap(); + + if (arrayLength < 0){ + return ti.createAndThrowException("java.lang.NegativeArraySizeException"); + } + + // there is no clinit for array classes, but we still have to create a class object + // since its a builtin class, we also don't have to bother with NoClassDefFoundErrors + String clsName = "[" + type; + ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); + + if (!ci.isRegistered()) { + ci.registerClass(ti); + ci.setInitialized(); + } + + if (heap.isOutOfMemory()) { // simulate OutOfMemoryError + return ti.createAndThrowException("java.lang.OutOfMemoryError", + "trying to allocate new " + + getTypeName() + + "[" + arrayLength + "]"); + } + + ElementInfo eiArray = heap.newArray(type, arrayLength, ti); + int arrayRef = eiArray.getObjectRef(); + + frame.pushRef(arrayRef); + + return getNext(ti); + } + + @Override + public int getLength() { + return 2; // opcode, atype + } + + @Override + public int getByteCode () { + return 0xBC; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("newarray "); + sb.append(getTypeName()); + sb.append('['); + if (arrayLength >=0){ + sb.append(arrayLength); + } + sb.append(']'); + + return sb.toString(); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/NOP.java b/src/main/gov/nasa/jpf/jvm/bytecode/NOP.java new file mode 100644 index 0000000..d8f50b0 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/NOP.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Do nothing + * No change + */ +public class NOP extends Instruction implements JVMInstruction { + + public NOP () { + // nothing to do + } + + @Override + public Instruction execute (ThreadInfo th) { + return getNext(th); + } + + @Override + public int getByteCode () { + return 0x00; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/NewArrayInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/NewArrayInstruction.java new file mode 100644 index 0000000..ae8181f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/NewArrayInstruction.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.bytecode.NewInstruction; +import gov.nasa.jpf.vm.Types; + +public abstract class NewArrayInstruction extends NewInstruction implements JVMInstruction { + + protected String type; + protected String typeName; // deferred initialization + + protected int arrayLength = -1; + + /** + * this only makes sense post-execution since the array dimension + * is obtained from the operand stack + * + * @return length of allocated array + */ + public int getArrayLength(){ + return arrayLength; + } + + public String getType(){ + return type; + } + + public String getTypeName() { + if (typeName == null){ + typeName = Types.getTypeName(type); + } + return typeName; + } + + @Override + public void cleanupTransients(){ + arrayLength = -1; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/POP.java b/src/main/gov/nasa/jpf/jvm/bytecode/POP.java new file mode 100644 index 0000000..ef7749e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/POP.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Pop the top operand stack value + * ..., value => ... + */ +public class POP extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + frame.pop(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x57; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/POP2.java b/src/main/gov/nasa/jpf/jvm/bytecode/POP2.java new file mode 100644 index 0000000..9dd7a1b --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/POP2.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Pop the top two operand slots + * ..., value2, value1 => ... + */ +public class POP2 extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.pop(2); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x58; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/PUTFIELD.java b/src/main/gov/nasa/jpf/jvm/bytecode/PUTFIELD.java new file mode 100644 index 0000000..69adcf3 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/PUTFIELD.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.util.InstructionState; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.WriteInstruction; + +/** + * Set field in object + * ..., objectref, value => ... + */ +public class PUTFIELD extends JVMInstanceFieldInstruction implements WriteInstruction { + + public PUTFIELD(String fieldName, String clsDescriptor, String fieldDescriptor){ + super(fieldName, clsDescriptor, fieldDescriptor); + } + + @Override + public int getObjectSlot (StackFrame frame){ + return frame.getTopPos() - size; + } + + /** + * where do we get the value from? + * NOTE: only makes sense in a executeInstruction() context + */ + @Override + public int getValueSlot (StackFrame frame){ + return frame.getTopPos(); + } + + + /** + * where do we write to? + * NOTE: this should only be used from a executeInstruction()/instructionExecuted() context + */ + @Override + public ElementInfo getElementInfo(ThreadInfo ti){ + if (isCompleted(ti)){ + return ti.getElementInfo(lastThis); + } else { + return peekElementInfo(ti); // get it from the stack + } + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + int objRef = frame.peek( size); + lastThis = objRef; + + if (objRef == MJIEnv.NULL) { + return ti.createAndThrowException("java.lang.NullPointerException", "referencing field '" + fname + "' on null object"); + } + + ElementInfo eiFieldOwner = ti.getModifiableElementInfo(objRef); + FieldInfo fieldInfo = getFieldInfo(); + if (fieldInfo == null) { + return ti.createAndThrowException("java.lang.NoSuchFieldError", "no field " + fname + " in " + eiFieldOwner); + } + + //--- check scheduling point due to shared object access + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedObjectCG(ti,this,eiFieldOwner,fieldInfo)){ + eiFieldOwner = scheduler.updateObjectSharedness( ti, eiFieldOwner, fi); + if (scheduler.setsSharedObjectCG( ti, this, eiFieldOwner, fieldInfo)){ + return this; // re-execute + } + } + + // this might be re-executed + if (frame.getAndResetFrameAttr(InstructionState.class) == null){ + lastValue = PutHelper.setField(ti, frame, eiFieldOwner, fieldInfo); + } + + //--- check scheduling point due to exposure through shared object + if (isReferenceField()){ + int refValue = frame.peek(); + if (refValue != MJIEnv.NULL){ + ElementInfo eiExposed = ti.getElementInfo(refValue); + if (scheduler.setsSharedObjectExposureCG(ti, this, eiFieldOwner, fi, eiExposed)){ + frame.addFrameAttr( InstructionState.processed); + return this; // re-execute AFTER assignment + } + } + } + + popOperands(frame); + return getNext(); + } + + protected void popOperands (StackFrame frame){ + if (size == 1){ + frame.pop(2); // .. objref, val => .. + } else { + frame.pop(3); // .. objref, highVal,lowVal => .. + } + } + + @Override + public ElementInfo peekElementInfo (ThreadInfo ti) { + FieldInfo fi = getFieldInfo(); + int storageSize = fi.getStorageSize(); + int objRef = ti.getTopFrame().peek( (storageSize == 1) ? 1 : 2); + ElementInfo ei = ti.getElementInfo( objRef); + + return ei; + } + + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xB5; + } + + @Override + public boolean isRead() { + return false; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} + + + diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java b/src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java new file mode 100644 index 0000000..ac16018 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.util.InstructionState; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LoadOnJPFRequired; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.Scheduler; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.WriteInstruction; + + +/** + * Set static field in class + * ..., value => ... + */ +public class PUTSTATIC extends JVMStaticFieldInstruction implements WriteInstruction { + + public PUTSTATIC(String fieldName, String clsDescriptor, String fieldDescriptor){ + super(fieldName, clsDescriptor, fieldDescriptor); + } + + /** + * where do we get the value from? + * NOTE: only makes sense in a executeInstruction() context + */ + @Override + public int getValueSlot (StackFrame frame){ + return frame.getTopPos(); + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + FieldInfo fieldInfo; + + //--- check if this causes a class load by a user defined classloader + try { + fieldInfo = getFieldInfo(); + } catch (LoadOnJPFRequired lre) { + return ti.getPC(); + } + + if (fieldInfo == null) { + return ti.createAndThrowException("java.lang.NoSuchFieldError", (className + '.' + fname)); + } + + //--- check if this has to trigger class initialization + ClassInfo ciField = fieldInfo.getClassInfo(); + if (!mi.isClinit(ciField) && ciField.initializeClass(ti)) { + return ti.getPC(); // this returns the next insn in the topmost clinit that just got pushed + } + ElementInfo eiFieldOwner = ciField.getModifiableStaticElementInfo(); + + //--- check scheduling point due to shared class access + Scheduler scheduler = ti.getScheduler(); + if (scheduler.canHaveSharedClassCG( ti, this, eiFieldOwner, fieldInfo)){ + eiFieldOwner = scheduler.updateClassSharedness(ti, eiFieldOwner, fi); + if (scheduler.setsSharedClassCG( ti, this, eiFieldOwner, fieldInfo)){ + return this; // re-execute + } + } + + // check if this gets re-executed from a exposure CG (which already did the assignment + if (frame.getAndResetFrameAttr(InstructionState.class) == null){ + lastValue = PutHelper.setField(ti, frame, eiFieldOwner, fieldInfo); + } + + //--- check scheduling point due to exposure through shared class + if (isReferenceField()){ + int refValue = frame.peek(); + if (refValue != MJIEnv.NULL){ + ElementInfo eiExposed = ti.getElementInfo(refValue); + if (scheduler.setsSharedClassExposureCG(ti,this,eiFieldOwner,fieldInfo,eiExposed)){ + frame.addFrameAttr( InstructionState.processed); + return this; // re-execute AFTER assignment + } + } + } + + popOperands(frame); + return getNext(); + } + + protected void popOperands (StackFrame frame){ + if (size == 1){ + frame.pop(); // .. val => .. + } else { + frame.pop(2); // .. highVal, lowVal => .. + } + } + + @Override + public int getLength() { + return 3; // opcode, index1, index2 + } + + @Override + public int getByteCode () { + return 0xB3; + } + + @Override + public boolean isRead() { + return false; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/PutHelper.java b/src/main/gov/nasa/jpf/jvm/bytecode/PutHelper.java new file mode 100644 index 0000000..2868e31 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/PutHelper.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * helper class to factor out common PUT code + * + * <2do> This is going to be moved into a Java 8 interface with default methods + */ +public class PutHelper { + + protected static boolean hasNewValue (ThreadInfo ti, StackFrame frame, ElementInfo eiFieldOwner, FieldInfo fi){ + Object valAttr = null; + int fieldSize = fi.getStorageSize(); + + if (fieldSize == 1){ + valAttr = frame.getOperandAttr(); + int val = frame.peek(); + if (eiFieldOwner.get1SlotField(fi) != val){ + return true; + } + + } else { + valAttr = frame.getLongOperandAttr(); + long val = frame.peekLong(); + if (eiFieldOwner.get2SlotField(fi) != val){ + return true; + } + } + + if (eiFieldOwner.getFieldAttr(fi) != valAttr){ + return true; + } + + return false; + } + + protected static int setReferenceField (ThreadInfo ti, StackFrame frame, ElementInfo eiFieldOwner, FieldInfo fi){ + Object valAttr = frame.getOperandAttr(); + int val = frame.peek(); + eiFieldOwner.set1SlotField(fi, val); + eiFieldOwner.setFieldAttr(fi, valAttr); + return val; + } + + protected static long setField (ThreadInfo ti, StackFrame frame, ElementInfo eiFieldOwner, FieldInfo fi){ + int fieldSize = fi.getStorageSize(); + + if (fieldSize == 1){ + Object valAttr = frame.getOperandAttr(); + int val = frame.peek(); + eiFieldOwner.set1SlotField(fi, val); + eiFieldOwner.setFieldAttr(fi, valAttr); + return val; + + } else { + Object valAttr = frame.getLongOperandAttr(); + long val = frame.peekLong(); + eiFieldOwner.set2SlotField(fi, val); + eiFieldOwner.setFieldAttr(fi, valAttr); + return val; + } + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/RET.java b/src/main/gov/nasa/jpf/jvm/bytecode/RET.java new file mode 100644 index 0000000..a9f62a6 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/RET.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Return from subroutine + * No change + */ +public class RET extends Instruction implements JVMInstruction { + private int index; + + public RET( int index){ + this.index = index; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getTopFrame(); + int jumpTgt = frame.getLocalVariable(index); + return mi.getInstructionAt(jumpTgt); + } + + @Override + public int getLength() { + return 2; // opcode, insnIndex + } + + @Override + public int getByteCode () { + return 0xA9; // ?? wide + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getIndex() { + return index; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/RETURN.java b/src/main/gov/nasa/jpf/jvm/bytecode/RETURN.java new file mode 100644 index 0000000..605e8ac --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/RETURN.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Return void from method + * ... [empty] + */ +public class RETURN extends JVMReturnInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + + if (mi.isInit()) { // Check to see if this method is a constructor. + int objref = ti.getThis(); + ElementInfo ei = ti.getElementInfo(objref); // Get the object. + + if (!ei.isConstructed()) { // Don't bother doing the following work if the object is already constructed. + + ClassInfo ei_ci = ei.getClassInfo(); // Get the object's class. + ClassInfo mi_ci = mi.getClassInfo(); // Get the method's class. + + if (ei_ci == mi_ci) { // If the object's class and the method's class are equal, then the thread is returning from the object's constructor. + ei = ei.getModifiableInstance(); + ei.setConstructed(); + } + } + + } else if (mi.isClinit()) { + // this also needs to happen in NATIVERETURN for native clinits. See comment + // there why we can't refactor this into DIRECTCALLRETURN + mi.getClassInfo().setInitialized(); + } + + return super.execute(ti); + } + + @Override + public int getReturnTypeSize() { + return 0; + } + + @Override + protected Object getReturnedOperandAttr (StackFrame frame) { + return null; + } + + + @Override + public Object getReturnAttr (ThreadInfo ti){ + return null; // no return value + } + + @Override + protected void getAndSaveReturnValue (StackFrame frame) { + // we don't have any + } + + @Override + protected void pushReturnValue (StackFrame frame) { + // nothing to do + } + + @Override + public Object getReturnValue(ThreadInfo ti) { + //return Void.class; // Hmm, not sure if this is right, but we have to distinguish from ARETURN + return null; + } + + @Override + public String toString() { + return "return " + mi.getFullName(); + } + + @Override + public int getByteCode () { + return 0xB1; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/RUNSTART.java b/src/main/gov/nasa/jpf/jvm/bytecode/RUNSTART.java new file mode 100644 index 0000000..9fa1512 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/RUNSTART.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * this is an artificial instruction that is automatically prepended to + * a run()/main() method call. + * + * The main purpose is to have a special instruction marking the beginning + * of a new thread execution which does not cause CGs or is otherwise subject + * to execution semantics that change the program state. + * + * For instance, without it we would have to add a new ThreadInfo state to + * determine if the first instruction within this thread was re-executed or + * just happens to be the first transition we execute within this thread + * + */ +public class RUNSTART extends Instruction implements JVMInstruction { + + public RUNSTART () { + } + + @Override + public Instruction execute (ThreadInfo ti) { + // nothing here, we could have used a NOP + return getNext(ti); + } + + public static final int OPCODE = 257; + + @Override + public int getByteCode () { + return OPCODE; + } + + @Override + public boolean isExtendedInstruction() { + return true; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/SALOAD.java b/src/main/gov/nasa/jpf/jvm/bytecode/SALOAD.java new file mode 100644 index 0000000..aea3261 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/SALOAD.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Load short from array + * ..., arrayref, index => ..., value + */ +public class SALOAD extends ArrayLoadInstruction { + + @Override + protected void push (StackFrame frame, ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + short value = ei.getShortElement(index); + frame.push( value); + } + + + @Override + public int getByteCode () { + return 0x35; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/SASTORE.java b/src/main/gov/nasa/jpf/jvm/bytecode/SASTORE.java new file mode 100644 index 0000000..96a090c --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/SASTORE.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.StackFrame; + +/** + * Store into short array + * ..., array, index, value => ... + */ +public class SASTORE extends ArrayStoreInstruction { + + short value; + + @Override + protected void popValue(StackFrame frame){ + value = (short)frame.pop(); + } + + @Override + protected void setField (ElementInfo ei, int index) throws ArrayIndexOutOfBoundsExecutiveException { + ei.checkArrayBounds(index); + ei.setShortElement(index, value); + } + + + @Override + public int getByteCode () { + return 0x56; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/SIPUSH.java b/src/main/gov/nasa/jpf/jvm/bytecode/SIPUSH.java new file mode 100644 index 0000000..8b1f18d --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/SIPUSH.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Push short + * ... => ..., value + */ +public class SIPUSH extends Instruction implements JVMInstruction { + protected int value; + + public SIPUSH(int value){ + this.value = value; + } + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.push(value); + + return getNext(ti); + } + + @Override + public int getLength() { + return 3; // opcode, b1, b2 + } + + @Override + public int getByteCode () { + return 0x11; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getValue() { + return value; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/SWAP.java b/src/main/gov/nasa/jpf/jvm/bytecode/SWAP.java new file mode 100644 index 0000000..c53d655 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/SWAP.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Swap the top two operand stack values + * ..., value2, value1 => ..., value1, value2 + */ +public class SWAP extends Instruction implements JVMInstruction { + + @Override + public Instruction execute (ThreadInfo ti) { + StackFrame frame = ti.getModifiableTopFrame(); + + frame.swap(); + + return getNext(ti); + } + + @Override + public int getByteCode () { + return 0x5F; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/StaticFieldInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/StaticFieldInstruction.java new file mode 100644 index 0000000..f2a896e --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/StaticFieldInstruction.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StaticElementInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.FieldInstruction; + +/** + * class to abstract instructions accessing static fields + */ +public abstract class StaticFieldInstruction extends FieldInstruction { + + protected StaticFieldInstruction(String fieldName, String clsDescriptor, String fieldDescriptor){ + super(fieldName, clsDescriptor, fieldDescriptor); + } + + /** + * on-demand initialize the ClassInfo and FieldInfo fields. Note that + * classinfo might not correspond with the static className, but can be one of + * the super classes. Rather than checking for this on each subsequent access, + * we get the right one that declares the field here + */ + protected void initialize() { + ClassInfo ciRef = mi.getClassInfo().resolveReferencedClass(className); + + FieldInfo f = ciRef.getStaticField(fname); + ClassInfo ciField = f.getClassInfo(); + if (!ciField.isRegistered()){ + // classLoaded listeners might change/remove this field + ciField.registerClass(ThreadInfo.getCurrentThread()); + f = ciField.getStaticField(fname); + } + + fi = f; + } + + /** + * who owns the field? + * NOTE: this should only be used from a executeInstruction()/instructionExecuted() context + */ + @Override + public ElementInfo getElementInfo(ThreadInfo ti){ + return getFieldInfo().getClassInfo().getStaticElementInfo(); + } + + @Override + public String toPostExecString(){ + StringBuilder sb = new StringBuilder(); + sb.append(getMnemonic()); + sb.append(' '); + sb.append( fi.getFullName()); + + return sb.toString(); + } + + public ClassInfo getClassInfo() { + if (fi == null) { + initialize(); + } + return fi.getClassInfo(); + } + + @Override + public FieldInfo getFieldInfo() { + if (fi == null) { + initialize(); + } + return fi; + } + + /** + * that's invariant, as opposed to InstanceFieldInstruction, so it's + * not really a peek + */ + @Override + public ElementInfo peekElementInfo (ThreadInfo ti) { + return getLastElementInfo(); + } + + @Override + public StaticElementInfo getLastElementInfo() { + return getFieldInfo().getClassInfo().getStaticElementInfo(); + } + + // this can be different than ciField - the field might be in one of its + // superclasses + public ClassInfo getLastClassInfo(){ + return getFieldInfo().getClassInfo(); + } + + public String getLastClassName() { + return getLastClassInfo().getName(); + } + + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction typeSafeClone(MethodInfo mi) { + StaticFieldInstruction clone = null; + + try { + clone = (StaticFieldInstruction) super.clone(); + + // reset the method that this insn belongs to + clone.mi = mi; + clone.fi = null; // ClassInfo is going to be different + + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return clone; + } +} + diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/SwitchInstruction.java b/src/main/gov/nasa/jpf/jvm/bytecode/SwitchInstruction.java new file mode 100644 index 0000000..0752b5f --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/SwitchInstruction.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.KernelState; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.SystemState; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.choice.IntIntervalGenerator; + +/** + * common root class for LOOKUPSWITCH and TABLESWITCH insns + * + * <2do> this is inefficient. First, we should store targets as instruction indexes + * to avoid execution() looping. Second, there are no matches for a TABLESWITCH + */ +public abstract class SwitchInstruction extends Instruction implements JVMInstruction { + + public static final int DEFAULT = -1; + + protected int target; // default branch + protected int[] targets; // explicit value branches + protected int[] matches; // branch consts + + protected int lastIdx; + + protected SwitchInstruction (int defaultTarget, int numberOfTargets){ + target = defaultTarget; + targets = new int[numberOfTargets]; + matches = new int[numberOfTargets]; + } + + public int getNumberOfEntries() { + return targets.length; + } + + protected Instruction executeConditional (ThreadInfo ti){ + StackFrame frame = ti.getModifiableTopFrame(); + + int value = frame.pop(); + + lastIdx = DEFAULT; + + for (int i = 0, l = matches.length; i < l; i++) { + if (value == matches[i]) { + lastIdx = i; + return mi.getInstructionAt(targets[i]); + } + } + + return mi.getInstructionAt(target); + } + + @Override + public Instruction execute (ThreadInfo ti) { + // this can be overridden by subclasses, so we have to delegate the conditional execution + // to avoid getting recursive in executeAllBranches() + return executeConditional(ti); + } + + /** useful for symbolic execution modes */ + public Instruction executeAllBranches (SystemState ss, KernelState ks, ThreadInfo ti) { + if (!ti.isFirstStepInsn()) { + IntIntervalGenerator cg = new IntIntervalGenerator("switchAll", 0,matches.length); + if (ss.setNextChoiceGenerator(cg)){ + return this; + + } else { + // listener did override CG, fall back to conditional execution + return executeConditional(ti); + } + + } else { + IntIntervalGenerator cg = ss.getCurrentChoiceGenerator("switchAll", IntIntervalGenerator.class); + assert (cg != null) : "no IntIntervalGenerator"; + + StackFrame frame = ti.getModifiableTopFrame(); + int idx = frame.pop(); // but we are not using it + idx = cg.getNextChoice(); + + if (idx == matches.length){ // default branch + lastIdx = DEFAULT; + return mi.getInstructionAt(target); + } else { + lastIdx = idx; + return mi.getInstructionAt(targets[idx]); + } + } + } + + //--- a little inspection, but only post exec yet + + public int getLastTargetIndex () { + return lastIdx; + } + + public int getNumberOfTargets () { + return matches.length; + } + + public int getMatchConst (int idx){ + return matches[idx]; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + public int getTarget() { + return target; + } + + public int[] getTargets() { + return targets; + } + + public int[] getMatches() { + return matches; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/TABLESWITCH.java b/src/main/gov/nasa/jpf/jvm/bytecode/TABLESWITCH.java new file mode 100644 index 0000000..ee77258 --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/TABLESWITCH.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.JPFException; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * Access jump table by index and jump + * ..., index => ... + */ +public class TABLESWITCH extends SwitchInstruction implements gov.nasa.jpf.vm.bytecode.TableSwitchInstruction { + + int min, max; + + public TABLESWITCH(int defaultTarget, int min, int max){ + super(defaultTarget, (max - min +1)); + this.min = min; + this.max = max; + } + + public int getMin(){ + return min; + } + + public int getMax(){ + return max; + } + + @Override + public void setTarget (int value, int target){ + int i = value-min; + + if (i>=0 && i=0 && i this is BAD - we should compute the target insns just once + return mi.getInstructionAt(pc); + } + + + @Override + public int getLength() { + return 13 + 2*(matches.length); // <2do> NOT RIGHT: padding!! + } + + @Override + public int getByteCode () { + return 0xAA; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/VirtualInvocation.java b/src/main/gov/nasa/jpf/jvm/bytecode/VirtualInvocation.java new file mode 100644 index 0000000..f394eea --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/VirtualInvocation.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.ClassChangeException; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + + +/** + * a base class for virtual call instructions + */ +public abstract class VirtualInvocation extends InstanceInvocation { + + // note that we can't null laseCalleeCi and invokedMethod in cleanupTransients() + // since we use it as an internal optimization (loops with repeated calls on the + // same object) + + ClassInfo lastCalleeCi; // cached for performance + + protected VirtualInvocation () {} + + protected VirtualInvocation (String clsDescriptor, String methodName, String signature){ + super(clsDescriptor, methodName, signature); + } + + @Override + public String toPostExecString(){ + StringBuilder sb = new StringBuilder(); + sb.append(getMnemonic()); + sb.append(' '); + + if (invokedMethod != null){ + sb.append( lastCalleeCi.getName()); + sb.append('@'); + sb.append(Integer.toHexString(lastObj)); + sb.append('.'); + sb.append(invokedMethod.getUniqueName()); + + if (invokedMethod.isMJI()){ + sb.append(" [native]"); + } + + } else { // something went wrong, the method wasn't found + if (lastCalleeCi != null){ + sb.append( lastCalleeCi.getName()); + } else { + sb.append(cname); + } + sb.append('@'); + if (lastObj == MJIEnv.NULL){ + sb.append(""); + } else { + sb.append(Integer.toHexString(lastObj)); + } + sb.append('.'); + sb.append(mname); + sb.append(signature); + sb.append(" (?)"); + } + + return sb.toString(); + } + + @Override + public Instruction execute (ThreadInfo ti) { + int objRef = ti.getCalleeThis(getArgSize()); + MethodInfo callee; + + if (objRef == MJIEnv.NULL) { + lastObj = MJIEnv.NULL; + return ti.createAndThrowException("java.lang.NullPointerException", "Calling '" + mname + "' on null object"); + } + + try { + callee = getInvokedMethod(ti, objRef); + } catch (ClassChangeException ccx){ + return ti.createAndThrowException("java.lang.IncompatibleClassChangeError", ccx.getMessage()); + } + + ElementInfo ei = ti.getElementInfo(objRef); + + if (callee == null) { + String clsName = ti.getClassInfo(objRef).getName(); + return ti.createAndThrowException("java.lang.NoSuchMethodError", clsName + '.' + mname); + } else { + if (callee.isAbstract()){ + return ti.createAndThrowException("java.lang.AbstractMethodError", callee.getFullName() + ", object: " + ei); + } + } + + if (callee.isSynchronized()) { + ei = ti.getScheduler().updateObjectSharedness(ti, ei, null); // locks most likely belong to shared objects + if (reschedulesLockAcquisition(ti, ei)){ + return this; + } + } + + setupCallee( ti, callee); // this creates, initializes and pushes the callee StackFrame + + return ti.getPC(); // we can't just return the first callee insn if a listener throws an exception + } + + /** + * If the current thread already owns the lock, then the current thread can go on. + * For example, this is a recursive acquisition. + */ + protected boolean isLockOwner(ThreadInfo ti, ElementInfo ei) { + return ei.getLockingThread() == ti; + } + + /** + * If the object will still be owned, then the current thread can go on. + * For example, all but the last monitorexit for the object. + */ + protected boolean isLastUnlock(ElementInfo ei) { + return ei.getLockCount() == 1; + } + + + @Override + public MethodInfo getInvokedMethod(ThreadInfo ti){ + int objRef; + + if (ti.getNextPC() == null){ // this is pre-exec + objRef = ti.getCalleeThis(getArgSize()); + } else { // this is post-exec + objRef = lastObj; + } + + return getInvokedMethod(ti, objRef); + } + + public MethodInfo getInvokedMethod (ThreadInfo ti, int objRef) { + + if (objRef != MJIEnv.NULL) { + lastObj = objRef; + + ClassInfo cci = ti.getClassInfo(objRef); + + if (lastCalleeCi != cci) { // callee ClassInfo has changed + lastCalleeCi = cci; + invokedMethod = cci.getMethod(mname, true); + + if (invokedMethod == null) { + invokedMethod = cci.getDefaultMethod(mname); + + if (invokedMethod == null){ + lastObj = MJIEnv.NULL; + lastCalleeCi = null; + } + } + } + + } else { + lastObj = MJIEnv.NULL; + lastCalleeCi = null; + invokedMethod = null; + } + + return invokedMethod; + } + + @Override + public Object getFieldValue (String id, ThreadInfo ti){ + int objRef = getCalleeThis(ti); + ElementInfo ei = ti.getElementInfo(objRef); + + Object v = ei.getFieldValueObject(id); + + if (v == null){ // try a static field + v = ei.getClassInfo().getStaticFieldValueObject(id); + } + + return v; + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } + + @Override + public Instruction typeSafeClone(MethodInfo clonedMethod) { + VirtualInvocation clone = null; + + try { + clone = (VirtualInvocation) super.clone(); + + // reset the method that this insn belongs to + clone.mi = clonedMethod; + + clone.lastCalleeCi = null; + clone.invokedMethod = null; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return clone; + } +} diff --git a/src/main/gov/nasa/jpf/jvm/bytecode/WIDE.java b/src/main/gov/nasa/jpf/jvm/bytecode/WIDE.java new file mode 100644 index 0000000..8d43ddb --- /dev/null +++ b/src/main/gov/nasa/jpf/jvm/bytecode/WIDE.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.jvm.bytecode; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * modifies following insn, no stack manipulation + * NOTE: transparently handled by BCEL, we should never receive this + * + * (1): indexbyte1 indexbyte2 + * (2): indexbyte1 indexbyte2 constbyte1 constbyte2 + * + */ +public class WIDE extends Instruction implements JVMInstruction { + + // would have to be checked and reset by following insn + public static boolean isWide = false; + + @Override + public int getByteCode() { + return 0xc4; + } + + @Override + public Instruction execute(ThreadInfo ti) { + // nothing, BCEL doesn't even pass this on; + return getNext(ti); + } + + @Override + public void accept(JVMInstructionVisitor insVisitor) { + insVisitor.visit(this); + } +} diff --git a/src/main/gov/nasa/jpf/listener/AssertionProperty.java b/src/main/gov/nasa/jpf/listener/AssertionProperty.java new file mode 100644 index 0000000..178b1d6 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/AssertionProperty.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.PropertyListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.ATHROW; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Heap; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * this is a property listener that turns thrown AssertionErrors into + * property violations before they are caught (i.e. potentially + * change the stack). + * Besides serving the purpose of eliminating the "catch(Throwable)" case, + * it can be used in conjunction with "search.multiple_errors=true" to + * report assertions but otherwise ignore them and go on searching the + * same path (otherwise, multiple_errors would cause a backtrack) + */ +public class AssertionProperty extends PropertyListenerAdapter { + + static JPFLogger log = JPF.getLogger("gov.nasa.jpf.listener.AssertionProperty"); + + boolean goOn; + String msg; + + public AssertionProperty (Config config) { + goOn = config.getBoolean("ap.go_on",false); + } + + @Override + public boolean check(Search search, VM vm) { + return (msg == null); + } + + @Override + public String getErrorMessage() { + return msg; + } + + protected String getMessage (String details, Instruction insn){ + String s = "failed assertion"; + + if (details != null){ + s += ": \""; + s += details; + s += '"'; + } + + s += " at "; + s += insn.getSourceLocation(); + + return s; + } + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insn){ + + if (insn instanceof ATHROW) { + + Heap heap = vm.getHeap(); + StackFrame frame = ti.getTopFrame(); + int xobjref = frame.peek(); + ElementInfo ei = heap.get(xobjref); + ClassInfo ci = ei.getClassInfo(); + + if (ci.getName().equals("java.lang.AssertionError")) { + int msgref = ei.getReferenceField("detailMessage"); + ElementInfo eiMsg = heap.get(msgref); + String details = eiMsg != null ? eiMsg.asString() : null; + + // Ok, arm ourselves + msg = getMessage( details, insn.getNext()); + + if (goOn) { + log.warning(msg); + + frame = ti.getModifiableTopFrame(); + frame.pop(); // ensure operand stack integrity (ATHROW pops) + + ti.skipInstruction(insn.getNext()); + + } else { + ti.skipInstruction(insn); + ti.breakTransition("assertion"); + } + } + } + } + + @Override + public void reset() { + msg = null; + } +} diff --git a/src/main/gov/nasa/jpf/listener/BudgetChecker.java b/src/main/gov/nasa/jpf/listener/BudgetChecker.java new file mode 100644 index 0000000..2a84b6c --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/BudgetChecker.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.annotation.JPFOption; +import gov.nasa.jpf.annotation.JPFOptions; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; + +/** + * Listener that implements various budget constraints + */ +@JPFOptions({ + @JPFOption(type = "Long", key = "budget.max_time", defaultValue= "-1", comment = "stop search after specified duration [msec]"), + @JPFOption(type = "Long", key = "budget.max_heap", defaultValue = "-1", comment="stop search when VM heapsize reaches specified limit"), + @JPFOption(type = "Int", key = "budget.max_depth", defaultValue = "-1", comment = "stop search at specified search depth"), + @JPFOption(type = "long", key = "budget.max_insn", defaultValue = "-1", comment = "stop search after specified number of intstructions"), + @JPFOption(type = "Int", key = "budget.max_state", defaultValue = "-1", comment = "stop search when reaching specified number of new states"), + @JPFOption(type = "Int", key = "budget.max_new_states", defaultValue = "-1", comment="stop search ater specified number of non-replayed new states") +}) +public class BudgetChecker extends ListenerAdapter { + + static final int CHECK_INTERVAL = 10000; + static final int CHECK_INTERVAL1 = CHECK_INTERVAL-1; + + long tStart; + MemoryUsage muStart; + long mStart; + MemoryMXBean mxb; + + VM vm; + Search search; + long insnCount; + + //--- the budget thresholds + long maxTime; + long maxHeap; + + int maxDepth; + long maxInsn; + int maxState; + int maxNewStates; + + int newStates; + + // the message explaining the exceeded budget + String message; + + public BudgetChecker (Config conf, JPF jpf) { + + //--- get the configured budget limits (0 means not set) + maxTime = conf.getDuration("budget.max_time", 0); + maxHeap = conf.getMemorySize("budget.max_heap", 0); + maxDepth = conf.getInt("budget.max_depth", 0); + maxInsn = conf.getLong("budget.max_insn", 0); + maxState = conf.getInt("budget.max_state", 0); + maxNewStates = conf.getInt("budget.max_new_states", 0); + + tStart = System.currentTimeMillis(); + + if (maxHeap > 0) { + mxb = ManagementFactory.getMemoryMXBean(); + muStart = mxb.getHeapMemoryUsage(); + mStart = muStart.getUsed(); + } + + search = jpf.getSearch(); + vm = jpf.getVM(); + } + + public boolean timeExceeded() { + if (maxTime > 0) { + long dur = System.currentTimeMillis() - tStart; + if (dur > maxTime) { + message = "max time exceeded: " + Publisher.formatHMS(dur) + + " >= " + Publisher.formatHMS(maxTime); + return true; + } + } + + return false; + } + + public boolean heapExceeded() { + if (maxHeap > 0) { + MemoryUsage mu = mxb.getHeapMemoryUsage(); + long used = mu.getUsed() - mStart; + if (used > maxHeap) { + message = "max heap exceeded: " + (used / (1024*1024)) + "MB" + + " >= " + (maxHeap / (1024*1024)) + "MB" ; + return true; + } + } + + return false; + } + + public boolean depthExceeded () { + if (maxDepth > 0) { + int d = search.getDepth(); + if (d > maxDepth) { + message = "max search depth exceeded: " + maxDepth; + return true; + } + } + + return false; + } + + public boolean statesExceeded () { + if (maxState > 0) { + int stateId = vm.getStateId(); + if (stateId > maxState) { + message = "max states exceeded: " + maxState;; + return true; + } + } + + return false; + } + + public boolean insnExceeded () { + if (maxInsn > 0) { + if (insnCount > maxInsn) { + message = "max instruction count exceeded: " + maxInsn; + return true; + } + } + return false; + } + + public boolean newStatesExceeded(){ + if (maxNewStates > 0){ + if (newStates > maxNewStates) { + message = "max new state count exceeded: " + maxNewStates; + return true; + } + } + return false; + } + + @Override + public void stateAdvanced (Search search) { + if (timeExceeded() || heapExceeded()) { + search.notifySearchConstraintHit(message); + search.terminate(); + } + + if (search.isNewState()){ + if (!vm.isTraceReplay()){ + newStates++; + } + if (statesExceeded() || depthExceeded() || newStatesExceeded()){ + search.notifySearchConstraintHit(message); + search.terminate(); + } + } + } + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + if ((insnCount++ % CHECK_INTERVAL) == CHECK_INTERVAL1) { + + if (timeExceeded() || heapExceeded() || insnExceeded()) { + search.notifySearchConstraintHit(message); + + vm.getCurrentThread().breakTransition("budgetConstraint"); + search.terminate(); + } + } + } + +} diff --git a/src/main/gov/nasa/jpf/listener/CGMonitor.java b/src/main/gov/nasa/jpf/listener/CGMonitor.java new file mode 100644 index 0000000..9f3c21c --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/CGMonitor.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.VM; +import java.io.PrintStream; + +/** + * listener to report out what CGs and choices are processed during the search. + * This is a simple tool to find out about the SUT state space + */ +public class CGMonitor extends ListenerAdapter { + + protected PrintStream out; + + protected int depth; + + // display options + protected boolean showInsn = false; // show the insn that caused the CG + protected boolean showChoice = false; // show the choice value (-> show each CG.advance()) + protected boolean showDepth = true; // show search depth at point of CG set/advance + + public CGMonitor (Config conf) { + showInsn = conf.getBoolean("cgm.show_insn", showInsn); + showChoice = conf.getBoolean("cgm.show_choice", showChoice); + showDepth = conf.getBoolean("cgm.show_depth", showDepth); + + out = System.out; + } + + @Override + public void stateAdvanced (Search search) { + depth++; + } + + @Override + public void stateBacktracked (Search search) { + depth--; + } + + @Override + public void stateRestored (Search search) { + depth = search.getDepth(); + } + + void printPrefix(char c) { + for (int i=0; i cg, boolean printChoice){ + if (showDepth){ + printPrefix('.'); + } + + out.print(cg); + + if (printChoice){ + out.print(", "); + out.print(cg.getNextChoice()); + } + + if (showInsn){ + out.print(", \""); + out.print(cg.getInsn()); + out.print('\"'); + } + + out.println(); + } + + @Override + public void choiceGeneratorSet (VM vm, ChoiceGenerator currentCG) { + if (!showChoice){ + printCG( vm.getChoiceGenerator(), false); + } + } + + @Override + public void choiceGeneratorAdvanced (VM vm, ChoiceGenerator currentCG) { + if (showChoice){ + printCG( vm.getChoiceGenerator(), true); + } + } + +} diff --git a/src/main/gov/nasa/jpf/listener/CGRemover.java b/src/main/gov/nasa/jpf/listener/CGRemover.java new file mode 100644 index 0000000..14aa962 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/CGRemover.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.util.LocationSpec; +import gov.nasa.jpf.util.MethodSpec; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * listener that removes CGs for specified locations, method calls or method bodies + * + * This is an application specific state space optimizer that should be used + * carefully since it has to be aware of which CGs can be removed, and which + * ones can't (e.g. blocking sync or wait). You also have to be aware of the + * order of listener registration, since subsequently registered listeners can + * still add new CGs after they got removed here. THIS IS ONLY AN OPTIMIZATION + * TOOL THAT SHOULD BE USED IN A WELL KNOWN APPLICATION CONTEXT. + * + * cgrm.thread.cg_class = gov.nasa.jpf.vm.ThreadChoiceGenerator + * cgrm.thread.locations = Foobar.java:42 // either a LocationSpec + * cgrm.thread.method_bodies = a.SomeClass.someMethod() // ..or a MethodSpec for a body + * cgrm.thread.method_calls = b.A.foo(int) // ..or a MethodSpec for a call + * + * NOTE: in its current implementation, this listener has to be registered + * before targeted classes are loaded + */ +public class CGRemover extends ListenerAdapter { + + static JPFLogger log = JPF.getLogger("gov.nasa.jpf.CGRemover"); + + static class Category { + String id; + + Class cgClass; + + ArrayList locations = new ArrayList(); + ArrayList methodBodies = new ArrayList(); + ArrayList methodCalls = new ArrayList(); + + Category (String id){ + this.id = id; + } + + boolean checkSpecification() { + return cgClass != null && + (!locations.isEmpty() || !methodBodies.isEmpty() || !methodCalls.isEmpty()); + } + } + + List categories; + + HashMap methodBodies; + HashMap methodCalls; + HashMap locations; + + + public CGRemover (Config conf){ + categories = parseCategories(conf); + } + + protected List parseCategories (Config conf){ + ArrayList list = new ArrayList(); + Category category = null; + + for (String key : conf.getKeysStartingWith("cgrm.")){ + String[] kc = conf.getKeyComponents(key); + if (kc.length == 3){ + String k = kc[1]; + if (category != null){ + if (!category.id.equals(k)){ + addCategory(list, category); + + category = new Category(k); + } + } else { + category = new Category(k); + } + + k = kc[2]; + + if ("cg_class".equals(k)){ + category.cgClass = conf.getClass(key); + + } else if ("locations".equals(k)){ + parseLocationSpecs(category.locations, conf.getStringArray(key)); + + } else if ("method_bodies".equals(k)){ + parseMethodSpecs(category.methodBodies, conf.getStringArray(key)); + + } else if ("method_calls".equals(k)){ + parseMethodSpecs(category.methodCalls, conf.getStringArray(key)); + + } else { + // we might have more options in the future + log.warning("illegal CGRemover option: ", key); + } + + } else { + log.warning("illegal CGRemover key: ", key); + } + } + + addCategory(list, category); + return list; + } + + protected void addCategory (List list, Category cat){ + if (cat != null) { + if (cat.checkSpecification()) { + list.add(cat); + log.info("added category: ", cat.id); + } else { + log.warning("incomplete CGRemover category: ", cat.id); + } + } + } + + protected void parseLocationSpecs (List list, String[] specs){ + for (String spec : specs) { + LocationSpec locSpec = LocationSpec.createLocationSpec(spec); + if (locSpec != null) { + if (locSpec.isAnyLine()){ + log.warning("whole file location specs not supported by CGRemover (use cgrm...method_bodies)"); + } else { + list.add(locSpec); + } + } else { + log.warning("location spec did not parse: ", spec); + } + } + } + + protected void parseMethodSpecs (List list, String[] specs){ + for (String spec : specs) { + MethodSpec mthSpec = MethodSpec.createMethodSpec(spec); + if (mthSpec != null) { + list.add(mthSpec); + } else { + log.warning("methos spec did not parse: ", spec); + } + } + } + + + protected void processClass (ClassInfo ci, Category cat){ + String fname = ci.getSourceFileName(); + + for (LocationSpec loc : cat.locations){ + if (loc.matchesFile(fname)){ // Ok, we have to dig out the corresponding insns (if any) + Instruction[] insns = ci.getMatchingInstructions(loc); + if (insns != null){ + if (locations == null){ + locations = new HashMap(); + } + for (Instruction insn : insns){ + locations.put(insn, cat); + } + } else { + log.warning("no insns for location: ", loc, " in class: ", ci.getName()); + } + } + } + + for (MethodSpec ms : cat.methodBodies){ + List list = ci.getMatchingMethodInfos(ms); + if (list != null){ + for (MethodInfo mi : list){ + if (methodBodies == null){ + methodBodies = new HashMap(); + } + methodBodies.put(mi, cat); + } + } + } + + for (MethodSpec ms : cat.methodCalls){ + List list = ci.getMatchingMethodInfos(ms); + if (list != null){ + for (MethodInfo mi : list){ + if (methodCalls == null){ + methodCalls = new HashMap(); + } + methodCalls.put(mi, cat); + } + } + } + } + + protected boolean removeCG (VM vm, Category cat, ChoiceGenerator cg){ + if (cat != null){ + if (cat.cgClass.isAssignableFrom(cg.getClass())){ + vm.getSystemState().removeNextChoiceGenerator(); + log.info("removed CG: ", cg); + return true; + } + } + + return false; + } + + //--- VMListener interface + + // this is where we turn Categories into MethodInfos and Instructions to watch out for + @Override + public void classLoaded (VM vm, ClassInfo loadedClass){ + for (Category cat : categories){ + processClass(loadedClass, cat); + } + } + + // this is our main purpose in life + @Override + public void choiceGeneratorRegistered (VM vm, ChoiceGenerator nextCG, ThreadInfo ti, Instruction executedInsn){ + ChoiceGenerator cg = vm.getNextChoiceGenerator(); + Instruction insn = cg.getInsn(); + + if (locations != null){ + if ( removeCG(vm, locations.get(insn), cg)){ + return; + } + } + + if (insn instanceof JVMInvokeInstruction){ + MethodInfo invokedMi = ((JVMInvokeInstruction)insn).getInvokedMethod(); + if (methodCalls != null) { + if (removeCG(vm, methodCalls.get(invokedMi), cg)) { + return; + } + } + } + + if (methodBodies != null){ + if (removeCG(vm, methodBodies.get(insn.getMethodInfo()), cg)) { + return; + } + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/CallMonitor.java b/src/main/gov/nasa/jpf/listener/CallMonitor.java new file mode 100644 index 0000000..010e52c --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/CallMonitor.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * this isn't yet a useful tool, but it shows how to track method calls with + * their corresponding argument values + */ +public class CallMonitor extends ListenerAdapter { + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + + if (executedInsn instanceof JVMInvokeInstruction) { + if (executedInsn.isCompleted(ti) && !ti.isInstructionSkipped()) { + JVMInvokeInstruction call = (JVMInvokeInstruction)executedInsn; + MethodInfo mi = call.getInvokedMethod(); + Object[] args = call.getArgumentValues(ti); + ClassInfo ci = mi.getClassInfo(); + + StringBuilder sb = new StringBuilder(); + + sb.append(ti.getId()); + sb.append(": "); + + int d = ti.getStackDepth(); + for (int i=0; i currentCG) { + int n = currentCG.getTotalNumberOfChoices(); + + if (trace != null) { // this is a replay + + // <2do> maybe that should just be a warning, and then a single choice + assert currentCG.getClass().getName().equals(trace.getCgClassName()) : + "wrong choice generator class, expecting: " + trace.getCgClassName() + + ", read: " + currentCG.getClass().getName(); + + int choiceIndex = trace.getChoiceIndex(); + currentCG.select(choiceIndex); + + } else { + if (singleChoice) { + if (n > 1) { + int r = random.nextInt(n); + currentCG.select(r); // sets it done, so we never backtrack into it + } + } + } + } + + @Override + public void threadStarted(VM vm, ThreadInfo ti) { + if (singleChoice && (threadSet != null)) { + String tname = ti.getName(); + if (threadSet.matchesAny( tname)){ + threadsAlive = true; + checkSingleChoiceCond(); + } + } + } + + @Override + public void executeInstruction(VM vm, ThreadInfo ti, Instruction insnToExecute) { + if (singleChoice && !callSeen && (calls != null)) { + if (insnToExecute instanceof JVMInvokeInstruction) { + String mthName = ((JVMInvokeInstruction)insnToExecute).getInvokedMethod(ti).getBaseName(); + + if (calls.matchesAny(mthName)){ + callSeen = true; + checkSingleChoiceCond(); + } + } + } + } + + @Override + public void stateAdvanced(Search search) { + + if (trace != null) { + // there is no backtracking or restoring as long as we replay + trace = trace.getNext(); + + if (trace == null){ + search.getVM().setTraceReplay(false); + if (searchAfterTrace){ + singleChoice = false; + } + } + + } else { + if (singleChoice && !depthReached && (startDepth >= 0)) { + if (search.getDepth() == startDepth) { + depthReached = true; + checkSingleChoiceCond(); + } + } + } + } + +} diff --git a/src/main/gov/nasa/jpf/listener/ChoiceTracker.java b/src/main/gov/nasa/jpf/listener/ChoiceTracker.java new file mode 100644 index 0000000..0f418d8 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/ChoiceTracker.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.SystemState; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; + +/** + * generic choice tracker tool, to produce a list of choice values that + * can be used to create readable replay scripts etc. + */ +public class ChoiceTracker extends ListenerAdapter implements PublisherExtension { + + enum Format { CG, CHOICE }; + + Config config; + VM vm; + Search search; + + protected PrintWriter pw; + Class[] cgClasses; + boolean isReportExtension; + + boolean showLocation; + Format format = Format.CHOICE; + String[] excludes; + + // <2do> hardwired type specific tracker for use with some shells - check if + // we can get rid of it + public ChoiceTracker (JPF jpf, String traceFileName, Class cgClass){ + config = jpf.getConfig(); + vm = jpf.getVM(); + search = jpf.getSearch(); + + cgClasses = new Class[1]; + cgClasses[0] = cgClass; + + try { + pw = new PrintWriter(traceFileName); + } catch (FileNotFoundException fnfx) { + System.err.println("cannot write choice trace to file: " + traceFileName); + pw = new PrintWriter(System.out); + } + } + + public ChoiceTracker (Config config, JPF jpf) { + this.config = config; + vm = jpf.getVM(); + search = jpf.getSearch(); + + String fname = config.getString("choice.trace"); + if (fname == null) { + isReportExtension = true; + jpf.addPublisherExtension(ConsolePublisher.class, this); + // pw is going to be set later + } else { + try { + pw = new PrintWriter(fname); + } catch (FileNotFoundException fnfx) { + System.err.println("cannot write choice trace to file: " + fname); + pw = new PrintWriter(System.out); + } + } + + excludes = config.getStringArray("choice.exclude"); + cgClasses = config.getClasses("choice.class"); + + format = config.getEnum("choice.format", Format.values(), Format.CG); + showLocation = config.getBoolean("choice.show_location", true); + } + + public void setExcludes (String... ex) { + excludes=ex; + } + + boolean isRelevantCG (ChoiceGenerator cg){ + if (cgClasses == null){ + return true; + } else { + for (Class cls : cgClasses){ + if (cls.isAssignableFrom(cg.getClass())){ + return true; + } + } + + return false; + } + } + + @Override + public void propertyViolated (Search search) { + + if (!isReportExtension) { + + pw.print("// application: "); + pw.println( search.getVM().getSUTDescription()); + + if (cgClasses == null) { + pw.println("// trace over all CG classes"); + } else { + pw.print("// trace over CG types: "); + for (Class cls : cgClasses){ + pw.print(cls.getName()); + pw.print(' '); + } + pw.println(); + } + + pw.println("//------------------------- choice trace"); + printChoices(); + + pw.println("//------------------------- end choice trace"); + pw.flush(); + } + } + + void printChoices () { + int i = 0; + SystemState ss = vm.getSystemState(); + ChoiceGenerator[] cgStack = ss.getChoiceGenerators(); + + nextChoice: + for (ChoiceGenerator cg : cgStack) { + if (isRelevantCG(cg) && !cg.isDone()){ + + Object choice = cg.getNextChoice(); + if (choice == null) { + continue; + } else { + if (excludes != null) { + for (String e : excludes) { + if (choice.toString().startsWith(e)) { + continue nextChoice; + } + } + } + } + + String line = null; + + switch (format){ + case CHOICE: + line = choice.toString(); + if (line.startsWith("gov.nasa.jpf.vm.")){ + line = line.substring(17); + } + break; + case CG: + line = cg.toString(); + if (line.startsWith("gov.nasa.jpf.vm.choice.")){ + line = line.substring(24); + } + break; + } + + if (line != null){ + pw.print(String.format("%4d: ", i++)); + + pw.print(line); + + if (showLocation) { + String loc = cg.getSourceLocation(); + if (loc != null) { + pw.println(); + pw.print(" \tat "); + pw.print(loc); + } + } + pw.println(); + } + } + } + } + + //--- the PublisherExtension interface + + @Override + public void publishPropertyViolation (Publisher publisher) { + pw = publisher.getOut(); + publisher.publishTopicStart("choice trace " + publisher.getLastErrorId()); + printChoices(); + } + +} diff --git a/src/main/gov/nasa/jpf/listener/CoverageAnalyzer.java b/src/main/gov/nasa/jpf/listener/CoverageAnalyzer.java new file mode 100644 index 0000000..23010ca --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/CoverageAnalyzer.java @@ -0,0 +1,1228 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.GOTO; +import gov.nasa.jpf.jvm.bytecode.IfInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMReturnInstruction; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.util.Misc; +import gov.nasa.jpf.util.StringSetMatcher; +import gov.nasa.jpf.vm.AnnotationInfo; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassInfoException; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ExceptionHandler; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Logger; + +/** + * a listener to report coverage statistics + * + * The idea is to collect per-class/-method/-thread information about + * executed instructions, and then analyze this deeper when it comes to + * report time (e.g. branch coverage, basic blocks, ..) + * + * Keep in mind that this is potentially a concurrent, model checked program, + * i.e. there is more to coverage than what hits the eye of a static analyzer + * (exceptions, data and thread CGs) + */ +public class CoverageAnalyzer extends ListenerAdapter implements PublisherExtension { + + static Logger log = JPF.getLogger("gov.nasa.jpf.listener.CoverageAnalyzer"); + + static class Coverage { + + int total; + int covered; + + Coverage(int total, int covered) { + this.total = total; + this.covered = covered; + } + + public void add(Coverage cov) { + total += cov.total; + covered += cov.covered; + } + + public int percent() { + if (total > 0) { + return covered * 100 / total; + } + + return (Integer.MIN_VALUE); + } + + public int covered() { + return covered; + } + + public int total() { + return total; + } + + public boolean isPartiallyCovered() { + return ((covered > 0) && (covered < total)); + } + + public boolean isNotCovered() { + return (covered == 0); + } + + public boolean isFullyCovered() { + return (covered == total); + } + } + + static class MethodCoverage { + + MethodInfo mi; + + // we base everything else on bytecode instruction coverage + BitSet[] covered; + BitSet basicBlocks; // set on demand + BitSet handlers; // set on demand + BitSet branches; // set on demand + BitSet branchTrue; + BitSet branchFalse; + + MethodCoverage(MethodInfo mi) { + this.mi = mi; + log.info("add method: " + mi.getUniqueName()); + } + + MethodInfo getMethodInfo() { + return mi; + } + + void setExecuted(ThreadInfo ti, Instruction insn) { + int idx = ti.getId(); + + if (covered == null) { + covered = new BitSet[idx + 1]; + } else if (idx >= covered.length) { + BitSet[] a = new BitSet[idx + 1]; + System.arraycopy(covered, 0, a, 0, covered.length); + covered = a; + } + + if (covered[idx] == null) { + covered[idx] = new BitSet(mi.getInstructions().length); + } + + int off = insn.getInstructionIndex(); + covered[idx].set(off); + + if (showBranchCoverage && (insn instanceof IfInstruction)) { + if (branchTrue == null) { + branchTrue = new BitSet(mi.getInstructions().length); + branchFalse = new BitSet(branchTrue.size()); + } + if (!((IfInstruction) insn).getConditionValue()) { + branchTrue.set(off); + } else { + branchFalse.set(off); + } + } + } + + void setCGed(ThreadInfo ti, Instruction insn) { + ti = null; // Remove IDE warning about unused variable. + // Hmm, we have to store the bb set at this point + BitSet bb = getBasicBlocks(); + Instruction next = insn.getNext(); + if (next != null) { // insn might be a sync return + bb.set(next.getInstructionIndex()); + } + } + + BitSet getExecutedInsn() { + int nTotal = mi.getInstructions().length; + BitSet bUnion = new BitSet(nTotal); + + if (covered != null) { + for (BitSet b : covered) { + if (b != null) { + bUnion.or(b); + } + } + } + + return bUnion; + } + + Coverage getCoveredInsn() { + int nTotal = mi.getInstructions().length; + + if (excludeHandlers) { + nTotal -= getHandlers().cardinality(); + } + + if (covered != null) { + BitSet bExec = getExecutedInsn(); + if (excludeHandlers) { + bExec.andNot(getHandlers()); + } + return new Coverage(nTotal, bExec.cardinality()); + } else { + return new Coverage(nTotal, 0); + } + } + + Coverage getCoveredLines() { + BitSet executable = new BitSet(); + BitSet covered = new BitSet(); + + getCoveredLines(executable, covered); + + return new Coverage(executable.cardinality(), covered.cardinality()); + } + + boolean getCoveredLines(BitSet executable, BitSet covered) { + Instruction inst[] = mi.getInstructions(); + BitSet insn; + int i, line; + + if (covered == null) { + return false; + } + + insn = getExecutedInsn(); + if (excludeHandlers) { + insn.andNot(getHandlers()); + } + + if (branchTrue != null) { + for (i = branchTrue.length() - 1; i >= 0; i--) { + boolean cTrue = branchTrue.get(i); + boolean cFalse = branchFalse.get(i); + + if ((!cTrue || !cFalse) && (inst[i] instanceof IfInstruction)) { + insn.clear(i); + } + } + } + + for (i = inst.length - 1; i >= 0; i--) { + line = inst[i].getLineNumber(); + + if (line > 0) { + executable.set(line); + covered.set(line); + } + } + + for (i = inst.length - 1; i >= 0; i--) { + line = inst[i].getLineNumber(); + if ((!insn.get(i)) && (line > 0)) { // TODO What do we do with instructions that don't have a line number. Is this even possible? + covered.clear(line); + } + } + + return true; + } + + Coverage getCoveredBranches() { + BitSet b = getBranches(); + int nTotal = b.cardinality(); + int nCovered = 0; + + if (branchTrue != null) { + int n = branchTrue.size(); + + for (int i = 0; i < n; i++) { + boolean cTrue = branchTrue.get(i); + boolean cFalse = branchFalse.get(i); + + if (cTrue && cFalse) { + nCovered++; + } + } + } + + return new Coverage(nTotal, nCovered); + } + + BitSet getHandlerStarts() { + BitSet b = new BitSet(mi.getInstructions().length); + ExceptionHandler[] handler = mi.getExceptions(); + + if (handler != null) { + for (int i = 0; i < handler.length; i++) { + Instruction hs = mi.getInstructionAt(handler[i].getHandler()); + b.set(hs.getInstructionIndex()); + } + } + + return b; + } + + BitSet getHandlers() { + // this algorithm is a bit subtle - we walk through the code until + // we hit a forward GOTO (or RETURN). If the insn following the goto is the + // beginning of a handler, we mark everything up to the jump address + // as a handler block + + if (handlers == null) { + BitSet hs = getHandlerStarts(); + Instruction[] code = mi.getInstructions(); + BitSet b = new BitSet(code.length); + + if (!hs.isEmpty()) { + for (int i = 0; i < code.length; i++) { + Instruction insn = code[i]; + if (insn instanceof GOTO) { + GOTO gotoInsn = (GOTO) insn; + if (!gotoInsn.isBackJump() && hs.get(i + 1)) { // jump around handler + int handlerEnd = gotoInsn.getTarget().getInstructionIndex(); + for (i++; i < handlerEnd; i++) { + b.set(i); + } + } + } else if (insn instanceof JVMReturnInstruction) { // everything else is handler + for (i++; i < code.length; i++) { + b.set(i); + } + } + } + } + + handlers = b; + } + + return handlers; + } + + // that's kind of redundant with basic blocks, but not really - here + // we are interested in the logic behind branches, i.e. we want to know + // what the condition values were. We are not interested in GOTOs and exceptions + BitSet getBranches() { + if (branches == null) { + Instruction[] code = mi.getInstructions(); + BitSet br = new BitSet(code.length); + + for (int i = 0; i < code.length; i++) { + Instruction insn = code[i]; + if (insn instanceof IfInstruction) { + br.set(i); + } + } + + branches = br; + } + + return branches; + } + + BitSet getBasicBlocks() { + if (basicBlocks == null) { + Instruction[] code = mi.getInstructions(); + BitSet bb = new BitSet(code.length); + + bb.set(0); // first insn is always a bb start + + // first, look at the insn type + for (int i = 0; i < code.length; i++) { + Instruction insn = code[i]; + if (insn instanceof IfInstruction) { + IfInstruction ifInsn = (IfInstruction) insn; + + Instruction tgt = ifInsn.getTarget(); + bb.set(tgt.getInstructionIndex()); + + tgt = ifInsn.getNext(); + bb.set(tgt.getInstructionIndex()); + } else if (insn instanceof GOTO) { + Instruction tgt = ((GOTO) insn).getTarget(); + bb.set(tgt.getInstructionIndex()); + } else if (insn instanceof JVMInvokeInstruction) { + // hmm, this might be a bit too conservative, but who says we + // don't jump out of a caller into a handler, or even that we + // ever return from the call? + Instruction tgt = insn.getNext(); + bb.set(tgt.getInstructionIndex()); + } + } + + // and now look at the handlers (every first insn is a bb start) + ExceptionHandler[] handlers = mi.getExceptions(); + if (handlers != null) { + for (int i = 0; i < handlers.length; i++) { + Instruction tgt = mi.getInstructionAt(handlers[i].getHandler()); + bb.set(tgt.getInstructionIndex()); + } + } + + basicBlocks = bb; + + /** dump + System.out.println(); + System.out.println(mi.getFullName()); + for (int i=0; i' : ' ')); + System.out.println(code[i]); + } + **/ + } + + return basicBlocks; + } + + Coverage getCoveredBasicBlocks() { + BitSet bExec = getExecutedInsn(); + BitSet bb = getBasicBlocks(); + int nCov = 0; + + if (excludeHandlers) { + BitSet handlers = getHandlers(); + bb.and(handlers); + } + + if (bExec != null) { + BitSet bCov = new BitSet(bb.size()); + bCov.or(bb); + bCov.and(bExec); + nCov = bCov.cardinality(); + } + + return new Coverage(bb.cardinality(), nCov); + } + } + + static class ClassCoverage { + + String className; // need to store since we never might get a ClassInfo + ClassInfo ci; // not initialized before the class is loaded + boolean covered; + HashMap methods; + + ClassCoverage(String className) { + this.className = className; + } + + void setLoaded(ClassInfo ci) { + if (methods == null) { + this.ci = ci; + covered = true; + log.info("used class: " + className); + + methods = new HashMap(); + for (MethodInfo mi : ci.getDeclaredMethodInfos()) { + // <2do> what about MJI methods? we should report why we don't cover them + if (!mi.isNative() && !mi.isAbstract()) { + MethodCoverage mc = new MethodCoverage(mi); + methods.put(mi, mc); + } + } + } + } + + boolean isInterface() { + if (ci == null) // never loaded + if (!isCodeLoaded()) // can it be loaded? + return false; // will never load + + return ci.isInterface(); + } + + boolean isCodeLoaded() { + if (ci != null) + return true; + + try { + ci = ClassLoaderInfo.getCurrentResolvedClassInfo(className); + } catch (ClassInfoException cie) { + log.warning("CoverageAnalyzer problem: " + cie); // Just log the problem but don't fail. We still want the report to be written. + } + + return ci != null; + } + + MethodCoverage getMethodCoverage(MethodInfo mi) { + if (methods == null) { + setLoaded(ci); + } + return methods.get(mi); + } + + Coverage getCoveredMethods() { + Coverage cov = new Coverage(0, 0); + + if (methods != null) { + cov.total = methods.size(); + + for (MethodCoverage mc : methods.values()) { + if (mc.covered != null) { + cov.covered++; + } + } + } + + return cov; + } + + Coverage getCoveredInsn() { + Coverage cov = new Coverage(0, 0); + + if (methods != null) { + for (MethodCoverage mc : methods.values()) { + Coverage c = mc.getCoveredInsn(); + cov.total += c.total; + cov.covered += c.covered; + } + } + + return cov; + } + + boolean getCoveredLines(BitSet executable, BitSet covered) { + boolean result = false; + + if (methods == null) { + return false; + } + + for (MethodCoverage mc : methods.values()) { + result = mc.getCoveredLines(executable, covered) || result; + } + + return result; + } + + Coverage getCoveredLines() { + BitSet executable = new BitSet(); + BitSet covered = new BitSet(); + + getCoveredLines(executable, covered); + + return new Coverage(executable.cardinality(), covered.cardinality()); + } + + Coverage getCoveredBasicBlocks() { + Coverage cov = new Coverage(0, 0); + + if (methods != null) { + for (MethodCoverage mc : methods.values()) { + Coverage c = mc.getCoveredBasicBlocks(); + cov.total += c.total; + cov.covered += c.covered; + } + } + + return cov; + } + + Coverage getCoveredBranches() { + Coverage cov = new Coverage(0, 0); + + if (methods != null) { + for (MethodCoverage mc : methods.values()) { + Coverage c = mc.getCoveredBranches(); + cov.total += c.total; + cov.covered += c.covered; + } + } + + return cov; + } + } + + StringSetMatcher includes = null; // means all + StringSetMatcher excludes = null; // means none + StringSetMatcher loaded; + static boolean loadedOnly; // means we only check loaded classes that are not filtered + static boolean showMethods; // do we want to show per-method coverage? + static boolean showMethodBodies; + static boolean excludeHandlers; // do we count the handlers in? (off-nominal CF) + static boolean showBranchCoverage; // makes only sense with showMethods + static boolean showRequirements; // report requirements coverage + HashMap classes = new HashMap(); + + public CoverageAnalyzer(Config conf, JPF jpf) { + includes = StringSetMatcher.getNonEmpty(conf.getStringArray("coverage.include")); + excludes = StringSetMatcher.getNonEmpty(conf.getStringArray("coverage.exclude")); + + showMethods = conf.getBoolean("coverage.show_methods", false); + showMethodBodies = conf.getBoolean("coverage.show_bodies", false); + excludeHandlers = conf.getBoolean("coverage.exclude_handlers", false); + showBranchCoverage = conf.getBoolean("coverage.show_branches", true); + loadedOnly = conf.getBoolean("coverage.loaded_only", true); + showRequirements = conf.getBoolean("coverage.show_requirements", false); + + if (!loadedOnly) { + getCoverageCandidates(); // this might take a little while + } + + jpf.addPublisherExtension(ConsolePublisher.class, this); + } + + void getCoverageCandidates() { + + // doesn't matter in which order we process this, since we + // just store one entry per qualified class name (i.e. there won't be + // multiple entries) + // NOTE : this doesn't yet deal with ClassLoaders, but that's also true for BCEL + ClassLoaderInfo cl = ClassLoaderInfo.getCurrentClassLoader(); + for (String s : cl.getClassPathElements()) { + log.fine("analyzing classpath element: " + s); + File f = new File(s); + if (f.exists()) { + if (f.isDirectory()) { + traverseDir(f, null); + } else if (s.endsWith(".jar")) { + traverseJar(f); + } + } + } + } + + void addClassEntry(String clsName) { + ClassCoverage cc = new ClassCoverage(clsName); + classes.put(clsName, cc); + log.info("added class candidate: " + clsName); + } + + boolean isAnalyzedClass(String clsName) { + return StringSetMatcher.isMatch(clsName, includes, excludes); + } + + void traverseDir(File dir, String pkgPrefix) { + for (File f : dir.listFiles()) { + if (f.isDirectory()) { + String prefix = f.getName(); + if (pkgPrefix != null) { + prefix = pkgPrefix + '.' + prefix; + } + traverseDir(f, prefix); + } else { + String fname = f.getName(); + if (fname.endsWith(".class")) { + if (f.canRead() && (f.length() > 0)) { + String clsName = fname.substring(0, fname.length() - 6); + if (pkgPrefix != null) { + clsName = pkgPrefix + '.' + clsName; + } + + if (isAnalyzedClass(clsName)) { + addClassEntry(clsName); + } + } else { + log.warning("cannot read class file: " + fname); + } + } + } + } + } + + void traverseJar(File jar) { + try { + JarFile jf = new JarFile(jar); + for (Enumeration entries = jf.entries(); entries.hasMoreElements();) { + JarEntry e = entries.nextElement(); + if (!e.isDirectory()) { + String eName = e.getName(); + if (eName.endsWith(".class")) { + if (e.getSize() > 0) { + String clsName = eName.substring(0, eName.length() - 6); + clsName = clsName.replace('/', '.'); + if (isAnalyzedClass(clsName)) { + addClassEntry(clsName); + } + } else { + log.warning("cannot read jar entry: " + eName); + } + } + } + } + } catch (IOException iox) { + iox.printStackTrace(); + } + } + + + HashMap getGlobalRequirementsMethods() { + HashMap map = new HashMap(); + + // <2do> this is extremely braindead, since inefficient + // it would be much better to do this with Class instead of ClassInfo, but + // then we need a JPF- ClassLoader, since the path might be different. As a + // middle ground, we could use BCEL + + for (ClassCoverage cc : classes.values()) { + ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(cc.className); + for (MethodInfo mi : ci.getDeclaredMethodInfos()) { + AnnotationInfo ai = getRequirementsAnnotation(mi); + if (ai != null) { + for (String id : ai.getValueAsStringArray()) { + Integer n = map.get(id); + if (n == null) { + map.put(id, 1); + } else { + map.put(id, n + 1); + } + } + } + } + } + + return map; + } + + int computeTotalRequirementsMethods(HashMap map) { + int n = 0; + for (Integer i : map.values()) { + n += i; + } + return n; + } + + private void computeCoverages(String packageFilter, List> clsEntries, Coverage cls, Coverage mth, Coverage branch, Coverage block, Coverage line, Coverage insn) { + for (Map.Entry e : clsEntries) { + if (e.getKey().startsWith(packageFilter)) { + ClassCoverage cc = e.getValue(); + + if (cc.isInterface()) { + continue; // no code + } + + cls.total++; + + if (cc.covered) { + cls.covered++; + } + + insn.add(cc.getCoveredInsn()); + line.add(cc.getCoveredLines()); + block.add(cc.getCoveredBasicBlocks()); + branch.add(cc.getCoveredBranches()); + mth.add(cc.getCoveredMethods()); + } + } + } + + + /** + * print uncovered source ranges + */ + + //-------- the listener interface + @Override + public void classLoaded(VM vm, ClassInfo ci) { + String clsName = ci.getName(); + + if (loadedOnly) { + if (isAnalyzedClass(clsName)) { + addClassEntry(clsName); + } + } + + ClassCoverage cc = classes.get(clsName); + if (cc != null) { + cc.setLoaded(ci); + } + } + MethodInfo lastMi = null; + MethodCoverage lastMc = null; + + MethodCoverage getMethodCoverage(Instruction insn) { + + if (!insn.isExtendedInstruction()) { + MethodInfo mi = insn.getMethodInfo(); + if (mi != lastMi) { + lastMc = null; + lastMi = mi; + ClassInfo ci = mi.getClassInfo(); + if (ci != null) { + ClassCoverage cc = classes.get(ci.getName()); + if (cc != null) { + lastMc = cc.getMethodCoverage(mi); + } + } + } + + return lastMc; + } + + return null; + } + HashMap> requirements; + + void updateRequirementsCoverage(String[] ids, MethodCoverage mc) { + if (requirements == null) { + requirements = new HashMap>(); + } + + for (String id : ids) { + HashSet mcs = requirements.get(id); + if (mcs == null) { + mcs = new HashSet(); + requirements.put(id, mcs); + } + + if (!mcs.contains(mc)) { + mcs.add(mc); + } + } + } + + AnnotationInfo getRequirementsAnnotation(MethodInfo mi) { + // <2do> should probably look for overridden method annotations + return mi.getAnnotation("gov.nasa.jpf.Requirement"); + } + + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + MethodCoverage mc = getMethodCoverage(executedInsn); + + if (mc != null) { + mc.setExecuted(ti, executedInsn); + + if (showRequirements) { + if (executedInsn.getPosition() == 0) { // first insn in method, check for Requirements + AnnotationInfo ai = getRequirementsAnnotation(mc.getMethodInfo()); + if (ai != null) { + String[] ids = ai.getValueAsStringArray(); + updateRequirementsCoverage(ids, mc); + } + } + } + } + } + + @Override + public void choiceGeneratorSet(VM vm, ChoiceGenerator newCG) { + /*** should be an option + Instruction insn = vm.getLastInstruction(); + MethodCoverage mc = getMethodCoverage(vm); + mc.setCGed(vm.getLastThreadInfo(),insn); + ***/ + } + + //-------- the publisher interface + private Publisher publisher; + private ArrayList> clsEntries; + + + abstract class Publish { + PrintWriter pw; + + Publish () {} + Publish (Publisher p){ + pw = p.getOut(); + } + + abstract void publish(); + abstract void printClassCoverages(); + abstract void printRequirementsCoverage(); + } + + class PublishConsole extends Publish { + PublishConsole (ConsolePublisher p){ + super(p); + } + + @Override + void publish() { + publisher.publishTopicStart("coverage statistics"); + + printClassCoverages(); + + if (showRequirements) { + printRequirementsCoverage(); + } + + } + + void printCoverage (Coverage cov){ + int nTotal = cov.total(); + int nCovered = cov.covered(); + + String s; + if (nTotal <= 0) { + s = " - "; + } else { + s = String.format("%.2f (%d/%d)", ((double) nCovered / nTotal), nCovered, nTotal); + } + pw.print(String.format("%1$-18s", s)); + } + + + @Override + void printClassCoverages() { + String space = " "; + Coverage clsCoverage = new Coverage(0, 0); + Coverage mthCoverage = new Coverage(0, 0); + Coverage bbCoverage = new Coverage(0, 0); + Coverage lineCoverage = new Coverage(0, 0); + Coverage insnCoverage = new Coverage(0, 0); + Coverage branchCoverage = new Coverage(0, 0); + + computeCoverages("", clsEntries, clsCoverage, mthCoverage, branchCoverage, bbCoverage, lineCoverage, insnCoverage); + + pw.println(); + pw.println("-------------------------------------------- class coverage ------------------------------------------------"); + pw.println("bytecode line basic-block branch methods location"); + pw.println("------------------------------------------------------------------------------------------------------------"); + + // Write Body + for (Map.Entry e : clsEntries) { + ClassCoverage cc = e.getValue(); + + printCoverage(cc.getCoveredInsn()); + pw.print(space); + + printCoverage(cc.getCoveredLines()); + pw.print(space); + + printCoverage(cc.getCoveredBasicBlocks()); + pw.print(space); + + printCoverage(cc.getCoveredBranches()); + pw.print(space); + + printCoverage(cc.getCoveredMethods()); + pw.print(space); + + pw.println(e.getKey()); + + if (showMethods) { + printMethodCoverages(cc); + } + } + + pw.println(); + pw.println("------------------------------------------------------------------------------------------------------------"); + + printCoverage(insnCoverage); + pw.print(space); + printCoverage(lineCoverage); + pw.print(space); + printCoverage(bbCoverage); + pw.print(space); + printCoverage(branchCoverage); + pw.print(space); + printCoverage(mthCoverage); + pw.print(space); + printCoverage(clsCoverage); + pw.println(" total"); + + } + + @Override + void printRequirementsCoverage() { + HashMap reqMethods = getGlobalRequirementsMethods(); + + String space = " "; + Coverage bbAll = new Coverage(0, 0); + Coverage insnAll = new Coverage(0, 0); + Coverage branchAll = new Coverage(0, 0); + Coverage mthAll = new Coverage(0, 0); + Coverage reqAll = new Coverage(0, 0); + + reqAll.total = reqMethods.size(); + mthAll.total = computeTotalRequirementsMethods(reqMethods); + + pw.println(); + pw.println(); + pw.println("--------------------------------- requirements coverage -----------------------------------"); + pw.println("bytecode basic-block branch methods requirement"); + pw.println("-------------------------------------------------------------------------------------------"); + + for (String id : Misc.getSortedKeyStrings(reqMethods)) { + + Coverage bbCoverage = new Coverage(0, 0); + Coverage insnCoverage = new Coverage(0, 0); + Coverage branchCoverage = new Coverage(0, 0); + Coverage reqMth = new Coverage(reqMethods.get(id), 0); + + if (requirements != null && requirements.containsKey(id)) { + reqAll.covered++; + for (MethodCoverage mc : requirements.get(id)) { + insnCoverage.add(mc.getCoveredInsn()); + bbCoverage.add(mc.getCoveredBasicBlocks()); + branchCoverage.add(mc.getCoveredBranches()); + + mthAll.covered++; + reqMth.covered++; + } + + + printCoverage(insnCoverage); + pw.print(space); + printCoverage(bbCoverage); + pw.print(space); + printCoverage(branchCoverage); + pw.print(space); + printCoverage(reqMth); + pw.print("\"" + id + "\""); + + + pw.println(); + + if (showMethods) { + for (MethodCoverage mc : requirements.get(id)) { + + pw.print(space); + printCoverage(mc.getCoveredInsn()); + pw.print(space); + printCoverage(mc.getCoveredBasicBlocks()); + pw.print(space); + printCoverage(mc.getCoveredBranches()); + pw.print(space); + + pw.print(mc.getMethodInfo().getFullName()); + pw.println(); + } + } + } else { // requirement not covered + pw.print(" - - - "); + + printCoverage(reqMth); + pw.print("\"" + id + "\""); + pw.println(); + } + + insnAll.add(insnCoverage); + bbAll.add(bbCoverage); + branchAll.add(branchCoverage); + } + + pw.println(); + pw.println("------------------------------------------------------------------------------------------"); + + printCoverage(insnAll); + pw.print(space); + printCoverage(bbAll); + pw.print(space); + printCoverage(branchAll); + pw.print(space); + printCoverage(mthAll); + pw.print(space); + printCoverage(reqAll); + pw.print(" total"); + + pw.println(); + } + + void printMethodCoverages(ClassCoverage cc) { + String space = " "; + boolean result = true; + + if (cc.methods == null) { + return; + } + + ArrayList> mthEntries = + Misc.createSortedEntryList(cc.methods, new Comparator>() { + + @Override + public int compare(Map.Entry o1, + Map.Entry o2) { + int a = o2.getValue().getCoveredInsn().percent(); + int b = o1.getValue().getCoveredInsn().percent(); + + if (a == b) { + return o2.getKey().getUniqueName().compareTo(o1.getKey().getUniqueName()); + } else { + return a - b; + } + } + }); + + Coverage emptyCoverage = new Coverage(0, 0); + + for (Map.Entry e : mthEntries) { + MethodCoverage mc = e.getValue(); + MethodInfo mi = mc.getMethodInfo(); + Coverage insnCoverage = mc.getCoveredInsn(); + Coverage lineCoverage = mc.getCoveredLines(); + Coverage branchCoverage = mc.getCoveredBranches(); + + result = result && insnCoverage.isFullyCovered(); + + + pw.print(space); + printCoverage(insnCoverage); + + pw.print(space); + printCoverage(lineCoverage); + + pw.print(space); + printCoverage(mc.getCoveredBasicBlocks()); + + pw.print(space); + printCoverage(branchCoverage); + + pw.print(space); + printCoverage(emptyCoverage); + + pw.print(space); + pw.print(mi.getLongName()); + pw.println(); + + if (showMethodBodies && + (!insnCoverage.isFullyCovered() || !branchCoverage.isFullyCovered())) { + printBodyCoverage(mc); + } + } + } + + void printBodyCoverage(MethodCoverage mc) { + MethodInfo mi = mc.getMethodInfo(); + Instruction[] code = mi.getInstructions(); + BitSet cov = mc.getExecutedInsn(); + int i, start = -1; + + BitSet handlers = mc.getHandlers(); + + if (excludeHandlers) { + cov.andNot(handlers); + } + + for (i = 0; i < code.length; i++) { + if (!cov.get(i)) { // not covered + if (start == -1) { + start = i; + } + } else { // covered + if (start != -1) { + printSourceRange(code, handlers, start, i - 1, ""); + start = -1; + } + } + } + if (start != -1) { + printSourceRange(code, handlers, start, i - 1, ""); + } + + // now print the missing branches + BitSet branches = mc.getBranches(); + lastStart = -1; // reset in case condition and branch are in same line + for (i = 0; i < code.length; i++) { + if (branches.get(i)) { + String prefix = ""; + BitSet bTrue = mc.branchTrue; + BitSet bFalse = mc.branchFalse; + if (bTrue != null) { // means we have condition bit sets + boolean cTrue = bTrue.get(i); + boolean cFalse = bFalse.get(i); + if (cTrue) { + prefix = cFalse ? "" : "F "; // covered or false missing + } else { + prefix = cFalse ? "T " : "N "; // true or both missing + } + } else { + prefix = "N "; // not covered at all + } + + if (prefix != null) { + printSourceRange(code, handlers, i, i, prefix); + } + } + } + } + + // there might be several ranges within the same source line + int lastStart = -1; + + void printSourceRange(Instruction[] code, BitSet handlers, + int start, int end, String prefix) { + + int line = code[start].getLineNumber(); + + if (lastStart == line) { + return; + } + + lastStart = line; + + printLocation(prefix, "at", code[start].getSourceLocation(), handlers.get(start) ? "x" : ""); + + if (line != code[end].getLineNumber()) { + printLocation(prefix, "..", code[end].getSourceLocation(), handlers.get(end) ? "x" : ""); + } + // we need the "(..)" wrapper so that Eclipse parses this + // as a source location when displaying the report in a console + } + + private void printLocation(String prefix, String at, String location, String suffix) { + + printBlanks(pw, 84); + pw.print(prefix); + pw.print(at); + pw.print(' '); + pw.print(location); + pw.print(' '); + pw.println(suffix); + } + + void printBlanks(PrintWriter pw, int n) { + for (int i = 0; i < n; i++) { + pw.print(' '); + } + } + + } + + + @Override + public void publishFinished(Publisher publisher) { + + if (clsEntries == null) { + clsEntries = Misc.createSortedEntryList(classes, new Comparator>() { + + @Override + public int compare(Map.Entry o1, + Map.Entry o2) { + return o2.getKey().compareTo(o1.getKey()); + } + }); + } + + this.publisher = publisher; + + if (publisher instanceof ConsolePublisher) { + new PublishConsole((ConsolePublisher) publisher).publish(); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/DeadlockAnalyzer.java b/src/main/gov/nasa/jpf/listener/DeadlockAnalyzer.java new file mode 100644 index 0000000..e434d17 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/DeadlockAnalyzer.java @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.EXECUTENATIVE; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.ListIterator; +import java.util.Stack; + +/** + * example of a listener that creates property specific traces. The interesting + * thing is that it does so without the need to store steps, i.e. it maintains + * it's own transition stack. + * this is still work in progress, analyzing the trace can be much more + * elaborate (we just dump up to a max history size for now) + * + * <2do> DeadlockAnalyzer output can be confusing if a reorganizing + * ThreadList is used (which reassigns thread ids) + */ +public class DeadlockAnalyzer extends ListenerAdapter { + + enum OpType { block, lock, unlock, wait, notify, notifyAll, started, terminated }; + static String[] opTypeMnemonic = { "B", "L", "U", "W", "N", "A", "S", "T" }; + + static class ThreadOp { + ThreadInfo ti; + ElementInfo ei; + Instruction insn; + + // kind of redundant, but there might be context attributes in addition + // to the insn itself + OpType opType; + + // we could identify this with the insn, but only in case this is + // a transition boundary, which is far less general than we can be + int stateId; + ThreadOp prevTransition; + ThreadOp prevOp; + + ThreadOp (ThreadInfo ti, ElementInfo ei, OpType type) { + this.ti = ti; + this.ei = ei; + insn = getReportInsn(ti); // we haven't had the executeInsn notification yet + opType = type; + + prevOp = null; + } + + Instruction getReportInsn(ThreadInfo ti){ + StackFrame frame = ti.getTopFrame(); + if (frame != null) { + Instruction insn = frame.getPC(); + if (insn instanceof EXECUTENATIVE) { + frame = frame.getPrevious(); + if (frame != null) { + insn = frame.getPC(); + } + } + + return insn; + } else { + return null; + } + } + + void printLocOn (PrintWriter pw) { + pw.print(String.format("%6d", new Integer(stateId))); + + if (insn != null) { + pw.print(String.format(" %18.18s ", insn.getMnemonic())); + pw.print(insn.getFileLocation()); + String line = insn.getSourceLine(); + if (line != null){ + pw.print( " : "); + pw.print(line.trim()); + //pw.print(insn); + } + } + } + + void printOn (PrintWriter pw){ + pw.print( stateId); + pw.print( " : "); + pw.print( ti.getName()); + pw.print( " : "); + pw.print( opType.name()); + pw.print( " : "); + pw.println(ei); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append( stateId); + sb.append( " : "); + sb.append( ti.getName()); + sb.append( " : "); + sb.append( opType.name()); + sb.append( " : "); + sb.append(ei); + return sb.toString(); + } + + void printColumnOn(PrintWriter pw, Collection tlist){ + for (ThreadInfo t : tlist) { + if (ti == t) { + if (opType == OpType.started || opType == OpType.terminated) { + pw.print(String.format(" %1$s ", opTypeMnemonic[opType.ordinal()])); + } else { + pw.print(String.format("%1$s:%2$-5x ", opTypeMnemonic[opType.ordinal()], ei.getObjectRef())); + } + //break; + } else { + pw.print(" | "); + } + } + } + } + + ThreadOp lastOp; + ThreadOp lastTransition; + + int maxHistory; + String format; + + VM vm; + Search search; + + public DeadlockAnalyzer (Config config, JPF jpf){ + jpf.addPublisherExtension(ConsolePublisher.class, this); + + maxHistory = config.getInt("deadlock.max_history", Integer.MAX_VALUE); + format = config.getString("deadlock.format", "essential"); + + vm = jpf.getVM(); + search = jpf.getSearch(); + } + + boolean requireAllOps() { + return (format.equalsIgnoreCase("essential")); + } + + void addOp (ThreadInfo ti, ElementInfo ei, OpType opType){ + ThreadOp op = new ThreadOp(ti, ei, opType); + if (lastOp == null){ + lastOp = op; + } else { + assert lastOp.stateId == 0; + + op.prevOp = lastOp; + lastOp = op; + } + } + + void printRawOps (PrintWriter pw) { + int i=0; + + for (ThreadOp tOp = lastTransition; tOp != null; tOp = tOp.prevTransition){ + for (ThreadOp op = tOp; op != null; op=op.prevOp) { + if (i++ >= maxHistory){ + pw.println("..."); + return; + } + op.printOn(pw); + } + } + } + + /** + * include all threads that are currently blocked or waiting, and + * all the threads that had the last interaction with them. Note that + * we do this completely on the basis of the recorded ThreadOps, i.e. + * don't rely on when this is called + */ + void printEssentialOps(PrintWriter pw) { + LinkedHashSet threads = new LinkedHashSet(); + ArrayList ops = new ArrayList(); + HashMap waits = new HashMap(); + HashMap blocks = new HashMap(); + HashSet runnables = new HashSet(); + + // collect all relevant threads and ops + for (ThreadOp trans = lastTransition; trans != null; trans = trans.prevTransition){ + for (ThreadOp tOp = trans; tOp != null; tOp = tOp.prevOp) { + OpType ot = tOp.opType; + ThreadInfo oti = tOp.ti; + + if (ot == OpType.wait || ot == OpType.block) { + if (!runnables.contains(oti) && !threads.contains(oti)){ + HashMap map = (ot == OpType.block) ? blocks : waits; + threads.add(oti); + map.put(tOp.ei, oti); + ops.add(tOp); + } + + } else if (ot == OpType.notify || ot == OpType.notifyAll || ot == OpType.lock) { + HashMap map = (ot == OpType.lock) ? blocks : waits; + ThreadInfo ti = map.get(tOp.ei); + + if (ti != null && ti != oti){ + if (!threads.contains(oti)){ + threads.add(oti); + } + map.remove(tOp.ei); + ops.add(tOp); + } + + runnables.add(oti); + + } else if (ot == OpType.unlock) { + // not relevant + runnables.add(oti); + + } else if (ot == OpType.terminated || ot == OpType.started) { + ops.add(tOp); // might be removed later-on + } + } + } + + // remove all starts/terminates of irrelevant threads + for (ListIterator it = ops.listIterator(); it.hasNext(); ){ + ThreadOp tOp = it.next(); + if (tOp.opType == OpType.terminated || tOp.opType == OpType.started) { + if (!threads.contains(tOp.ti)){ + it.remove(); + } + } + } + + // now we are ready to print + printHeader(pw,threads); + + for (ThreadOp tOp : ops) { + tOp.printColumnOn(pw,threads); + tOp.printLocOn(pw); + pw.println(); + } + } + + + Collection getThreadList() { + ArrayList tcol = new ArrayList(); + boolean allOps = requireAllOps(); + int i=0; + + prevTrans: + for (ThreadOp tOp = lastTransition; tOp != null; tOp = tOp.prevTransition){ + i++; + if (!allOps && (i >= maxHistory)){ + break; + } + + for (ThreadInfo ti : tcol) { + if (ti == tOp.ti) continue prevTrans; + } + tcol.add(tOp.ti); + } + + return tcol; + } + + void printHeader (PrintWriter pw, Collection tlist){ + for (ThreadInfo ti : tlist){ + pw.print(String.format(" %1$2d ", ti.getId())); + } + pw.print(" trans insn loc : stmt"); + pw.println(); + + for (int i=0; i tlist = getThreadList(); + printHeader(pw,tlist); + + // and now the data + for (ThreadOp tOp = lastTransition; tOp != null; tOp = tOp.prevTransition){ + for (ThreadOp op = tOp; op != null; op=op.prevOp) { + if (i++ >= maxHistory){ + pw.println("..."); + return; + } + + op.printColumnOn(pw,tlist); + op.printLocOn(pw); + pw.println(); + } + } + } + + /** + * this is the workhorse - filter which ops should be shown, and which + * are irrelevant for the deadlock + */ + boolean showOp (ThreadOp op, ThreadInfo[] tlist, + boolean[] waitSeen, boolean[] notifySeen, + boolean[] blockSeen, boolean[] lockSeen, + Stack[] unlocked) { + ThreadInfo ti = op.ti; + ElementInfo ei = op.ei; + int idx; + for (idx=0; idx < tlist.length; idx++){ + if (tlist[idx] == ti) break; + } + + // we could delegate this to the enum type, but let's not be too fancy + switch (op.opType) { + case block: + // only report the last one if thread is blocked + if (ti.isBlocked()) { + if (!blockSeen[idx]) { + blockSeen[idx] = true; + return true; + } + } + return false; + + case unlock: + unlocked[idx].push(ei); + return false; + + case lock: + // if we had a corresponding unlock, ignore + if (!unlocked[idx].isEmpty() && (unlocked[idx].peek() == ei)) { + unlocked[idx].pop(); + return false; + } + + // only report the last one if there is a thread that's currently blocked on it + for (int i=0; i stateId)){ + lastTransition = lastTransition.prevTransition; + } + lastOp = null; + } + + // for HeuristicSearches. Ok, that's braindead but at least no need for cloning + HashMap storedTransition = new HashMap(); + + @Override + public void stateStored (Search search) { + // always called after stateAdvanced + storedTransition.put(search.getStateId(), lastTransition); + } + + @Override + public void stateRestored (Search search) { + int stateId = search.getStateId(); + ThreadOp op = storedTransition.get(stateId); + if (op != null) { + lastTransition = op; + storedTransition.remove(stateId); // not strictly required, but we don't come back + } + } + + @Override + public void publishPropertyViolation (Publisher publisher) { + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("thread ops " + publisher.getLastErrorId()); + + if ("column".equalsIgnoreCase(format)){ + printColumnOps(pw); + } else if ("essential".equalsIgnoreCase(format)) { + printEssentialOps(pw); + } else { + printRawOps(pw); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/DistributedSimpleDot.java b/src/main/gov/nasa/jpf/listener/DistributedSimpleDot.java new file mode 100644 index 0000000..d41a8c4 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/DistributedSimpleDot.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.jvm.bytecode.DIRECTCALLRETURN; +import gov.nasa.jpf.jvm.bytecode.EXECUTENATIVE; +import gov.nasa.jpf.jvm.bytecode.JVMFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.LockInstruction; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.GlobalSchedulingPoint; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; + +/** + * This is a Graphviz dot-file generator similar to SimpleDot. It is useful in + * the case of Multiprocess applications. It distinguishes local choices from global + * choices. + * + * @author Nastaran Shafiei + */ +public class DistributedSimpleDot extends SimpleDot { + + static final String MP_START_NODE_ATTRS = "shape=octagon,fillcolor=green"; + static final String MP_NODE_ATTRS = "shape=octagon,fillcolor=azure2"; + + protected String mpNodeAttrs; + protected String mpStartNodeAttrs; + + protected Instruction insn; + + public DistributedSimpleDot (Config config, JPF jpf) { + super(config, jpf); + + mpNodeAttrs = config.getString("dot.mp_node_attr", MP_NODE_ATTRS); + startNodeAttrs = config.getString("dot.mp_start_node_attr", MP_START_NODE_ATTRS); + } + + @Override + public void instructionExecuted(VM vm, ThreadInfo currentThread, Instruction nextInstruction, Instruction executedInstruction) { + insn = executedInstruction; + } + + @Override + public void stateAdvanced(Search search){ + int id = search.getStateId(); + long edgeId = ((long)lastId << 32) | id; + + String prcId = "P"+Integer.toString(search.getVM().getCurrentApplicationContext().getId()); + if (id <0 || seenEdges.contains(edgeId)){ + return; // skip the root state and property violations (reported separately) + } + + String lastInst = getNextCG(); + String choice = prcId+"."+getLastChoice(); + + if (search.isErrorState()) { + String eid = "e" + search.getNumberOfErrors(); + printTransition(getStateId(lastId), eid, choice, getError(search)); + printErrorState(eid); + lastErrorId = eid; + + } else if (search.isNewState()) { + + if (search.isEndState()) { + printTransition(getStateId(lastId), getStateId(id), choice, lastInst); + printEndState(getStateId(id)); + } else { + printTransition(getStateId(lastId), getStateId(id), choice, lastInst); + printMultiProcessState(getStateId(id)); + } + + } else { // already visited state + printTransition(getStateId(lastId), getStateId(id), choice, lastInst); + } + + seenEdges.add(edgeId); + lastId = id; + } + + @Override + protected String getNextCG(){ + if (insn instanceof EXECUTENATIVE) { + return getNativeExecCG((EXECUTENATIVE)insn); + + } else if (insn instanceof JVMFieldInstruction) { // shared object field access + return getFieldAccessCG((JVMFieldInstruction)insn); + + } else if (insn instanceof LockInstruction){ // monitor_enter + return getLockCG((LockInstruction)insn); + + } else if (insn instanceof JVMInvokeInstruction){ // sync method invoke + return getInvokeCG((JVMInvokeInstruction)insn); + } else if(insn instanceof DIRECTCALLRETURN && vm.getCurrentThread().getNextPC()==null) { + return "return"; + } + + return insn.getMnemonic(); // our generic fallback + } + + protected void printMultiProcessState(String stateId){ + if(GlobalSchedulingPoint.isGlobal(vm.getNextChoiceGenerator())) { + pw.print(stateId); + + pw.print(" ["); + pw.print(mpNodeAttrs); + pw.print(']'); + + pw.println(" // multiprc state"); + } + } + + @Override + protected String getNativeExecCG (EXECUTENATIVE insn){ + MethodInfo mi = insn.getExecutedMethod(); + String s = mi.getName(); + + if (s.equals("start")) { + s = lastTi.getName() + ".start"; + } else if (s.equals("wait")) { + s = lastTi.getName() + ".wait"; + } + + return s; + } + + @Override + protected String getLastChoice() { + ChoiceGenerator cg = vm.getChoiceGenerator(); + Object choice = cg.getNextChoice(); + + if (choice instanceof ThreadInfo){ + return ((ThreadInfo) choice).getName(); + } else { + return choice.toString(); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/EndlessLoopDetector.java b/src/main/gov/nasa/jpf/listener/EndlessLoopDetector.java new file mode 100644 index 0000000..ef53d0a --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/EndlessLoopDetector.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.VM; + +/** + * little listener that tries to detect endless while() loops by counting + * backjumps, breaking transitions if the count exceeds a threshold, and + * then checking if program states match. If they do, there would be no progress + * in this thread. + */ +public class EndlessLoopDetector extends IdleFilter { + + boolean foundEndlessLoop = false; + + public EndlessLoopDetector(Config config) { + super(config); + + action = Action.BREAK; + } + + @Override + public void stateAdvanced(Search search) { + if (brokeTransition && search.isVisitedState()) { + foundEndlessLoop = true; + } + } + + @Override + public boolean check(Search search, VM vm) { + return !foundEndlessLoop; + } + + @Override + public void reset () { + foundEndlessLoop = false; + } +} diff --git a/src/main/gov/nasa/jpf/listener/ErrorTraceGenerator.java b/src/main/gov/nasa/jpf/listener/ErrorTraceGenerator.java new file mode 100644 index 0000000..94139f1 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/ErrorTraceGenerator.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.PropertyListenerAdapter; +import gov.nasa.jpf.annotation.JPFOption; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.SystemState; + +import java.io.PrintWriter; + +/** + * A lightweight listener to generate the error trace by printing + * the program instructions at transition boundaries. The idea is to have + * a shorter trace output that only shows the choices + */ +public class ErrorTraceGenerator extends PropertyListenerAdapter implements PublisherExtension { + + protected ChoiceGenerator[] trace; + + @JPFOption(type = "Boolean", key = "etg.show_insn", defaultValue = "true", comment = "print instruction that caused CG") + protected boolean showInsn = true; + + @JPFOption(type = "Boolean", key = "etg.show_loc", defaultValue = "true", comment = "print source location that caused CG") + protected boolean showLoc = true; + + @JPFOption(type = "Boolean", key = "etg.show_src", defaultValue = "true", comment = "print source line that caused CG") + protected boolean showSrc = true; + + public ErrorTraceGenerator(Config conf, JPF jpf) { + jpf.addPublisherExtension(ConsolePublisher.class, this); + + showInsn = conf.getBoolean("etg.show_insn", showInsn); + showSrc = conf.getBoolean("etg.show_src", showLoc); + showLoc = conf.getBoolean("etg.show_loc", showSrc); + } + + @Override + public void publishPropertyViolation (Publisher p){ + PrintWriter pw = p.getOut(); + + p.publishTopicStart("error trace choices"); + + if (trace != null){ + int i=0; + for (ChoiceGenerator cg : trace){ + int tid = cg.getThreadInfo().getId(); + Instruction insn = cg.getInsn(); + + if (!cg.isCascaded()){ + pw.printf("#%2d [tid=%2d] ", i++, tid); + } else { + pw.print(" "); + } + + pw.println(cg); + + if (!cg.isCascaded()){ + if (showLoc){ + String loc = insn.getFilePos(); + if (loc == null){ + loc = "[no file]"; + } + pw.print("\tat "); + pw.print(loc); + + pw.print(" in "); + pw.println( insn.getMethodInfo()); + } + + if (showInsn) { + pw.printf("\tinstruction: [pc=%d] %s\n", insn.getPosition(), insn); + } + + if (showSrc) { + String srcLine = insn.getSourceLine(); + if (srcLine == null){ + srcLine = "[no source]"; + } else { + srcLine = srcLine.trim(); + } + pw.print("\tsource: "); + pw.println( srcLine); + } + } + } + } + } + + @Override + public void propertyViolated(Search search) { + VM vm = search.getVM(); + SystemState ss = vm.getSystemState(); + trace = ss.getChoiceGenerators(); + } +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/listener/ExceptionInjector.java b/src/main/gov/nasa/jpf/listener/ExceptionInjector.java new file mode 100644 index 0000000..85a002e --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/ExceptionInjector.java @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.JPFConfigException; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + +import java.util.HashMap; + +/** + * listener to inject exceptions according to user specifications. This + * tool is meant to be used for exception handler verification, esp. if + * exceptions thrown by 3rd party code would be hard to produce. + * + * Exceptions are specified as a list of xSpec'@'location pairs. + * + * ExceptionSpec is specified as a class name, with optional details parameter. If no + * package is specified, either java.lang or default package are assumed + * + * Location can be + * - class:line + * - fully qualified method (callee that is supposed to throw, which is + * NOT executed in this case) + * - fully qualified method ':' lineOffset + * + * for line/offest based locations, either the first or last insn associated + * with this line (depending on ei.throwFirst=true|false) is not executed + * but replaced with throwing the exception. + * + * Method body line offsets count from the first statement line in the method body + * + * Examples: + * IOException@x.Foobar:42 + * NullPointerException@x.SomeClass.computeSomething(Ljava/lang/String;I) + * y.MyException("something went wrong")@x.SomeClass.foo(D):10 + */ + +public class ExceptionInjector extends ListenerAdapter { + + boolean throwFirst; // for location targets, throw on first insn associated with line + + static class ExceptionEntry { + Instruction insn; + ExceptionSpec xSpec; + Location loc; + + ExceptionEntry next; // there might be more than one for one class + + ExceptionEntry (ExceptionSpec xSpec, Location loc, ExceptionEntry next){ + this.xSpec = xSpec; + this.loc = loc; + this.next = next; + } + + String getLocationClassName() { + return loc.className; + } + + String getMethod() { + return loc.method; + } + + int getLine() { + return loc.line; + } + + ClassInfo getExceptionClassInfo(ThreadInfo ti) { + return ClassLoaderInfo.getCurrentResolvedClassInfo(xSpec.xClsName); + } + + String getExceptionDetails() { + return xSpec.details; + } + + @Override + public String toString() { + return xSpec.toString() + '@' + loc.toString(); + } + } + + static class ExceptionSpec { + String xClsName; + String details; + + ExceptionSpec (String xClsName, String details){ + this.xClsName = xClsName; + this.details = details; + } + + @Override + public String toString() { + if (details == null){ + return xClsName; + } else { + StringBuilder sb = new StringBuilder(xClsName); + sb.append('('); + if (!details.isEmpty()){ + sb.append('"'); + sb.append(details); + sb.append('"'); + } + sb.append(')'); + return sb.toString(); + } + } + } + + static class Location { + String className; + String method; // name + signature + int line; + + Location (String className, String method, int line){ + this.className = className; + this.method = method; + this.line = line; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(className); + if (method != null){ + sb.append('.'); + sb.append(method); + } + if (line >= 0){ + sb.append(':'); + sb.append(line); + } + return sb.toString(); + } + } + + // these two are used to process classes at loadtime + HashMap targetClasses = new HashMap(); + HashMap targetBases = new HashMap(); + + // methods and instructions to watch for at runtime will have ExceptionEntry attrs + + + public ExceptionInjector (Config config, JPF jpf){ + throwFirst = config.getBoolean("ei.throw_first", false); + String[] xSpecs = config.getStringArray("ei.exception", new char[] {';'}); + + if (xSpecs != null){ + for (String xSpec : xSpecs){ + if (!parseException(xSpec)){ + throw new JPFConfigException("invalid exception spec: " + xSpec); + } + } + } + + printEntries(); + } + + boolean parseException (String xSpec){ + int i = xSpec.indexOf('@'); + if (i > 0){ + String typeSpec = xSpec.substring(0, i).trim(); + String locSpec = xSpec.substring(i+1).trim(); + + ExceptionSpec type = parseType(typeSpec); + if (type != null){ + Location loc = parseLocation(locSpec); + if (loc != null){ + String cls = loc.className; + int line = loc.line; + if (line >= 0){ + targetClasses.put(cls, new ExceptionEntry(type,loc,targetClasses.get(cls))); + } else { + targetBases.put(cls, new ExceptionEntry(type,loc,targetBases.get(cls))); + } + return true; + } + } + } + + return false; + } + + ExceptionSpec parseType (String spec){ + String cls = null; + String details = null; + + int i = spec.indexOf('('); + if (i > 0){ + cls = spec.substring(0, i); + + int j = spec.lastIndexOf(')'); + if (spec.charAt(i+1) == '"'){ + i++; + } + if (spec.charAt(j-1) == '"'){ + j--; + } + details = spec.substring(i+1, j); + if (details.isEmpty()){ + details = null; + } + + } else if (i < 0) { // no details + cls = spec; + } + + if (cls != null){ + return new ExceptionSpec( cls,details); + } + + return null; + } + + Location parseLocation (String spec){ + int i = spec.indexOf('('); + if (i > 0){ // we have a method name + int j = spec.lastIndexOf('.', i); // get class part + if (j > 0){ + String cls = spec.substring(0, j).trim(); + i = spec.indexOf(':'); + if (i > 0){ + + String mth = Types.getSignatureName(spec.substring(j+1, i)); + + try { + int line = Integer.parseInt(spec.substring(i + 1)); + if (!cls.isEmpty() && !mth.isEmpty() && line >= 0){ + return new Location(cls, mth, line); + } + } catch (NumberFormatException nfx) { + return null; + } + } else { + String mth = Types.getSignatureName(spec.substring(j+1)); + return new Location(cls,mth, -1); + } + } + + } else { // no method + i = spec.indexOf(':'); // but we need a line number + if (i > 0){ + String cls = spec.substring(0, i).trim(); + try { + int line = Integer.parseInt(spec.substring(i+1)); + if (!cls.isEmpty() && line >= 0){ + return new Location (cls, null, line); + } + } catch (NumberFormatException nfx){ + return null; + } + } + } + + return null; + } + + boolean checkTargetInsn (ExceptionEntry e, MethodInfo mi, int[] ln, int line){ + if ((ln[0] <= line) && (ln[ln.length - 1] >= line)) { + for (int i = 0; i < ln.length; i++) { + if (ln[i] == line) { + if (!throwFirst) { + while ((i++ < ln.length) && (ln[i] == line)); + i--; + } + + mi.getInstruction(i).addAttr(e); + return true; + } + } + } + + return false; + } + + /** + * get the target insns/methods + */ + @Override + public void classLoaded (VM vm, ClassInfo loadedClass){ + + nextClassEntry: + for (ExceptionEntry e = targetClasses.get(loadedClass.getName()); e != null; e = e.next){ + String method = e.getMethod(); + int line = e.getLine(); + + if (method != null){ // method or method/line-offset + for (MethodInfo mi : loadedClass.getDeclaredMethodInfos()){ + if (mi.getUniqueName().startsWith(method)){ + if (line >= 0){ // line offset + int[] ln = mi.getLineNumbers(); + line += ln[0]; + if (checkTargetInsn(e,mi,ln,line)){ + continue nextClassEntry; + } + } + } + } + + } else { // absolute line number + if (line >= 0){ + for (MethodInfo mi : loadedClass.getDeclaredMethodInfos()) { + int[] ln = mi.getLineNumbers(); + if (checkTargetInsn(e, mi, ln, line)) { + continue nextClassEntry; + } + } + } + } + } + + if (targetBases != null){ + for (; loadedClass != null; loadedClass = loadedClass.getSuperClass()) { + nextBaseEntry: + for (ExceptionEntry e = targetBases.get(loadedClass.getName()); e != null; e = e.next){ + String method = e.getMethod(); + for (MethodInfo mi : loadedClass.getDeclaredMethodInfos()){ + if (mi.getUniqueName().startsWith(method)){ + mi.addAttr(e); + continue nextBaseEntry; + } + } + } + } + } + } + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insnToExecute){ + + ExceptionEntry e = insnToExecute.getAttr(ExceptionEntry.class); + if ((e == null) && insnToExecute instanceof JVMInvokeInstruction){ + MethodInfo mi = ((JVMInvokeInstruction) insnToExecute).getInvokedMethod(); + e = mi.getAttr(ExceptionEntry.class); + } + + if (e != null){ + Instruction nextInsn = ti.createAndThrowException(e.getExceptionClassInfo(ti), e.getExceptionDetails()); + ti.skipInstruction(nextInsn); + return; + } + } + + // for debugging purposes + void printEntries () { + for (ExceptionEntry e : targetClasses.values()){ + System.out.println(e); + } + for (ExceptionEntry e : targetBases.values()){ + System.out.println(e); + } + } + + /** + public static void main (String[] args){ + Config conf = JPF.createConfig(args); + ExceptionInjector ei = new ExceptionInjector(conf,null); + + ei.parseException("x.y.Zang(\"bang\")@z.Foo.doit(Ljava/lang/Object;I)"); + ei.printEntries(); + } + **/ +} diff --git a/src/main/gov/nasa/jpf/listener/ExecTracker.java b/src/main/gov/nasa/jpf/listener/ExecTracker.java new file mode 100644 index 0000000..5dab34a --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/ExecTracker.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.annotation.JPFOption; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.PrintWriter; + +/** + * Listener tool to monitor JPF execution. This class can be used as a drop-in replacement for JPF, which is called by + * ExecTracker. ExecTracker is mostly a VMListener of 'instructionExecuted' and a SearchListener of 'stateAdvanced' and + * 'statehBacktracked' + * + * NOTE - the ExecTracker is machine type agnostic + */ + +public class ExecTracker extends ListenerAdapter { + + @JPFOption(type = "Boolean", key = "et.print_insn", defaultValue = "true", comment = "print executed bytecode instructions") + boolean printInsn = true; + + @JPFOption(type = "Boolean", key = "et.print_src", defaultValue = "false", comment = "print source lines") + boolean printSrc = false; + + @JPFOption(type = "Boolean", key = "et.print_mth", defaultValue = "false", comment = "print executed method names") + boolean printMth = false; + + @JPFOption(type = "Boolean", key = "et.skip_init", defaultValue = "true", comment = "do not log execution before entering main()") + boolean skipInit = false; + + boolean showShared = false; + + PrintWriter out; + String lastLine; + MethodInfo lastMi; + String linePrefix; + + boolean skip; + MethodInfo miMain; // just to make init skipping more efficient + + public ExecTracker (Config config) { + /** @jpfoption et.print_insn : boolean - print executed bytecode instructions (default=true). */ + printInsn = config.getBoolean("et.print_insn", true); + + /** @jpfoption et.print_src : boolean - print source lines (default=false). */ + printSrc = config.getBoolean("et.print_src", false); + + /** @jpfoption et.print_mth : boolean - print executed method names (default=false). */ + printMth = config.getBoolean("et.print_mth", false); + + /** @jpfoption et.skip_init : boolean - do not log execution before entering main() (default=true). */ + skipInit = config.getBoolean("et.skip_init", true); + + showShared = config.getBoolean("et.show_shared", true); + + if (skipInit) { + skip = true; + } + + out = new PrintWriter(System.out, true); + } + + /******************************************* SearchListener interface *****/ + + @Override + public void stateRestored(Search search) { + int id = search.getStateId(); + out.println("----------------------------------- [" + + search.getDepth() + "] restored: " + id); + } + + //--- the ones we are interested in + @Override + public void searchStarted(Search search) { + out.println("----------------------------------- search started"); + if (skipInit) { + ThreadInfo tiCurrent = ThreadInfo.getCurrentThread(); + miMain = tiCurrent.getEntryMethod(); + + out.println(" [skipping static init instructions]"); + } + } + + @Override + public void stateAdvanced(Search search) { + int id = search.getStateId(); + + out.print("----------------------------------- [" + + search.getDepth() + "] forward: " + id); + if (search.isNewState()) { + out.print(" new"); + } else { + out.print(" visited"); + } + + if (search.isEndState()) { + out.print(" end"); + } + + out.println(); + + lastLine = null; // in case we report by source line + lastMi = null; + linePrefix = null; + } + + @Override + public void stateProcessed (Search search) { + int id = search.getStateId(); + out.println("----------------------------------- [" + + search.getDepth() + "] done: " + id); + } + + @Override + public void stateBacktracked(Search search) { + int id = search.getStateId(); + + lastLine = null; + lastMi = null; + + out.println("----------------------------------- [" + + search.getDepth() + "] backtrack: " + id); + } + + @Override + public void searchFinished(Search search) { + out.println("----------------------------------- search finished"); + } + + /******************************************* VMListener interface *********/ + + @Override + public void gcEnd(VM vm) { + out.println("\t\t # garbage collection"); + } + + //--- the ones we are interested in + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + + if (skip) { + MethodInfo mi = executedInsn.getMethodInfo(); + if (mi == miMain) { + skip = false; // start recording + } else { + return; // skip + } + } + + int nNoSrc = 0; + + if (linePrefix == null) { + linePrefix = Integer.toString( ti.getId()) + " : "; + } + + // that's pretty redundant to what is done in the ConsolePublisher, but we don't want + // presentation functionality in Step anymore + if (printSrc) { + String line = executedInsn.getSourceLine(); + if (line != null){ + if (nNoSrc > 0) { + out.println(" [" + nNoSrc + " insn w/o sources]"); + } + + if (!line.equals(lastLine)) { + out.print(" ["); + out.print(executedInsn.getFileLocation()); + out.print("] : "); + out.println(line.trim()); + } + + nNoSrc = 0; + + } else { // no source + nNoSrc++; + } + + lastLine = line; + } + + if (printInsn) { + if (printMth) { + MethodInfo mi = executedInsn.getMethodInfo(); + if (mi != lastMi){ + ClassInfo mci = mi.getClassInfo(); + out.print(" "); + if (mci != null) { + out.print(mci.getName()); + out.print("."); + } + out.println(mi.getUniqueName()); + lastMi = mi; + } + } + + out.print( linePrefix); + + out.printf("[%04x] ", executedInsn.getPosition()); + + out.println( executedInsn.toPostExecString()); + } + } + + @Override + public void threadStarted(VM vm, ThreadInfo ti) { + out.println( "\t\t # thread started: " + ti.getName() + " index: " + ti.getId()); + } + + @Override + public void threadTerminated(VM vm, ThreadInfo ti) { + out.println( "\t\t # thread terminated: " + ti.getName() + " index: " + ti.getId()); + } + + @Override + public void exceptionThrown (VM vm, ThreadInfo ti, ElementInfo ei) { + MethodInfo mi = ti.getTopFrameMethodInfo(); + out.println("\t\t\t\t # exception: " + ei + " in " + mi); + } + + @Override + public void choiceGeneratorAdvanced (VM vm, ChoiceGenerator currentCG) { + out.println("\t\t # choice: " + currentCG); + + //vm.dumpThreadStates(); + } + + @Override + public void objectExposed (VM vm, ThreadInfo currentThread, ElementInfo fieldOwnerObject, ElementInfo exposedObject) { + if (showShared){ + String msg = "\t\t # exposed " + exposedObject; + if (fieldOwnerObject != null){ + String ownerStatus = ""; + if (fieldOwnerObject.isShared()){ + ownerStatus = "shared "; + } else if (fieldOwnerObject.isExposed()){ + ownerStatus = "exposed "; + } + + msg += " through " + ownerStatus + fieldOwnerObject; + } + out.println(msg); + } + } + + @Override + public void objectShared (VM vm, ThreadInfo currentThread, ElementInfo sharedObject) { + if (showShared){ + out.println("\t\t # shared " + sharedObject); + } + } + + + /****************************************** private stuff ******/ + + void filterArgs (String[] args) { + for (int i=0; i pathStats = new Stack(); + + DynamicObjectArray loc = new DynamicObjectArray(); + + HashMap typeStat = new HashMap(); + + int maxState; + int nForward; + int nBacktrack; + + int nElemTotal; + int nGcTotal; + int nSharedTotal; + int nImmutableTotal; + + int nElemMax = Integer.MIN_VALUE; + int nElemMin = Integer.MAX_VALUE; + int nElemAv; + + int pElemSharedMax = Integer.MIN_VALUE; + int pElemSharedMin = Integer.MAX_VALUE; + int pElemSharedAv; + + int pElemImmutableMax = Integer.MIN_VALUE; + int pElemImmutableMin = Integer.MAX_VALUE; + int pElemImmutableAv; + + int nReleased; + int nReleasedTotal; + int nReleasedAv; + int nReleasedMax = Integer.MIN_VALUE; + int nReleasedMin = Integer.MAX_VALUE; + + int maxPathHeap = Integer.MIN_VALUE; + int maxPathNew = Integer.MIN_VALUE; + int maxPathReleased = Integer.MIN_VALUE; + int maxPathAlive = Integer.MIN_VALUE; + + int initHeap = 0; + int initNew = 0; + int initReleased = 0; + int initAlive = 0; + + + boolean showTypeStats; + int maxTypesShown; + + // used as a property check + int maxHeapSizeLimit; + int maxLiveLimit; + boolean throwOutOfMemory = false; + + StringSetMatcher includes, excludes; + + void updateMaxPathValues() { + if (stat.heapSize > maxPathHeap) { + maxPathHeap = stat.heapSize; + } + + if (stat.nNew > maxPathNew) { + maxPathNew = stat.nNew; + } + + if (stat.nReleased > maxPathReleased) { + maxPathReleased = stat.nReleased; + } + + int nAlive = stat.nNew - stat.nReleased; + if (nAlive > maxPathAlive) { + maxPathAlive = nAlive; + } + } + + void allocTypeStats (ElementInfo ei) { + String typeName = ei.getClassInfo().getName(); + TypeStat ts = typeStat.get(typeName); + if (ts == null) { + ts = new TypeStat(typeName); + typeStat.put(typeName, ts); + } + ts.nAlloc++; + } + + void releaseTypeStats (ElementInfo ei) { + String typeName = ei.getClassInfo().getName(); + TypeStat ts = typeStat.get(typeName); + if (ts != null) { + ts.nReleased++; + } + } + + + public HeapTracker (Config config, JPF jpf) { + maxHeapSizeLimit = config.getInt("heap.size_limit", -1); + maxLiveLimit = config.getInt("heap.live_limit", -1); + throwOutOfMemory = config.getBoolean("heap.throw_exception"); + showTypeStats = config.getBoolean("heap.show_types"); + maxTypesShown = config.getInt("heap.max_types", 20); + + includes = StringSetMatcher.getNonEmpty(config.getStringArray("heap.include")); + excludes = StringSetMatcher.getNonEmpty(config.getStringArray("heap.exclude")); + + jpf.addPublisherExtension(ConsolePublisher.class, this); + } + + /******************************************* abstract Property *****/ + + /** + * return 'false' if property is violated + */ + @Override + public boolean check (Search search, VM vm) { + if (throwOutOfMemory) { + // in this case we don't want to stop the program, but see if it + // behaves gracefully - don't report a property violation + return true; + } else { + if ((maxHeapSizeLimit >= 0) && (stat.heapSize > maxHeapSizeLimit)) { + return false; + } + if ((maxLiveLimit >=0) && ((stat.nNew - stat.nReleased) > maxLiveLimit)) { + return false; + } + + return true; + } + } + + @Override + public String getErrorMessage () { + return "heap limit exceeded: " + stat.heapSize + " > " + maxHeapSizeLimit; + } + + /******************************************* SearchListener interface *****/ + @Override + public void searchStarted(Search search) { + super.searchStarted(search); + + updateMaxPathValues(); + pathStats.push(stat); + + initHeap = stat.heapSize; + initNew = stat.nNew; + initReleased = stat.nReleased; + initAlive = initNew - initReleased; + + stat = (PathStat)stat.clone(); + } + + @Override + public void stateAdvanced(Search search) { + + if (search.isNewState()) { + int id = search.getStateId(); + + if (id > maxState) maxState = id; + + updateMaxPathValues(); + pathStats.push(stat); + stat = (PathStat)stat.clone(); + + nForward++; + } + } + + @Override + public void stateBacktracked(Search search) { + nBacktrack++; + + if (!pathStats.isEmpty()){ + stat = pathStats.pop(); + } + } + + /******************************************* PublisherExtension interface ****/ + @Override + public void publishFinished (Publisher publisher) { + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("heap statistics"); + + pw.println("heap statistics:"); + pw.println(" states: " + maxState); + pw.println(" forwards: " + nForward); + pw.println(" backtrack: " + nBacktrack); + pw.println(); + pw.println(" gc cycles: " + nGcTotal); + pw.println(); + pw.println(" max Objects: " + nElemMax); + pw.println(" min Objects: " + nElemMin); + pw.println(" avg Objects: " + nElemAv); + pw.println(); + pw.println(" max% shared: " + pElemSharedMax); + pw.println(" min% shared: " + pElemSharedMin); + pw.println(" avg% shared: " + pElemSharedAv); + pw.println(); + pw.println(" max% immutable: " + pElemImmutableMax); + pw.println(" min% immutable: " + pElemImmutableMin); + pw.println(" avg% immutable: " + pElemImmutableAv); + pw.println(); + pw.println(" max released: " + nReleasedMax); + pw.println(" min released: " + nReleasedMin); + pw.println(" avg released: " + nReleasedAv); + + pw.println(); + pw.print( " max path heap (B): " + maxPathHeap); + pw.println(" / " + (maxPathHeap - initHeap)); + pw.print( " max path alive: " + maxPathAlive); + pw.println(" / " + (maxPathAlive - initAlive)); + pw.print( " max path new: " + maxPathNew); + pw.println(" / " + (maxPathNew - initNew)); + pw.print( " max path released: " + maxPathReleased); + pw.println(" / " + (maxPathReleased - initReleased)); + + if (showTypeStats) { + pw.println(); + pw.println(" type allocation statistics:"); + + ArrayList> list = + Misc.createSortedEntryList(typeStat, new Comparator>() { + @Override + public int compare (Map.Entry e1, + Map.Entry e2) { + return Integer.signum(e1.getValue().nAlloc - e2.getValue().nAlloc); + }}); + + int i=0; + for (Map.Entry e : list) { + TypeStat ts = e.getValue(); + pw.print(" "); + pw.print(String.format("%1$9d : ", ts.nAlloc)); + pw.println(ts.typeName); + + if (i++ > maxTypesShown) { + pw.println(" ..."); + break; + } + } + } + } + + + /******************************************* VMListener interface *********/ + @Override + public void gcBegin(VM vm) { + /** + System.out.println(); + System.out.println( "----- gc cycle: " + vm.getDynamicArea().getGcNumber() + + ", state: " + vm.getStateId()); + **/ + } + + @Override + public void gcEnd(VM vm) { + Heap heap = vm.getHeap(); + + int n = 0; + int nShared = 0; + int nImmutable = 0; + + for (ElementInfo ei : heap.liveObjects()) { + n++; + + if (ei.isShared()) nShared++; + if (ei.isImmutable()) nImmutable++; + + //printElementInfo(ei); + } + + nElemTotal += n; + nGcTotal++; + + if (n > nElemMax) nElemMax = n; + if (n < nElemMin) nElemMin = n; + + int pShared = (nShared * 100) / n; + int pImmutable = (nImmutable * 100) / n; + + if (pShared > pElemSharedMax) pElemSharedMax = pShared; + if (pShared < pElemSharedMin) pElemSharedMin = pShared; + + nSharedTotal += nShared; + nImmutableTotal += nImmutable; + + pElemSharedAv = (nSharedTotal * 100) / nElemTotal; + pElemImmutableAv = (nImmutableTotal * 100) / nElemTotal; + + if (pImmutable > pElemImmutableMax) pElemImmutableMax = pImmutable; + if (pImmutable < pElemImmutableMin) pElemImmutableMin = pImmutable; + + nElemAv = nElemTotal / nGcTotal; + nReleasedAv = nReleasedTotal / nGcTotal; + + if (nReleased > nReleasedMax) nReleasedMax = nReleased; + if (nReleased < nReleasedMin) nReleasedMin = nReleased; + + nReleased = 0; + } + + boolean isRelevantType (ElementInfo ei) { + String clsName = ei.getClassInfo().getName(); + return StringSetMatcher.isMatch(clsName, includes, excludes); + } + + @Override + public void objectCreated(VM vm, ThreadInfo ti, ElementInfo ei) { + int idx = ei.getObjectRef(); + int line = ti.getLine(); + MethodInfo mi = ti.getTopFrameMethodInfo(); + SourceRef sr = null; + + if (!isRelevantType(ei)) { + return; + } + + if (mi != null) { + ClassInfo mci = mi.getClassInfo(); + if (mci != null) { + String file = mci.getSourceFileName(); + if (file != null) { + sr = new SourceRef(file, line); + } else { + sr = new SourceRef(mci.getName(), line); + } + } + } + + // means references with null loc are from synthetic methods + loc.set(idx, sr); + + stat.nNew++; + stat.heapSize += ei.getHeapSize(); + + // update the type statistics + if (showTypeStats) { + allocTypeStats(ei); + } + + + // check if we should simulate an OutOfMemoryError + if (throwOutOfMemory) { + if (((maxHeapSizeLimit >=0) && (stat.heapSize > maxHeapSizeLimit)) || + ((maxLiveLimit >=0) && ((stat.nNew - stat.nReleased) > maxLiveLimit))){ + vm.getHeap().setOutOfMemory(true); + } + } + } + + @Override + public void objectReleased(VM vm, ThreadInfo ti, ElementInfo ei) { + + if (!isRelevantType(ei)) { + return; + } + + nReleasedTotal++; + nReleased++; + + if (showTypeStats) { + releaseTypeStats(ei); + } + + stat.nReleased++; + stat.heapSize -= ei.getHeapSize(); + } + + /****************************************** private stuff ******/ + protected void printElementInfo(ElementInfo ei) { + boolean first = false; + + System.out.print( ei.getObjectRef()); + System.out.print( ": "); + System.out.print( ei.getClassInfo().getName()); + System.out.print( " ["); + + if (ei.isShared()) { + System.out.print( "shared"); + first = false; + } + if (ei.isImmutable()) { + if (!first) System.out.print(' '); + System.out.print( "immutable"); + } + System.out.print( "] "); + + SourceRef sr = loc.get(ei.getObjectRef()); + if (sr != null) { + System.out.println(sr); + } else { + System.out.println("?"); + } + } + + + static void printUsage () { + System.out.println("HeapTracker - a JPF listener tool to report and check heap utilization"); + System.out.println("usage: java gov.nasa.jpf.tools.HeapTracker "); + System.out.println(" +heap.size_limit= : report property violation if heap exceeds bytes"); + System.out.println(" +heap.live_limit= : report property violation if more than live objects"); + System.out.println(" +heap.classes= : only report instances of classes matching "); + System.out.println(" +heap.throw_exception=: throw a OutOfMemoryError instead of reporting property violation"); + } +} + diff --git a/src/main/gov/nasa/jpf/listener/IdleFilter.java b/src/main/gov/nasa/jpf/listener/IdleFilter.java new file mode 100644 index 0000000..ece2e4a --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/IdleFilter.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.JPFConfigException; +import gov.nasa.jpf.PropertyListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.ArrayStoreInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.DynamicObjectArray; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.util.logging.Logger; + +/** + * simple combined listener that checks if a thread seems to do idle loops that + * might starve other threads or JPF. The most classical case is a "busy wait" loop + * like + * + * for (long l=0; l<1000000; l++); + * + * which would give us a pretty long path. Even worse, things like + * + * while (true); + * + * would (just like in a normal VM) never terminate in JPF, even though people + * familiar with model checking would expect state matching. Only that without + * a transition break, JPF has no reason to match states, so we have to + * automatically add a break on the backjump. We shouldn't add one on every + * backjump though because that might cause a lot of overhead in programs that + * do terminate. + * + * IdleFilter has two options: + * idle.max_backjumps : sets the number of backjumps after which we break + * idle.action : what to do if max_backjumps are exceeded in the same thread + * on the same location and stackframe + * warn : only print warning for backjumps exceeding the max_backjumps + * break : break the transition to allow state matching + * prune : unconditionally prune the search + * jump : jump past the backjump (this is dangerous if the loop has side effects) + */ +public class IdleFilter extends PropertyListenerAdapter { + + static Logger log = JPF.getLogger("gov.nasa.jpf.listener.IdleFilter"); + + static class ThreadStat { + String tname; + + int backJumps; + + boolean isCleared = false; + + int loopStartPc; + + int loopEndPc; + + int loopStackDepth; + + ThreadStat(String tname) { + this.tname = tname; + } + } + + static enum Action { JUMP, PRUNE, BREAK, YIELD, WARN } + + DynamicObjectArray threadStats = new DynamicObjectArray(4,16); + + ThreadStat ts; + + // we use this to remember that we just broke the transition + boolean brokeTransition; + + int maxBackJumps; + Action action; + + + // ----------------------------------------------------- SearchListener + // interface + + public IdleFilter(Config config) { + maxBackJumps = config.getInt("idle.max_backjumps", 500); + + String act = config.getString("idle.action", "break"); + if ("warn".equalsIgnoreCase(act)){ + action = Action.WARN; + } else if ("break".equalsIgnoreCase(act)){ + action = Action.BREAK; + } else if ("yield".equalsIgnoreCase(act)){ + action = Action.YIELD; + } else if ("prune".equalsIgnoreCase(act)){ + action = Action.PRUNE; + } else if ("jump".equalsIgnoreCase(act)){ + action = Action.JUMP; + } else { + throw new JPFConfigException("unknown IdleFilter action: " +act); + } + + } + + @Override + public void stateAdvanced(Search search) { + ts.backJumps = 0; + ts.isCleared = false; + ts.loopStackDepth = 0; + ts.loopStartPc = ts.loopEndPc = 0; + + brokeTransition = false; + } + + @Override + public void stateBacktracked(Search search) { + ts.backJumps = 0; + ts.isCleared = false; + ts.loopStackDepth = 0; + ts.loopStartPc = ts.loopEndPc = 0; + } + + // ----------------------------------------------------- VMListener interface + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + + int tid = ti.getId(); + ts = threadStats.get(tid); + if (ts == null) { + ts = new ThreadStat(ti.getName()); + threadStats.set(tid, ts); + } + + if (executedInsn.isBackJump()) { + ts.backJumps++; + + int loopStackDepth = ti.getStackDepth(); + int loopPc = nextInsn.getPosition(); + + if ((loopStackDepth != ts.loopStackDepth) || (loopPc != ts.loopStartPc)) { + // new loop, reset + ts.isCleared = false; + ts.loopStackDepth = loopStackDepth; + ts.loopStartPc = loopPc; + ts.loopEndPc = executedInsn.getPosition(); + ts.backJumps = 0; + + } else { + if (!ts.isCleared) { + if (ts.backJumps > maxBackJumps) { + + ti.reschedule("idleFilter"); // this breaks the executePorStep loop + MethodInfo mi = executedInsn.getMethodInfo(); + ClassInfo ci = mi.getClassInfo(); + int line = mi.getLineNumber(executedInsn); + String file = ci.getSourceFileName(); + + switch (action) { + case JUMP: + // pretty bold, we jump past the loop end and go on from there + + Instruction next = executedInsn.getNext(); + ti.setNextPC(next); + + log.warning("jumped past loop in: " + ti.getName() + + "\n\tat " + ci.getName() + "." + mi.getName() + "(" + file + ":" + line + ")"); + break; + + case PRUNE: + // cut this sucker off - we declare this a visited state + vm.ignoreState(); + log.warning("pruned thread: " + ti.getName() + + "\n\tat " + ci.getName() + "." + mi.getName() + "(" + file + ":" + line + ")"); + break; + + case BREAK: + // just break the transition and let the state matching take over + brokeTransition = true; + ti.breakTransition("breakIdleLoop"); + + log.warning("breaks transition on suspicious loop in thread: " + ti.getName() + + "\n\tat " + ci.getName() + "." + mi.getName() + "(" + file + ":" + line + ")"); + + break; + + case YIELD: + // give other threads a chance to run + brokeTransition = true; + ti.reschedule("rescheduleIdleLoop"); + + log.warning("yield on suspicious loop in thread: " + ti.getName() + + "\n\tat " + ci.getName() + "." + mi.getName() + "(" + file + ":" + line + ")"); + + break; + + case WARN: + log.warning("detected suspicious loop in thread: " + ti.getName() + + "\n\tat " + ci.getName() + "." + mi.getName() + "(" + file + ":" + line + ")"); + break; + + } + } + } + } + + } else if (!ts.isCleared) { + // if we call methods or set array elements inside the loop in question, + // we assume this is not an idle loop and terminate the checks + // <2do> this is too restrictive - we should leave this to state matching + + if ((executedInsn instanceof JVMInvokeInstruction) + || (executedInsn instanceof ArrayStoreInstruction)) { + int stackDepth = ti.getStackDepth(); + int pc = executedInsn.getPosition(); + + if (stackDepth == ts.loopStackDepth) { + if ((pc >= ts.loopStartPc) && (pc < ts.loopEndPc)) { + ts.isCleared = true; + } + } + } + } + } + + // thread ids are reused, so we have to clean up + @Override + public void threadTerminated (VM vm, ThreadInfo ti){ + int tid = ti.getId(); + threadStats.set(tid, null); + } + + +} diff --git a/src/main/gov/nasa/jpf/listener/InsnCounter.java b/src/main/gov/nasa/jpf/listener/InsnCounter.java new file mode 100644 index 0000000..4dddbdd --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/InsnCounter.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; + +/** + * simple tools to gather statistics about instructions executed by JPF. + * InsnCounter is mostly a VMListener that observes 'instructionExecuted' + */ +public class InsnCounter extends ListenerAdapter { + + String[] opCodes = new String[500]; + int[] counts = new int[500]; + int total; + + //----------------------------------------- SearchKistener interface + @Override + public void searchFinished(Search search) { + reportStatistics(); + } + + //----------------------------------------------------- VMListener interface + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + int bc = executedInsn.getByteCode(); + + if (opCodes[bc] == null) { + opCodes[bc] = executedInsn.getMnemonic(); + } + counts[bc]++; + total++; + } + + + //----------------------------------------------------- internal stuff + void reportStatistics () { + int[] sorted = getSortedCounts(); + int i; + + int total = 0; + + for (i=0; i 0) { + System.out.print( i); + System.out.print( " "); + System.out.print( opc); + System.out.print( " : "); + System.out.println( counts[idx]); + + total += counts[idx]; + } else { + break; + } + } + + System.out.println(); + System.out.println("total number of executed instructions: " + total); + } + + int[] getSortedCounts () { + int[] sorted = new int[256]; + int last = -1; + int i, j; + + for (i=0; i<256; i++) { + int c = counts[i]; + if (c > 0) { + for (j=0; j m_operations = new HashMap(); + private final HashMap m_state = new HashMap(); + private final HashMap m_index = new HashMap(); + private final ArrayList m_apply = new ArrayList(); + private Operation m_current; + + public int getLockedStackDepth(ElementInfo lock) + { + Integer result; + int lockIndex; + + lockIndex = lock.getObjectRef(); + result = m_state.get(makeKey(lock)); + + if (s_logger.isLoggable(Level.INFO)) + s_logger.info("Depth = " + result + " | Lock Index = " + lockIndex + " | Lock = " + lock); + + if (result == null) + return(-1); + + assert result >= 0; + + return(result); + } + + public List getLockedInTopFrame(ThreadInfo thread) + { + ArrayList result; + ElementInfo lock; + int threadDepth; + + threadDepth = thread.getStackDepth(); + result = new ArrayList(); + + for (Integer key : m_state.keySet()) + { + if (key < 0) + continue; + + if (threadDepth != m_state.get(key)) + continue; + + lock = thread.getElementInfo(key); + + if (lock == null) + continue; + + if (!lock.isLockedBy(thread)) + continue; + + result.add(lock); + } + + return(result); + } + + @Override + public void objectLocked(VM vm, ThreadInfo thread, ElementInfo ei) + { + ElementInfo lock; + Integer depth; + + lock = ei; + + logStack(thread); + + depth = new Operation(thread, null).getOldDepth(); + + if (depth == null) + depth = thread.getStackDepth(); + + assert thread.getLockCount() == 0; + assert thread.getLockObject() == null; + assert lock.isLockedBy(thread); + + if (m_state.containsKey(makeKey(lock))) // So that a breakpoint on the next line will only get hit if the assert will trigger. + assert !m_state.containsKey(makeKey(lock)); + + assert !m_state.containsKey(makeKey(thread)); + assert depth >= 0; + + new Operation(lock, depth); + } + + @Override + public void objectUnlocked(VM vm, ThreadInfo thread, ElementInfo ei) + { + ElementInfo lock; + Integer depth; + + logStack(thread); + + lock = ei; + depth = new Operation(lock, null).getOldDepth(); + + assert !m_state.containsKey(makeKey(lock)); + assert !m_state.containsKey(makeKey(thread)); + assert depth >= 0; + + if (thread.isWaiting()) + { + assert !lock.isLockedBy(thread); + assert lock.getLockCount() == 0; + assert thread.getLockCount() > 0; + assert thread.getLockObject() == lock; + new Operation(thread, depth); + } + else + { + assert lock.isLockedBy(thread); + assert lock.getLockCount() > 0; + assert thread.getLockCount() == 0; + assert thread.getLockObject() == null; + } + } + + @Override + public void searchStarted(Search search) + { + m_operations.clear(); + m_state.clear(); + + m_current = null; + } + + @Override + public void stateAdvanced(Search search) + { + Integer id; + + id = search.getStateId(); + + if (!m_operations.containsKey(id)) // Don't overwrite the original chain of Operations to get to the same state. The original chain is more likely to be shorter. + m_operations.put(id, m_current); + + if (s_logger.isLoggable(Level.FINE)) + s_logger.fine("State Advanced: " + id); + + logState(); + } + + @Override + public void stateProcessed(Search search) + { + Integer id; + + if (!(search instanceof DFSearch)) // Can't remove from m_operations since Search could go back to the state. + if (!(search instanceof BFSHeuristic)) + return; + + id = search.getStateId(); + + m_operations.remove(id); // DFSearch won't ever revisit this state. It is safe to remove and allow for cleanup. + + if (s_logger.isLoggable(Level.FINE)) + s_logger.fine("State Processed: " + id); + } + + @Override + public void stateBacktracked(Search search) + { + switchTo(search); + } + + @Override + public void stateRestored(Search search) + { + switchTo(search); + } + + private void switchTo(Search search) + { + Operation next; + Integer id; + + id = search.getStateId(); + next = m_operations.get(id); + + if (s_logger.isLoggable(Level.FINE)) + s_logger.fine("State Switching: " + id); + + assert (id <= 0) || (m_operations.containsKey(id)); + + switchTo(next); + + m_current = next; + + logState(); + + if (s_logger.isLoggable(Level.FINE)) + s_logger.fine("State Switched: " + id); + } + + private void switchTo(Operation next) + { + Operation operation; + Integer index; + int i; + + for (operation = next; operation != null; operation = operation.getParent()) // Go through all of the operations leading back to the root. + { + m_index.put(operation, m_apply.size()); // Keep track of the index into m_apply where operation is found + m_apply.add(operation); + } + + index = null; + + for (operation = m_current; operation != null; operation = operation.getParent()) // Go through all of the operations leading back to the root. + { + index = m_index.get(operation); + + if (index != null) // If a common ancestor is found, stop going back. + break; + + operation.revert(); // Revert the operation since it isn't common to both states. + } + + if (index == null) + index = m_apply.size(); // No common ancestor found. Must apply all of the operations. + + for (i = index; --i >= 0; ) // Apply all of the operations required to get back to the "next" state. + m_apply.get(i).apply(); + + m_index.clear(); + m_apply.clear(); + } + + private void logState() + { + StringBuilder message; + String type; + Integer key, keys[], depth; + int i; + + if (!s_logger.isLoggable(Level.FINER)) + return; + + message = new StringBuilder(); + keys = m_state.keySet().toArray(EMPTY); + + Arrays.sort(keys); + message.append("State | Size = "); + message.append(keys.length); + + for (i = 0; i < keys.length; i++) + { + key = keys[i]; + depth = m_state.get(key); + + if ((key & THREAD_FLAG) != 0) + type = "Thread"; + else + type = "Lock"; + + message.append('\n'); + message.append("Depth = "); + message.append(depth); + message.append(" | Key = "); + message.append(key & ~THREAD_FLAG); + message.append(" | "); + message.append(type); + } + + s_logger.finer(message.toString()); + } + + private void logStack(ThreadInfo thread) + { + if (!s_logger.isLoggable(Level.FINEST)) + return; + + s_logger.finest(thread.getStackTrace()); + } + + private static int makeKey(ElementInfo lock) + { + return(lock.getObjectRef()); + } + + private static int makeKey(ThreadInfo thread) + { + return(thread.getThreadObjectRef() ^ THREAD_FLAG); + } + + private class Operation + { + private final Operation m_parent; + private final Integer m_key; + private final Integer m_oldDepth; + private final Integer m_newDepth; + + public Operation(ElementInfo lock, Integer newDepth) + { + this(makeKey(lock), newDepth); + } + + public Operation(ThreadInfo thread, Integer newDepth) + { + this(makeKey(thread), newDepth); + } + + private Operation(Integer key, Integer newDepth) + { + m_parent = m_current; + m_current = this; + m_key = key; + m_newDepth = newDepth; + m_oldDepth = m_state.get(key); + + apply(); + } + + public Operation getParent() + { + return(m_parent); + } + + public Integer getOldDepth() + { + return(m_oldDepth); + } + + public Integer getNewDepth() + { + return(m_newDepth); + } + + public void apply() + { + change(m_newDepth); + log("Apply "); + } + + public void revert() + { + change(m_oldDepth); + log("Revert"); + } + + private void change(Integer depth) + { + Integer previous; + + if (depth == null) + m_state.remove(m_key); + else + { + previous = m_state.put(m_key, depth); + + assert previous == null; + } + } + + private void log(String header) + { + String message, subheader, depthStr, type; + Integer depth; + + if (!s_logger.isLoggable(Level.FINE)) + return; + + if (m_newDepth != null) + { + subheader = "Add "; + depth = m_newDepth; + } + else + { + subheader = "Remove"; + depth = m_oldDepth; + } + + depthStr = String.valueOf(depth); + + switch (depthStr.length()) + { + case 1: depthStr = " " + depthStr; break; + case 2: depthStr = " " + depthStr; break; + case 3: depthStr = " " + depthStr; break; + default: break; + } + + if ((m_key & THREAD_FLAG) != 0) + type = "Thread"; + else + type = "Lock"; + + message = header + " " + subheader + " | Depth = " + depthStr + " | Key = " + (m_key & ~THREAD_FLAG) + " | " + type; + + s_logger.fine(message); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/LogConsole.java b/src/main/gov/nasa/jpf/listener/LogConsole.java new file mode 100644 index 0000000..bf84b46 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/LogConsole.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * simple logging facility that listens on a socket (e.g. for log output display) + */ +public class LogConsole { + + static int DEF_PORT = 20000; // keep this in sync with the gov.nasa.jpf.util.LogHandler + + class ShutdownHook implements Runnable { + @Override + public void run () { + if (running) { + // not very threadsafe, but worst thing that can happen is we close twice + killed = true; + System.out.println("\nLogConsole killed, shutting down"); + } + try { + cs.close(); + ss.close(); + } catch (Throwable t) { + // not much we can do here anyway + } + } + } + + + boolean running; + + int port; + boolean autoclose; + boolean killed; + + ServerSocket ss; + Socket cs; + + public void run () { + running = true; + Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook())); + + if (port == 0) { + port = DEF_PORT; + } + + try { + ss = new ServerSocket(port); + + try { + do { + System.out.println("LogConsole listening on port: " + port); + + cs = ss.accept(); + BufferedReader in = new BufferedReader( new InputStreamReader(cs.getInputStream())); + String msg; + + System.out.println("LogConsole connected"); + System.out.println("--------------------------------------------------------------------------------"); + try { + + while ((msg = in.readLine()) != null) { + System.out.println(msg); + } + + System.out.println("--------------------------------------------------------------------------------"); + System.out.println("LogConsole disconnected"); + } catch (IOException iox) { + System.err.println(iox); + } + + in.close(); + cs.close(); + } while (!autoclose); + + System.out.println("LogConsole closing"); + + } catch (IOException iox) { + if (!killed) { + System.err.println("Error: LogConsole accept failed on port: " + port); + } + } + + } catch (IOException iox) { + System.err.println("Error: LogConsole cannot listen on port: " + port); + } + + running = false; + } + + public void showUsage () { + System.out.println("LogConsole: socket based console logger"); + System.out.println(" usage: java gov.nasa.jpf.tools.LogConsole {flags} []"); + System.out.println(" args: -help show this message"); + System.out.println(" -autoclose close the application upon disconnect"); + System.out.println(" optional port number, default: " + DEF_PORT); + } + + boolean processArgs (String[] args) { + for (int i=0; i this needs to be refactored with DeadlockAnalyzer - the whole + * trace mgnt (except of the printing) can be made generic + */ +public class MethodAnalyzer extends ListenerAdapter { + + enum OpType { CALL ("> "), // invokeX breaks transition (e.g. blocked sync) + EXECUTE (" - "), // method entered method after transition break + CALL_EXECUTE (">- "), // call & enter within same transition + RETURN (" <"), // method returned + EXEC_RETURN (" -<"), // enter & return in consecutive ops + CALL_EXEC_RETURN (">-<"); // call & enter & return in consecutive ops + String code; + OpType (String code){ this.code = code; } + }; + + static class MethodOp { + OpType type; + + ThreadInfo ti; + ElementInfo ei; + Instruction insn; // the caller + MethodInfo mi; // the callee + int stackDepth; + + // this is used to keep our own trace + int stateId = 0; + MethodOp prevTransition; + MethodOp p; // prev during execution + + MethodOp (OpType type, MethodInfo mi, ThreadInfo ti, ElementInfo ei, int stackDepth){ + this.type = type; + this.ti = ti; + this.mi = mi; + this.ei = ei; + this.stackDepth = stackDepth; + } + + MethodOp clone (OpType newType){ + MethodOp op = new MethodOp(newType, mi, ti, ei, stackDepth); + op.p = p; + return op; + } + + boolean isMethodEnter() { + return (type == OpType.CALL_EXECUTE) || (type == OpType.EXECUTE); + } + + boolean isSameMethod(MethodOp op) { + return (mi == op.mi) && (ti == op.ti) && (ei == op.ei) && (stackDepth == op.stackDepth); + } + + void printOn(PrintWriter pw, MethodAnalyzer analyzer) { + pw.print(ti.getId()); + pw.print(": "); + + pw.print(type.code); + pw.print(' '); + + if (analyzer.showDepth){ + for (int i = 0; i < stackDepth; i++) { + pw.print('.'); + } + pw.print(' '); + } + + if (!mi.isStatic()){ + if (ei.getClassInfo() != mi.getClassInfo()){ // method is in superclass + pw.print(mi.getClassName()); + pw.print('<'); + pw.print(ei); + pw.print('>'); + } else { // method is in concrete object class + pw.print(ei); + } + } else { + pw.print(mi.getClassName()); + } + + pw.print('.'); + + pw.print(Types.getDequalifiedMethodSignature(mi.getUniqueName())); + } + + @Override + public String toString() { + return "Op {" + ti.getName() + ',' + type.code + + ',' + mi.getFullName() + ',' + ei + '}'; + } + } + + // report options + + StringSetMatcher includes = null; // means all + StringSetMatcher excludes = null; // means none + + int maxHistory; + String format; + boolean skipInit; + boolean showDepth; + boolean showTransition; + boolean showCompleted; + + // execution environment + + VM vm; + Search search; + + OpType opType; + + // this is used to keep our own trace + MethodOp lastOp; + MethodOp lastTransition; + boolean isFirstTransition = true; + + // this is set after we call revertAndFlatten during reporting + // (we can't call revertAndFlatten twice since it is destructive, but + // we might have to report several times in case we have several publishers) + MethodOp firstOp = null; + + // for HeuristicSearches. Ok, that's braindead but at least no need for cloning + HashMap storedTransition = new HashMap(); + + + public MethodAnalyzer (Config config, JPF jpf){ + jpf.addPublisherExtension(ConsolePublisher.class, this); + + maxHistory = config.getInt("method.max_history", Integer.MAX_VALUE); + format = config.getString("method.format", "raw"); + skipInit = config.getBoolean("method.skip_init", true); + showDepth = config.getBoolean("method.show_depth", false); + showTransition = config.getBoolean("method.show_transition", false); + + includes = StringSetMatcher.getNonEmpty(config.getStringArray("method.include")); + excludes = StringSetMatcher.getNonEmpty(config.getStringArray("method.exclude")); + + vm = jpf.getVM(); + search = jpf.getSearch(); + } + + + void addOp (VM vm, OpType opType, MethodInfo mi, ThreadInfo ti, ElementInfo ei, int stackDepth){ + if (!(skipInit && isFirstTransition)) { + MethodOp op = new MethodOp(opType, mi, ti, ei, stackDepth); + if (lastOp == null){ + lastOp = op; + } else { + op.p = lastOp; + lastOp = op; + } + } + } + + boolean isAnalyzedMethod (MethodInfo mi){ + if (mi != null){ + String mthName = mi.getFullName(); + return StringSetMatcher.isMatch(mthName, includes, excludes); + } else { + return false; + } + } + + void printOn (PrintWriter pw) { + MethodOp start = firstOp; + int lastStateId = Integer.MIN_VALUE; + int transition = skipInit ? 1 : 0; + int lastTid = start.ti.getId(); + + for (MethodOp op = start; op != null; op = op.p) { + + if (showTransition) { + if (op.stateId != lastStateId) { + lastStateId = op.stateId; + pw.print("------------------------------------------ #"); + pw.println(transition++); + } + } else { + int tid = op.ti.getId(); + if (tid != lastTid) { + lastTid = tid; + pw.println("------------------------------------------"); + } + } + + op.printOn(pw, this); + pw.println(); + } + } + + // warning - this rotates pointers in situ, i.e. destroys the original structure + MethodOp revertAndFlatten (MethodOp start) { + + MethodOp last = null; + MethodOp prevTransition = start.prevTransition; + + for (MethodOp op = start; op != null;) { + MethodOp opp = op.p; + op.p = last; + + if (opp == null) { + if (prevTransition == null) { + return op; + } else { + last = op; + op = prevTransition; + prevTransition = op.prevTransition; + } + } else { + last = op; + op = opp; + } + } + + return null; + } + + //--- SearchListener interface + // <2do> this is the same as DeadlockAnalyzer, except of xxOp type -> refactor + @Override + public void stateAdvanced (Search search){ + + if (search.isNewState() && (lastOp != null)) { + int stateId = search.getStateId(); + + for (MethodOp op=lastOp; op != null; op=op.p) { + op.stateId = stateId; + } + + lastOp.prevTransition = lastTransition; + lastTransition = lastOp; + } + + lastOp = null; + isFirstTransition = false; + } + + @Override + public void stateBacktracked (Search search){ + int stateId = search.getStateId(); + while ((lastTransition != null) && (lastTransition.stateId > stateId)){ + lastTransition = lastTransition.prevTransition; + } + lastOp = null; + } + + @Override + public void stateStored (Search search) { + // always called after stateAdvanced + storedTransition.put(search.getStateId(), lastTransition); + } + + @Override + public void stateRestored (Search search) { + int stateId = search.getStateId(); + MethodOp op = storedTransition.get(stateId); + if (op != null) { + lastTransition = op; + storedTransition.remove(stateId); // not strictly required, but we don't come back + } + } + + + //--- VMlistener interface + @Override + public void instructionExecuted (VM vm, ThreadInfo thread, Instruction nextInsn, Instruction executedInsn) { + ThreadInfo ti; + MethodInfo mi; + ElementInfo ei = null; + + if (executedInsn instanceof JVMInvokeInstruction) { + JVMInvokeInstruction call = (JVMInvokeInstruction)executedInsn; + ti = thread; + mi = call.getInvokedMethod(ti); + + if (isAnalyzedMethod(mi)) { + OpType type; + + // check if this was actually executed, or is a blocked sync call + if (ti.getNextPC() == call) { // re-executed -> blocked or overlayed + type = OpType.CALL; + + } else { // executed + if (ti.isFirstStepInsn()) { + type = OpType.EXECUTE; + } else { + type = OpType.CALL_EXECUTE; + } + } + + if (call instanceof InstanceInvocation) { + ei = ((InstanceInvocation)call).getThisElementInfo(ti); + } + + addOp(vm,type,mi,ti,ei, ti.getStackDepth()); + } + + } else if (executedInsn instanceof JVMReturnInstruction) { + JVMReturnInstruction ret = (JVMReturnInstruction)executedInsn; + ti = thread; + StackFrame frame = ret.getReturnFrame(); + mi = frame.getMethodInfo(); + + if (isAnalyzedMethod(mi)) { + if (!mi.isStatic()) { + int ref = frame.getThis(); + if (ref != MJIEnv.NULL) { + ei = ti.getElementInfo(ref); + } + } + + addOp(vm,OpType.RETURN,mi,ti,ei, ti.getStackDepth()+1); // postExec-> frame already popped + } + } + } + + //--- the PubisherExtension part + @Override + public void publishPropertyViolation (Publisher publisher) { + + if (firstOp == null && lastTransition != null){ // do this just once + firstOp = revertAndFlatten(lastTransition); + } + + if (firstOp == null){ + return; + } + + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("method ops " + publisher.getLastErrorId()); + + + printOn(pw); + } +} diff --git a/src/main/gov/nasa/jpf/listener/MethodTracker.java b/src/main/gov/nasa/jpf/listener/MethodTracker.java new file mode 100644 index 0000000..e52e477 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/MethodTracker.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.INVOKESPECIAL; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.VirtualInvocation; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.PrintWriter; + +/** + * simple tool to log method invocations + * + * at this point, it doesn't do fancy things yet, but gives a more high + * level idea of what got executed by JPF than the ExecTracker + */ +public class MethodTracker extends ListenerAdapter { + + static final String INDENT = " "; + + MethodInfo lastMi; + PrintWriter out; + + public MethodTracker (Config conf, JPF jpf) { + out = new PrintWriter(System.out, true); + } + + void logMethodCall(ThreadInfo ti, MethodInfo mi, int stackDepth) { + out.print(ti.getId()); + out.print(":"); + + for (int i=0; i m_inStack = new HashSet(); + private final ArrayList m_stack = new ArrayList(); + + private int m_cycleFound = -1; + private int m_stackPos = -1; + + public NoStateCycles(Config config) { + if (!config.getString("search.class").equals("gov.nasa.jpf.search.DFSearch")) + config.throwException("search.class must be gov.nasa.jpf.search.DFSearch"); // Or any class which does a depth first search. + } + + @Override + public void stateAdvanced(Search search) { + SystemState state; + Integer id; + + state = search.getVM().getSystemState(); + if (state.isInitState()) + return; + + id = state.getId(); + + if ((m_stackPos < 0) && (m_inStack.contains(id))) { + m_cycleFound = id; + + for (m_stackPos = m_stack.size() - 1; m_stackPos >= 0; m_stackPos--) + if (m_stack.get(m_stackPos).equals(id)) + break; + } + + m_stack.add(id); + m_inStack.add(id); + } + + @Override + public void stateBacktracked(Search search) { + Integer id; + int pos; + + pos = m_stack.size() - 1; + id = m_stack.remove(pos); + m_inStack.remove(id); + + if (m_stackPos >= pos) + m_stackPos = -1; + } + + @Override + public boolean check(Search search, VM vm) { + return(m_cycleFound < 0); + } + + @Override + public void reset () { + m_cycleFound = -1; + } + + @Override + public String getErrorMessage () { + StringBuilder result; + int i, id; + + result = new StringBuilder(); + result.append("States:\n"); + + for (i = m_stack.size() - 1; i >= 0; i--) { + id = m_stack.get(i); + + result.append(" "); + result.append(id); + result.append('\n'); + + if (id == m_cycleFound) + break; + } + + return(result.toString()); + } + + @Override + public String getExplanation () { + return("Finds cycles in states. A cycle suggests that the program might be able to hang."); + } +} diff --git a/src/main/gov/nasa/jpf/listener/NonSharedChecker.java b/src/main/gov/nasa/jpf/listener/NonSharedChecker.java new file mode 100644 index 0000000..1a6654b --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/NonSharedChecker.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.jvm.bytecode.ALOAD; +import gov.nasa.jpf.jvm.bytecode.ARETURN; +import gov.nasa.jpf.jvm.bytecode.ASTORE; +import gov.nasa.jpf.jvm.bytecode.IFNONNULL; +import gov.nasa.jpf.jvm.bytecode.IFNULL; +import gov.nasa.jpf.vm.bytecode.InstanceFieldInstruction; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.jvm.bytecode.MONITORENTER; +import gov.nasa.jpf.jvm.bytecode.VirtualInvocation; +import gov.nasa.jpf.vm.StackFrame; + +/** + * + */ +public class NonSharedChecker extends ListenerAdapter { + + boolean throwOnCycle = false; + + static class Access { + ThreadInfo ti; + Access prev; + + Access(ThreadInfo ti, Access prev){ + this.ti = ti; + this.prev = prev; + } + + // <2do> get a better hashCode for state hashing + public int hashCode() { + int h = ti.getId(); + for (Access p = prev; p!= null; p = p.prev){ + h = 31*h + p.ti.getId(); + } + return h; + } + // but we don't care for equals() + } + + public NonSharedChecker (Config conf){ + throwOnCycle = conf.getBoolean("nonshared.throw_on_cycle"); + } + + boolean isNonShared(ElementInfo ei){ + ClassInfo ci = ei.getClassInfo(); + return (ci.getAnnotation("gov.nasa.jpf.annotation.NonShared") != null); + } + + boolean checkLiveCycles (ElementInfo ei, ThreadInfo ti, Access ac){ + if (ti == ac.ti){ + return true; // Ok, fine - no need to record + + } else { + boolean foundLiveOne = false; + for (Access a = ac; a != null; a = a.prev){ + ThreadInfo t = a.ti; + if (t == ti){ // cycle detected + return !foundLiveOne; + } + foundLiveOne = (foundLiveOne || t.isAlive()); // <2do> maybe we should check for non-blocked threads + } + + // new one, record it in the access history of the object + ac = new Access(ti, ac); + ei = ei.getModifiableInstance(); + ei.setObjectAttr(ac); + } + + return true; + } + + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insn){ + + ElementInfo ei = null; + + if (ti.isFirstStepInsn()) { + return; + } + + if (insn instanceof InstanceFieldInstruction){ + ei = ((InstanceFieldInstruction)insn).peekElementInfo(ti); + } else if (insn instanceof VirtualInvocation){ + ei = ((VirtualInvocation)insn).getThisElementInfo(ti); // Outch - that's expensive + } else if (insn instanceof MONITORENTER || + insn instanceof ASTORE || + insn instanceof ARETURN || + insn instanceof IFNONNULL || + insn instanceof IFNULL) { + StackFrame frame = ti.getTopFrame(); + int ref = frame.peek(); + if (ref != -1){ + ei = ti.getElementInfo(ref); + } + } else if (insn instanceof ALOAD){ + StackFrame frame = ti.getTopFrame(); + int ref = frame.getLocalVariable(((ALOAD)insn).getLocalVariableIndex()); + if (ref != -1){ + ei = ti.getElementInfo(ref); + } + } + + if (ei != null){ + Access ac = ei.getObjectAttr(Access.class); + if (ac != null){ + if (!checkLiveCycles(ei,ti,ac)){ + StringBuilder sb = new StringBuilder("NonShared object: "); + sb.append( ei); + sb.append(" accessed in live thread cycle: "); + sb.append( ti.getName()); + for (Access a = ac; a != null; a = a.prev ){ + sb.append(','); + sb.append(a.ti.getName()); + } + String msg = sb.toString(); + + if (throwOnCycle){ + ti.setNextPC( ti.createAndThrowException("java.lang.AssertionError", msg)); + } else { + System.err.println("WARNING: " + msg); + System.err.println("\tat " + insn.getSourceLocation()); + } + return; + } + } + } + } + + @Override + public void objectCreated (VM vm, ThreadInfo ti, ElementInfo ei){ + if (isNonShared(ei)){ + ei.setObjectAttrNoClone(new Access(ti, null)); + } + } +} + diff --git a/src/main/gov/nasa/jpf/listener/NullTracker.java b/src/main/gov/nasa/jpf/listener/NullTracker.java new file mode 100644 index 0000000..ac7bec8 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/NullTracker.java @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.ARETURN; +import gov.nasa.jpf.jvm.bytecode.ASTORE; +import gov.nasa.jpf.jvm.bytecode.PUTFIELD; +import gov.nasa.jpf.jvm.bytecode.PUTSTATIC; +import gov.nasa.jpf.jvm.bytecode.RETURN; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.LocalVarInfo; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.bytecode.FieldInstruction; +import gov.nasa.jpf.vm.bytecode.InstanceFieldInstruction; +import gov.nasa.jpf.vm.bytecode.InstanceInvokeInstruction; +import gov.nasa.jpf.vm.bytecode.InstructionInterface; +import gov.nasa.jpf.vm.bytecode.InvokeInstruction; +import gov.nasa.jpf.vm.bytecode.LocalVariableInstruction; +import gov.nasa.jpf.vm.bytecode.ReturnInstruction; +import gov.nasa.jpf.vm.bytecode.ReturnValueInstruction; +import gov.nasa.jpf.vm.bytecode.WriteInstruction; +import java.io.PrintWriter; + +/** + * trace where nulls come from - which is either a GETFIELD/STATIC, an + * JVMInvokeInstruction, an LocalVariableInstruction or a missing init. + * + * Record/accumulate the causes in an attribute and use the attribute + * to explain NPEs + */ +public class NullTracker extends ListenerAdapter { + + public static abstract class NullSource { + protected InstructionInterface insn; + protected ThreadInfo ti; + protected ElementInfo ei; + + protected NullSource cause; + + NullSource (ThreadInfo ti, InstructionInterface insn, ElementInfo ei){ + this.ti = ti; + this.insn = insn; + this.ei = ei; + } + + public void setCause (NullSource cause){ + this.cause = cause; + } + + abstract void printOn (PrintWriter pw); + + void printInsnOn (PrintWriter pw){ + pw.printf(" instruction: [%04x] %s\n", insn.getPosition(), insn.toString()); + } + + void printThreadInfoOn (PrintWriter pw){ + pw.println(" executed by: " + ti.getName() + " (id=" + ti.getId() + ")"); + } + + void printMethodInfoOn (PrintWriter pw, String msg, InstructionInterface instruction){ + MethodInfo mi = instruction.getMethodInfo(); + ClassInfo ci = mi.getClassInfo(); + pw.println( msg + ci.getName() + '.' + mi.getLongName() + " (" + instruction.getFilePos() + ')'); + } + + void printCauseOn (PrintWriter pw){ + if (cause != null){ + pw.println("set by: "); + cause.printOn(pw); + } + } + } + + + public static class LocalSource extends NullSource { + protected LocalVarInfo local; + + public LocalSource (ThreadInfo ti, LocalVariableInstruction insn, LocalVarInfo local){ + super(ti, insn, null); + this.local = local; + } + + @Override + void printOn (PrintWriter pw){ + printInsnOn(pw); + if (local != null){ + pw.println(" for local: " + local.getName()); + } else { + pw.println(" for local: #" + ((LocalVariableInstruction)insn).getLocalVariableSlot()); + } + printMethodInfoOn(pw, " in method: ", insn); + printThreadInfoOn(pw); + + printCauseOn(pw); + } + } + + public static class FieldSource extends NullSource { + public FieldSource (ThreadInfo ti, FieldInstruction insn, ElementInfo ei){ + super(ti,insn,ei); + } + + @Override + void printOn (PrintWriter pw){ + FieldInfo fi = ((FieldInstruction)insn).getFieldInfo(); + MethodInfo mi = insn.getMethodInfo(); + + printInsnOn(pw); + pw.println(" for field: " + fi.getFullName()); + printMethodInfoOn(pw, " in method: ", insn); + printThreadInfoOn(pw); + + printCauseOn(pw); + } + } + + public static class MethodSource extends NullSource { + InvokeInstruction call; + + public MethodSource (ThreadInfo ti, InstructionInterface returnInsn, InvokeInstruction call, ElementInfo ei){ + super(ti,returnInsn,ei); + this.call = call; + } + + @Override + void printOn (PrintWriter pw){ + printInsnOn(pw); + printMethodInfoOn(pw, " of method: ", insn); + + if (ei != null){ + pw.println(" for object: " + ei); + } + printMethodInfoOn(pw, " called by: ", call); + printThreadInfoOn(pw); + + printCauseOn(pw); + } + } + + public static class CtorSource extends MethodSource { + public CtorSource (ThreadInfo ti, Instruction returnInsn, InvokeInstruction call, ElementInfo ei){ + super(ti,returnInsn,call, ei); + } + + @Override + void printOn (PrintWriter pw){ + printMethodInfoOn(pw, " missing init: ", insn); + + if (ei != null){ + pw.println(" for object: " + ei); + } + printMethodInfoOn(pw, " called by: ", call); + printThreadInfoOn(pw); + + printCauseOn(pw); + } + } + + //--------------------------------------------------------------------------------- + + protected NullSource nullSource; + + public NullTracker (Config config, JPF jpf){ + jpf.addPublisherExtension(ConsolePublisher.class, this); + } + + protected void checkCtorSourcePre (ThreadInfo ti, ReturnInstruction insn){ + MethodInfo mi = insn.getMethodInfo(); + if (mi.isCtor()) { + StackFrame callerFrame = null; + InvokeInstruction call = null; + ElementInfo ei = ti.getThisElementInfo(); + ClassInfo ci = ei.getClassInfo(); + int nInstance = ci.getNumberOfDeclaredInstanceFields(); + + for (int i = 0; i < nInstance; i++) { + FieldInfo fi = ci.getDeclaredInstanceField(i); + if (fi.isReference()) { + int ref = ei.getReferenceField(fi); + if (ref == MJIEnv.NULL) { + ei = ei.getModifiableInstance(); // why do we need this in a ctor? + if (call == null) { + callerFrame = ti.getCallerStackFrame(); + call = (InvokeInstruction) callerFrame.getPC(); + } + NullSource attr = new CtorSource(ti, insn, call, ti.getThisElementInfo()); + ei.setFieldAttr(fi, attr); + } + } + } + } + } + + protected void checkFieldSourcePre (ThreadInfo ti, WriteInstruction put){ + FieldInfo fi = put.getFieldInfo(); + if (fi.isReference()) { + StackFrame frame = ti.getTopFrame(); + int valSlot = put.getValueSlot(frame); + int ref = frame.getSlot(valSlot); + + if (ref == MJIEnv.NULL) { // field will be set to null + ElementInfo ei = put.getElementInfo(ti); + NullSource attr = new FieldSource(ti, (FieldInstruction)put, ei); + + NullSource cause = frame.getSlotAttr(valSlot, NullSource.class); + if (cause != null) { + attr.setCause(cause); + frame.replaceSlotAttr(valSlot, cause, attr); + } else { + frame.addSlotAttr(valSlot, attr); + } + } + } + } + + protected void checkMethodSourcePre (ThreadInfo ti, ReturnValueInstruction aret){ + StackFrame frame = ti.getTopFrame(); + int valSlot = aret.getValueSlot(frame); + int ref = frame.getSlot(valSlot); + + if (ref == MJIEnv.NULL) { + StackFrame callerFrame = ti.getCallerStackFrame(); + InvokeInstruction call = (InvokeInstruction) callerFrame.getPC(); + NullSource attr = new MethodSource(ti, aret, call, ti.getThisElementInfo()); + + NullSource cause = frame.getSlotAttr(valSlot, NullSource.class); + if (cause != null) { + attr.setCause(cause); + frame.replaceSlotAttr(valSlot,cause, attr); + } else { + frame.addSlotAttr(valSlot,attr); + } + } + } + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insn) { + + if (insn instanceof ARETURN){ + checkMethodSourcePre( ti, (ARETURN)insn); + + } else if (insn instanceof PUTFIELD || insn instanceof PUTSTATIC){ + checkFieldSourcePre( ti, (WriteInstruction) insn); + + } else if (insn instanceof RETURN){ + checkCtorSourcePre(ti, (RETURN) insn); + } + } + + + protected void checkLocalSourcePost (ThreadInfo ti, LocalVariableInstruction insn){ + int slotIdx = insn.getLocalVariableSlot(); + StackFrame frame = ti.getTopFrame(); + int ref = frame.getSlot(slotIdx); + if (ref == MJIEnv.NULL) { + LocalVarInfo lv = insn.getLocalVarInfo(); + NullSource attr = new LocalSource(ti, insn, lv); + + NullSource cause = frame.getSlotAttr(slotIdx, NullSource.class); + if (cause != null) { + attr.setCause(cause); + frame.replaceSlotAttr(slotIdx, cause, attr); + } else { + frame.addSlotAttr(slotIdx, attr); + } + } + } + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction insn){ + + // we need to do LocalVariableInstruction post exec since it did overwrite the attr if it had an immediate operand + if (insn instanceof ASTORE) { + checkLocalSourcePost( ti, (LocalVariableInstruction)insn); + } + } + + @Override + public void exceptionThrown(VM vm, ThreadInfo ti, ElementInfo thrownException) { + if (thrownException.instanceOf("Ljava/lang/NullPointerException;")){ + StackFrame frame = ti.getTopFrame(); + Instruction insn = ti.getPC(); + + if (insn instanceof InstanceFieldInstruction){ // field access on null object + int objSlot = ((InstanceFieldInstruction)insn).getObjectSlot(frame); + NullSource attr = frame.getSlotAttr( objSlot,NullSource.class); + if (attr != null) { + nullSource = attr; + } + + } else if (insn instanceof InstanceInvokeInstruction) { // call on a null object + int objSlot = ((InstanceInvokeInstruction)insn).getObjectSlot(frame); + NullSource attr = frame.getSlotAttr( objSlot, NullSource.class); + if (attr != null) { + nullSource = attr; + } + } + } + } + + + @Override + public void publishPropertyViolation (Publisher publisher) { + if (nullSource != null){ // otherwise we don't have anything to report + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("NullTracker " + publisher.getLastErrorId()); + + pw.println("null value set by: "); + nullSource.printOn(pw); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/NumericValueChecker.java b/src/main/gov/nasa/jpf/listener/NumericValueChecker.java new file mode 100644 index 0000000..ee7da7e --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/NumericValueChecker.java @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPFConfigException; +import gov.nasa.jpf.PropertyListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.*; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.FieldSpec; +import gov.nasa.jpf.util.VarSpec; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.LocalVarInfo; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * little listener that checks value ranges of specified numeric fields and local vars + * + * configuration examples: + * + * range.fields=speed,.. + * range.speed.field=x.y.SomeClass.velocity + * range.speed.min=300 + * range.speed.max=500 + * + * range.vars=altitude,.. + * range.altitude.var=x.y.SomeClass.computeTrajectory(int):a + * range.altitude.min=125000 + * + */ +public class NumericValueChecker extends PropertyListenerAdapter { + + static abstract class RangeCheck { + double min, max; + + RangeCheck (double min, double max){ + this.min = min; + this.max = max; + } + + String check (long v){ + if (v < (long)min){ + return String.format("%d < %d", v, (long)min); + } else if (v > (long)max){ + return String.format("%d > %d", v, (long)max); + } + return null; + } + String check (double v){ + if (v < min){ + return String.format("%f < %f", v, min); + } else if (v > (long)max){ + return String.format("%f > %f", v, max); + } + return null; + } + } + + static class FieldCheck extends RangeCheck { + FieldSpec fspec; + + FieldCheck (FieldSpec fspec, double min, double max){ + super(min,max); + this.fspec = fspec; + } + + boolean matches (FieldInfo fi){ + return fspec.matches(fi); + } + } + + static class VarCheck extends RangeCheck { + VarSpec vspec; + + VarCheck (VarSpec vspec, double min, double max){ + super(min,max); + this.vspec = vspec; + } + + LocalVarInfo getMatch (MethodInfo mi, int pc, int slotIdx){ + return vspec.getMatchingLocalVarInfo(mi, pc, slotIdx); + } + } + + class Visitor extends JVMInstructionVisitorAdapter { + + void checkFieldInsn (JVMFieldInstruction insn){ + if (fieldChecks != null){ + FieldInfo fi = insn.getFieldInfo(); + + for (int i = 0; i < fieldChecks.length; i++) { + FieldCheck fc = fieldChecks[i]; + if (fc.matches(fi)) { + if (fi.isNumericField()) { + long lv = insn.getLastValue(); + String errorCond = fi.isFloatingPointField() + ? fc.check(Double.longBitsToDouble(lv)) : fc.check(lv); + + if (errorCond != null) { + error = String.format("field %s out of range: %s\n\t at %s", + fi.getFullName(), errorCond, insn.getSourceLocation()); + vm.breakTransition("fieldValueOutOfRange"); // terminate this transition + break; + } + } + } + } + } + } + + void checkVarInsn (JVMLocalVariableInstruction insn){ + if (varChecks != null){ + ThreadInfo ti = ThreadInfo.getCurrentThread(); + StackFrame frame = ti.getTopFrame(); + int slotIdx = insn.getLocalVariableIndex(); + + for (int i = 0; i < varChecks.length; i++) { + VarCheck vc = varChecks[i]; + + MethodInfo mi = insn.getMethodInfo(); + int pc = insn.getPosition()+1; // the scope would begin on the next insn, we are still at the xSTORE + LocalVarInfo lvar = vc.getMatch(mi, pc, slotIdx); + if (lvar != null) { + long v = lvar.getSlotSize() == 1 ? frame.getLocalVariable(slotIdx) : frame.getLongLocalVariable(slotIdx); + String errorCond = lvar.isFloatingPoint() + ? vc.check(Double.longBitsToDouble(v)) : vc.check(v); + + if (errorCond != null) { + error = String.format("local variable %s out of range: %s\n\t at %s", + lvar.getName(), errorCond, insn.getSourceLocation()); + vm.breakTransition("localVarValueOutOfRange"); // terminate this transition + break; + } + } + } + } + } + + @Override + public void visit(PUTFIELD insn){ + checkFieldInsn(insn); + } + @Override + public void visit(PUTSTATIC insn){ + checkFieldInsn(insn); + } + + @Override + public void visit(ISTORE insn){ + checkVarInsn(insn); + } + @Override + public void visit(LSTORE insn){ + checkVarInsn(insn); + } + @Override + public void visit(FSTORE insn){ + checkVarInsn(insn); + } + @Override + public void visit(DSTORE insn){ + checkVarInsn(insn); + } + + } + + + VM vm; + Visitor visitor; + + // the stuff we monitor + FieldCheck[] fieldChecks; + VarCheck[] varChecks; + + String error; // where we store errorCond details + + public NumericValueChecker (Config conf){ + visitor = new Visitor(); + + createFieldChecks(conf); + createVarChecks(conf); + } + + private void createFieldChecks(Config conf){ + String[] checkIds = conf.getCompactTrimmedStringArray("range.fields"); + if (checkIds.length > 0){ + fieldChecks = new FieldCheck[checkIds.length]; + + for (int i = 0; i < checkIds.length; i++) { + String id = checkIds[i]; + FieldCheck check = null; + String keyPrefix = "range." + id; + String spec = conf.getString(keyPrefix + ".field"); + if (spec != null) { + FieldSpec fs = FieldSpec.createFieldSpec(spec); + if (fs != null) { + double min = conf.getDouble(keyPrefix + ".min", Double.MIN_VALUE); + double max = conf.getDouble(keyPrefix + ".max", Double.MAX_VALUE); + check = new FieldCheck(fs, min, max); + } + } + if (check == null) { + throw new JPFConfigException("illegal field range check specification for " + id); + } + fieldChecks[i] = check; + } + } + } + + private void createVarChecks(Config conf){ + String[] checkIds = conf.getCompactTrimmedStringArray("range.vars"); + if (checkIds.length > 0){ + varChecks = new VarCheck[checkIds.length]; + + for (int i = 0; i < checkIds.length; i++) { + String id = checkIds[i]; + VarCheck check = null; + String keyPrefix = "range." + id; + String spec = conf.getString(keyPrefix + ".var"); + if (spec != null) { + VarSpec vs = VarSpec.createVarSpec(spec); + if (vs != null) { + double min = conf.getDouble(keyPrefix + ".min", Double.MIN_VALUE); + double max = conf.getDouble(keyPrefix + ".max", Double.MAX_VALUE); + check = new VarCheck(vs, min, max); + } + } + if (check == null) { + throw new JPFConfigException("illegal variable range check specification for " + id); + } + varChecks[i] = check; + } + } + } + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){ + this.vm = vm; + ((JVMInstruction)executedInsn).accept(visitor); + } + + @Override + public boolean check(Search search, VM vm) { + return (error == null); + } + + @Override + public void reset () { + error = null; + } + + @Override + public String getErrorMessage(){ + return error; + } +} diff --git a/src/main/gov/nasa/jpf/listener/OOMEInjector.java b/src/main/gov/nasa/jpf/listener/OOMEInjector.java new file mode 100644 index 0000000..1af58f1 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/OOMEInjector.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import java.util.ArrayList; +import java.util.List; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.NEW; +import gov.nasa.jpf.util.LocationSpec; +import gov.nasa.jpf.util.TypeSpec; +import gov.nasa.jpf.vm.bytecode.NewInstruction; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * simulator for OutOfMemoryErrors. This can be configured to either + * fire for a specified location range (file:line) or specified types. + * Ranges are transitive, i.e. everything called from within it should also + * trigger. + * + * Since our only action is to inject OutOfMemoryErrors, we don't need + * to implement a Property interface + */ +public class OOMEInjector extends ListenerAdapter { + + static class OOME {} + static OOME throwOOME = new OOME(); // we can reuse the same object as an attribute + + List locations = new ArrayList(); + List types = new ArrayList(); + + public OOMEInjector (Config config, JPF jpf){ + String[] spec = config.getStringArray("oome.locations"); + if (spec != null){ + for (String s : spec){ + LocationSpec locSpec = LocationSpec.createLocationSpec(s); + if (locSpec != null){ + locations.add(locSpec); + } + } + } + + spec = config.getStringArray("oome.types"); + if (spec != null){ + for (String s : spec){ + TypeSpec typeSpec = TypeSpec.createTypeSpec(s); + if (typeSpec != null){ + types.add(typeSpec); + } + } + } + } + + protected void markMatchingInstructions (MethodInfo mi, LocationSpec locSpec){ + int first = locSpec.getFromLine(); + int[] lineNumbers = mi.getLineNumbers(); + + if (lineNumbers != null && first >= lineNumbers[0]){ + int last = locSpec.getToLine(); + for (int i=0; i sel = new StateExtensionListener(this); + jpf.addSearchListener(sel); + } + + + //--- reporting + + @Override + public void publishPropertyViolation (Publisher publisher) { + if (log != null){ // otherwise we don't have anything to report + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("ObjectTracker " + publisher.getLastErrorId()); + printLogOn(pw); + } + } + + protected void printLogOn (PrintWriter pw){ + // the log can be quite long so we can't use recursion (Java does not optimize tail recursion) + List logRecs = new ArrayList(); + for (LogRecord lr = log; lr != null; lr = lr.prev){ + logRecs.add(lr); + } + + Collections.reverse(logRecs); + + for (LogRecord lr : logRecs){ + lr.printOn(pw); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/OverlappingMethodAnalyzer.java b/src/main/gov/nasa/jpf/listener/OverlappingMethodAnalyzer.java new file mode 100644 index 0000000..66f5c4c --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/OverlappingMethodAnalyzer.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.PrintWriter; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * this is a specialized MethodAnalyzer that looks for overlapping method + * calls on the same object from different threads. + * + * <2do> transition reporting does not work yet + */ +public class OverlappingMethodAnalyzer extends MethodAnalyzer { + + public OverlappingMethodAnalyzer (Config config, JPF jpf){ + super(config,jpf); + } + + MethodOp getReturnOp (MethodOp op, boolean withinSameThread){ + MethodInfo mi = op.mi; + int stateId = op.stateId; + int stackDepth = op.stackDepth; + ElementInfo ei = op.ei; + ThreadInfo ti = op.ti; + + for (MethodOp o = op.p; o != null; o = o.p){ + if (withinSameThread && o.ti != ti){ + break; + } + + if ((o.mi == mi) && (o.ti == ti) && (o.stackDepth == stackDepth) && (o.ei == ei)){ + return o; + } + } + + return null; + } + + // check if there is an open exec from another thread for the same ElementInfo + boolean isOpenExec (HashMap> openExecs, MethodOp op){ + ThreadInfo ti = op.ti; + ElementInfo ei = op.ei; + + for (Map.Entry> e : openExecs.entrySet()) { + if (e.getKey() != ti) { + Deque s = e.getValue(); + for (Iterator it = s.descendingIterator(); it.hasNext();) { + MethodOp o = it.next(); + if (o.ei == ei) { + return true; + } + } + } + } + + return false; + } + + // clean up (if necessary) - both RETURNS and exceptions + void cleanUpOpenExec (HashMap> openExecs, MethodOp op){ + ThreadInfo ti = op.ti; + int stackDepth = op.stackDepth; + + Deque stack = openExecs.get(ti); + if (stack != null && !stack.isEmpty()) { + for (MethodOp o = stack.peek(); o != null && o.stackDepth >= stackDepth; o = stack.peek()) { + stack.pop(); + } + } + } + + void addOpenExec (HashMap> openExecs, MethodOp op){ + ThreadInfo ti = op.ti; + Deque stack = openExecs.get(ti); + + if (stack == null){ + stack = new ArrayDeque(); + stack.push(op); + openExecs.put(ti, stack); + + } else { + stack.push(op); + } + } + + @Override + void printOn (PrintWriter pw) { + MethodOp start = firstOp; + + HashMap> openExecs = new HashMap>(); + + int lastStateId = -1; + int lastTid = start.ti.getId(); + + for (MethodOp op = start; op != null; op = op.p) { + + cleanUpOpenExec(openExecs, op); + + if (op.isMethodEnter()) { // EXEC or CALL_EXEC + MethodOp retOp = getReturnOp(op, true); + if (retOp != null) { // completed, skip + if (!isOpenExec(openExecs, op)) { + op = retOp; + lastStateId = op.stateId; + continue; + } + } else { // this is an open method exec, record it + addOpenExec(openExecs, op); + } + } + + op = consolidateOp(op); + + if (showTransition) { + if (op.stateId != lastStateId) { + if (lastStateId >= 0){ + pw.print("------------------------------------------ #"); + pw.println(lastStateId); + } + } + lastStateId = op.stateId; + + } else { + int tid = op.ti.getId(); + if (tid != lastTid) { + lastTid = tid; + pw.println("------------------------------------------"); + } + } + + op.printOn(pw, this); + pw.println(); + } + } + + MethodOp consolidateOp (MethodOp op){ + for (MethodOp o = op.p; o != null; o = o.p){ + if (showTransition && (o.stateId != op.stateId)){ + break; + } + if (o.isSameMethod(op)){ + switch (o.type) { + case RETURN: + switch (op.type){ + case CALL_EXECUTE: + op = o.clone(OpType.CALL_EXEC_RETURN); break; + case EXECUTE: + op = o.clone(OpType.EXEC_RETURN); break; + } + break; + case EXEC_RETURN: + switch (op.type){ + case CALL: + op = o.clone(OpType.CALL_EXEC_RETURN); break; + } + break; + case CALL_EXECUTE: // simple loop + switch (op.type){ + case CALL_EXEC_RETURN: + op = o; + } + break; + } + } else { + break; + } + } + + return op; + } +} diff --git a/src/main/gov/nasa/jpf/listener/PathOutputMonitor.java b/src/main/gov/nasa/jpf/listener/PathOutputMonitor.java new file mode 100644 index 0000000..abd6252 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/PathOutputMonitor.java @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.PropertyListenerAdapter; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Path; +import gov.nasa.jpf.vm.Transition; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * listener that monitors path output, matching it against specifications + * supplied as text files. Per default, this uses simple line-by-line + * regular expression matching, also supporting prefixes by means of + * special ". . ." ellipsis patterns. Each file can contain a number of + * path output specs, separated by "~~~~~" lines. + * + * The major purpose of this listener is to verify JPF state spaces, + * but it can also be used as a functional property + */ +public class PathOutputMonitor extends PropertyListenerAdapter { + + static final String SEPARATOR = "~~~"; + static final String ELLIPSIS = "..."; + + static Logger log = JPF.getLogger("gov.nasa.jpf.listener.PathOutputMonitor"); + + public interface PathOutputSpec { + boolean add (String spec); + boolean matches (String[] output); + void printOn (PrintWriter pw); + boolean isEmpty(); + } + + static class VerbatimOutputSpec implements PathOutputSpec { + ArrayList patterns = new ArrayList(); + + @Override + public boolean add (String spec) { + patterns.add(spec); + return true; + } + + @Override + public boolean matches (String[] output) { + if ((output != null) && (output.length > 0)) { + Iterator it = patterns.iterator(); + for (String line : output) { + if (it.hasNext()) { + String p = it.next(); + if (!p.equals(line)){ + return false; + } + } else { + return false; + } + } + + return !it.hasNext(); + + } else { + return patterns.isEmpty(); + } + } + + // sometimes, duck typing would be nice.. + + @Override + public void printOn (PrintWriter pw) { + for (String p : patterns) { + pw.println(p.toString()); + } + } + + @Override + public boolean isEmpty(){ + return patterns.isEmpty(); + } + } + + // simple regular expression matchers (could be a more sophisticated parser) + static class RegexOutputSpec implements PathOutputSpec { + ArrayList patterns = new ArrayList(); + + @Override + public boolean add (String spec) { + try { + Pattern p = Pattern.compile(spec); + patterns.add(p); + } catch (PatternSyntaxException psx) { + return false; + } + + return true; + } + + @Override + public boolean matches (String[] output) { + + if ((output != null) && (output.length > 0)) { + Iterator it = patterns.iterator(); + for (String line : output) { + if (it.hasNext()) { + Pattern p = it.next(); + + if (p.toString().equals(ELLIPSIS)) { + return true; + } + + Matcher m = p.matcher(line); + if (!m.matches()) { + return false; + } + } else { + return false; + } + } + + return (!it.hasNext() || it.next().toString().equals(ELLIPSIS)); + + } else { // no output + return patterns.isEmpty(); + } + } + + @Override + public void printOn (PrintWriter pw) { + for (Pattern p : patterns) { + pw.println(p.toString()); + } + } + + @Override + public boolean isEmpty(){ + return patterns.isEmpty(); + } + } + + //---- our instance data + VM vm; + + //--- this is where we store the outputs (line-wise) + // <2do> not very space efficient + List pathOutputs = new ArrayList(); + + //--- config options + Class psClass; + boolean printOutput; + boolean deferOutput; + List anySpecs, allSpecs, noneSpecs; + + //--- keep track of property violations + String errorMsg; + List violatedSpecs; + String[] offendingOutput; + + + public PathOutputMonitor (Config config, JPF jpf) { + vm = jpf.getVM(); + vm.storePathOutput(); + + jpf.addPublisherExtension(ConsolePublisher.class, this); + + printOutput = config.getBoolean("pom.print_output", true); + deferOutput = config.getBoolean("pom.defer_output", true); + + psClass = config.getClass("pom.output_spec.class", PathOutputSpec.class); + + if (psClass == null) { + psClass = RegexOutputSpec.class; + } + + anySpecs = loadSpecs(config, "pom.any"); + allSpecs = loadSpecs(config, "pom.all"); + noneSpecs = loadSpecs(config, "pom.none"); + + violatedSpecs = new ArrayList(); + } + + + List loadSpecs(Config conf, String key) { + String spec = conf.getString(key); + if (spec != null) { + if (spec.startsWith("\"")){ // spec is in-situ content (convenience method for test classes) + spec = spec.substring(1, spec.length()-1); + BufferedReader br = new BufferedReader( new StringReader(spec)); + return readPathPatterns(br); + + } else { // spec is pathname of output sepc file + File file = new File(spec); + try { + BufferedReader br = new BufferedReader( new FileReader(file)); + return readPathPatterns(br); + + } catch (FileNotFoundException fnfx){ + log.warning("pattern file not found: " + spec); + } + } + } + + return null; + } + + PathOutputSpec createPathOutputSpec() { + try { + return psClass.newInstance(); + } catch (Throwable t) { + log.severe("cannot instantiate PathoutputSpec class: " + t.getMessage()); + return null; + } + } + + + + List readPathPatterns (BufferedReader br){ + ArrayList results = new ArrayList(); + + // prefix pattern goes into file + + try { + PathOutputSpec ps = createPathOutputSpec(); + + int lineno = 0; + for (String line=br.readLine(); true; line = br.readLine()) { + if (line == null) { + results.add(ps); + break; + } + lineno++; + + if (line.startsWith(SEPARATOR)) { + results.add(ps); + ps = createPathOutputSpec(); + } else { + ps.add(line); + } + } + + br.close(); + } catch (FileNotFoundException fnfx) { + return null; + } catch (IOException e) { + e.printStackTrace(); + } + + return results; + } + + String[] getLines (String output) { + ArrayList lines = new ArrayList(); + BufferedReader br = new BufferedReader(new StringReader(output)); + try { + for (String line = br.readLine(); line != null; line = br.readLine()) { + lines.add(line); + } + } catch (IOException iox) { + iox.printStackTrace(); + } + + return lines.toArray(new String[lines.size()]); + } + + boolean matchesAny (List outputSpecs, String[] lines) { + for (PathOutputSpec ps : outputSpecs) { + if (ps.matches(lines)) { + return true; + } + } + + errorMsg = "unmatched output"; + offendingOutput = lines; + + return false; + } + + boolean matchesNone (List outputSpecs, String[] lines) { + for (PathOutputSpec ps : outputSpecs) { + if (ps.matches(lines)) { + errorMsg = "illegal output (matching inverse spec)"; + offendingOutput = lines; + violatedSpecs.add(ps); + + return false; + } + } + + return true; + } + + boolean matchesAll (List outputSpecs, List outputs) { + HashSet unmatched = new HashSet(); + unmatched.addAll(outputSpecs); + + for (String[] lines : outputs) { + for (PathOutputSpec ps : outputSpecs) { + if (ps.matches(lines)) { + unmatched.remove(ps); + if (unmatched.isEmpty()) { + return true; + } + } + } + } + + errorMsg = "unmatched specs (" + unmatched.size() + ')'; + for (PathOutputSpec ps : unmatched) { + violatedSpecs.add(ps); + } + + return false; + } + + + //----------- the listener interface + + @Override + public boolean check(Search search, VM vm) { + return (errorMsg == null); + } + + @Override + public String getErrorMessage () { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + pw.println(errorMsg); + + if (offendingOutput != null) { + pw.println("offending output:"); + for (String line : offendingOutput) { + pw.println(line); + } + } + + if (!violatedSpecs.isEmpty()) { + pw.println("violated specs:"); + for (PathOutputSpec ps : violatedSpecs) { + ps.printOn(pw); + pw.println(SEPARATOR); + } + + } + + String s = sw.toString(); + pw.close(); + + return s; + } + + @Override + public void reset () { + errorMsg = null; + violatedSpecs.clear(); + offendingOutput = null; + } + + @Override + public void stateAdvanced(Search search) { + if (search.isEndState()) { + + Path path = vm.getPath(); + if (path.hasOutput()) { + StringBuilder sb = null; + + if (deferOutput || (noneSpecs != null)) { + sb = new StringBuilder(); + for (Transition t : path) { + String s = t.getOutput(); + if (s != null){ + sb.append(s); + } + } + } + + String[] lines = getLines(sb.toString()); + + if (deferOutput) { + pathOutputs.add(lines); + + } else if (printOutput){ + for (Transition t : path) { + String s = t.getOutput(); + if (s != null){ + System.out.print(s); // <2do> don't use System.out + } + } + } + + // check safety properties + if (noneSpecs != null && !matchesNone(noneSpecs, lines)) { + log.warning("pom.none violated"); + } + if (anySpecs != null && !matchesAny(anySpecs, lines)) { + log.warning("pom.any violated"); + } + + } + } + } + + @Override + public void searchFinished (Search search) { + if (allSpecs != null && !matchesAll(allSpecs, pathOutputs)) { + log.warning("pom.all violated"); + search.error(this); + } + } + + @Override + public void publishFinished (Publisher publisher) { + + if (printOutput) { + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("path outputs"); + for (String[] output : pathOutputs) { + for (String line : output) { + pw.println(line); + } + pw.println(SEPARATOR); + } + } + } + +} diff --git a/src/main/gov/nasa/jpf/listener/Perturbator.java b/src/main/gov/nasa/jpf/listener/Perturbator.java new file mode 100644 index 0000000..0eaac2b --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/Perturbator.java @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.GETFIELD; +import gov.nasa.jpf.jvm.bytecode.JVMInstanceFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMReturnInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.perturb.OperandPerturbator; +import gov.nasa.jpf.util.FieldSpec; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.util.MethodSpec; +import gov.nasa.jpf.util.SourceRef; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.SystemState; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * listener that perturbs GETFIELD/GETSTATIC and JVMInvokeInstruction results + * + * NOTE - this listener initializes in two steps: (1) during listener construction + * it builds a list of classes it has to monitor, and (2) during class load + * time it further analyzes classes from this list to get the actual target + * objects (FieldInfos and MethodInfos) so that instruction monitoring is + * efficient enough. + * + * This means the listener always has to be instantiated BEFORE the respective + * target classes get loaded. + * + * configuration example: + * + * # field getter example + * perturb.fields = altitude,... + * perturb.altitude.field = x.y.MyClass.alt + * perturb.altitude.class = .perturb.IntOverUnder + * perturb.altitude.location = MyClass.java:42 + * perturb.altitude.delta = 1 + * + * # method return value example + * perturb.returns = velocity,... + * perturb.velocity.method = x.y.MyClass.computeVelocity() + * perturb.velocity.class = .perturb.IntOverUnder + * perturb.velocity.delta = 50 + * + * # method parameter perturbation example + * perturb.params = foo, ... + * perturb.foo.method = x.y.MyClass.send(int, float, boolean) + * perturb.foo.location = MyClass.java:42 + * perturb.class = .perturb.dataAbstractor + * + */ + +public class Perturbator extends ListenerAdapter { + + static JPFLogger log = JPF.getLogger("gov.nasa.jpf.Perturbator"); + + public static class Perturbation { + SourceRef sref; // location where field access should be perturbed + Class> cgType; // needs to be compatible with field type + OperandPerturbator perturbator; + + Perturbation (OperandPerturbator perturbator, String loc){ + this.perturbator = perturbator; + + if (loc != null){ + sref = new SourceRef(loc); + } + } + } + + public static class FieldPerturbation extends Perturbation { + FieldSpec fieldSpec; + + FieldPerturbation (FieldSpec fieldSpec, OperandPerturbator perturbator, String loc){ + super(perturbator, loc); + + this.fieldSpec = fieldSpec; + } + } + + public static class ReturnPerturbation extends Perturbation { + MethodSpec mthSpec; + + ReturnPerturbation (MethodSpec mthSpec, OperandPerturbator perturbator, String loc){ + super(perturbator, loc); + + this.mthSpec = mthSpec; + } + } + + public static class ParamsPerturbation extends Perturbation { + public MethodSpec mthSpec; + + ParamsPerturbation (MethodSpec mthSpec, OperandPerturbator perturbator, String loc) { + super(perturbator, loc); + + this.mthSpec = mthSpec; + } + } + + protected static Class[] argTypes = { Config.class, String.class }; + + protected List fieldWatchList = new ArrayList(); + protected HashMap perturbedFields = new HashMap(); + + protected List returnWatchList = new ArrayList(); + protected HashMap perturbedReturns = new HashMap(); + + protected List paramsWatchList = new ArrayList(); + protected HashMap perturbedParams = new HashMap(); + + protected StackFrame savedFrame; + + public Perturbator (Config conf){ + + // in the ctor we only find out which classname patterns we have to watch + // for, and store them in a list (together with their partially initialized + // Perturbation instances) that is to be checked upon classLoaded notifications + + // get the configured field perturbators + String[] fieldIds = conf.getCompactTrimmedStringArray("perturb.fields"); + for (String id : fieldIds){ + addToFieldWatchList(conf, id); + } + + String[] returnIds = conf.getCompactTrimmedStringArray("perturb.returns"); + for (String id : returnIds){ + addToReturnWatchList(conf, id); + } + + String[] paramsIds = conf.getCompactTrimmedStringArray("perturb.params"); + for (String id: paramsIds) { + addToParamsWatchList(conf, id); + } + } + + public boolean isMethodWatched(Instruction insn, MethodInfo mi) { + ParamsPerturbation e = perturbedParams.get(mi); + if (e != null && isRelevantCallLocation(insn, e)){ + return true; + } + return false; + } + + protected void addToFieldWatchList (Config conf, String id){ + String keyPrefix = "perturb." + id; + + String fs = conf.getString(keyPrefix + ".field"); + if (fs != null) { + FieldSpec fieldSpec = FieldSpec.createFieldSpec(fs); + if (fieldSpec != null){ + Object[] args = {conf, keyPrefix}; + OperandPerturbator perturbator = conf.getInstance(keyPrefix + ".class", OperandPerturbator.class, argTypes, args); + if (perturbator != null) { + String loc = conf.getString(keyPrefix + ".location"); + FieldPerturbation p = new FieldPerturbation(fieldSpec, perturbator, loc); + fieldWatchList.add(p); + } else { + log.warning("invalid perturbator spec for ", keyPrefix); + } + } else { + log.warning("malformed field specification for ", keyPrefix); + } + + } else { + log.warning("missing field specification for ", keyPrefix); + } + } + + protected void addToReturnWatchList (Config conf, String id){ + String keyPrefix = "perturb." + id; + + String ms = conf.getString(keyPrefix + ".method"); + if (ms != null) { + MethodSpec mthSpec = MethodSpec.createMethodSpec(ms); + if (mthSpec != null) { + Object[] args = {conf, keyPrefix}; + OperandPerturbator perturbator = conf.getInstance(keyPrefix + ".class", OperandPerturbator.class, argTypes, args); + if (perturbator != null) { + String loc = conf.getString(keyPrefix + ".location"); + ReturnPerturbation p = new ReturnPerturbation(mthSpec, perturbator, loc); + returnWatchList.add(p); + } else { + log.warning("invalid perturbator spec for ", keyPrefix); + } + + } else { + log.warning("malformed method specification for ", keyPrefix); + } + + } else { + log.warning("missing method specification for ", keyPrefix); + } + } + + protected void addToParamsWatchList (Config conf, String id){ + String keyPrefix = "perturb." + id; + + String ms = conf.getString(keyPrefix + ".method"); + if (ms != null) { + MethodSpec mthSpec = MethodSpec.createMethodSpec(ms); + if (mthSpec != null) { + Object[] args = {conf, keyPrefix}; + OperandPerturbator perturbator = conf.getInstance(keyPrefix + ".class", OperandPerturbator.class, argTypes, args); + if (perturbator != null) { + String loc = conf.getString(keyPrefix + ".location"); + ParamsPerturbation p = new ParamsPerturbation(mthSpec, perturbator, loc); + paramsWatchList.add(p); + } else { + log.warning("invalid perturbator spec for ", keyPrefix); + } + + } else { + log.warning("malformed method specification for ", keyPrefix); + } + } else { + log.warning("missing method specification for ", keyPrefix); + } + } + + @Override + public void classLoaded (VM vm, ClassInfo loadedClass){ + // this one takes the watchlists, finds out if the loaded class matches + // any of the watch entries, and in case it does fully initializes + // the corresponding Perturbation object with the target construct + // (MethodInfo, FieldInfo) we use to identify relevant ops during + // instruction execution notifications + + String clsName = loadedClass.getName(); + + for (FieldPerturbation p : fieldWatchList){ + FieldSpec fs = p.fieldSpec; + if (fs.isMatchingType(loadedClass)){ + addFieldPerturbations( p, loadedClass, loadedClass.getDeclaredInstanceFields()); + addFieldPerturbations( p, loadedClass, loadedClass.getDeclaredStaticFields()); + } + } + + for (ReturnPerturbation p : returnWatchList){ + MethodSpec ms = p.mthSpec; + if (ms.isMatchingType(loadedClass)){ + for (MethodInfo mi : loadedClass.getDeclaredMethodInfos()){ + if (ms.matches(mi)){ + Class> returnCGType = mi.getReturnChoiceGeneratorType(); + Class> perturbatorCGType = p.perturbator.getChoiceGeneratorType(); + if (returnCGType.isAssignableFrom(perturbatorCGType)){ + p.cgType = returnCGType; + perturbedReturns.put(mi, p); + } else { + log.warning("method " + mi + " not compatible with perturbator choice type " + perturbatorCGType.getName()); + } + } + } + } + } + + for (ParamsPerturbation p : paramsWatchList){ + MethodSpec ms = p.mthSpec; + if (ms.isMatchingType(loadedClass)){ + for (MethodInfo mi : loadedClass.getDeclaredMethodInfos()){ + if (ms.matches(mi)){ + // We simply associate the method with the parameters perturbator + Class> perturbatorCGType = p.perturbator.getChoiceGeneratorType(); + p.cgType = perturbatorCGType; + perturbedParams.put(mi, p); + } + } + } + } + } + + protected void addFieldPerturbations (FieldPerturbation p, ClassInfo ci, FieldInfo[] fieldInfos){ + for (FieldInfo fi : ci.getDeclaredInstanceFields()) { + if (p.fieldSpec.matches(fi)) { + Class> fieldCGType = fi.getChoiceGeneratorType(); + Class> perturbatorCGType = p.perturbator.getChoiceGeneratorType(); + if (fieldCGType.isAssignableFrom(perturbatorCGType)) { + p.cgType = fieldCGType; + perturbedFields.put(fi, p); + } else { + log.warning("field " + fi + " not compatible with perturbator choice type " + perturbatorCGType.getName()); + } + } + } + } + + protected boolean isRelevantCallLocation (ThreadInfo ti, Perturbation p){ + if (p.sref == null){ + // no caller location specified -> all calls relevant + return true; + } else { + StackFrame caller = ti.getCallerStackFrame(); + if (caller != null) { + Instruction invokeInsn = caller.getPC(); + return p.sref.equals(invokeInsn.getFilePos()); + } else { + return false; + } + } + } + + protected boolean isRelevantCallLocation (Instruction invokeInsn, Perturbation p) { + // For parameter perturbation, we are about to enter a method + // and hence can directly use the invoke instruction to get the file + // location of the call + if (p.sref == null) + return true; + else + return p.sref.equals(invokeInsn.getFilePos()); + } + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insnToExecute){ + + if (insnToExecute instanceof GETFIELD){ + FieldInfo fi = ((JVMInstanceFieldInstruction)insnToExecute).getFieldInfo(); + FieldPerturbation e = perturbedFields.get(fi); + + if (e != null) { // managed field + if (isMatchingInstructionLocation(e,insnToExecute)) { + if (!ti.isFirstStepInsn()){ + // save the current stackframe so that we can restore it before + // we re-enter + savedFrame = ti.getTopFrame().clone(); + } + } + } + + } else if (insnToExecute instanceof JVMReturnInstruction){ + MethodInfo mi = insnToExecute.getMethodInfo(); + ReturnPerturbation e = perturbedReturns.get(mi); + + if (e != null && isRelevantCallLocation(ti, e)){ + SystemState ss = vm.getSystemState(); + + if (!ti.isFirstStepInsn()){ + // first time, create & set CG but DO NOT enter the insn since it would + // pop the callee stackframe and modify the caller stackframe + // note that we don't need to enter in order to get the perturbation base + // value because its already on the operand stack + ChoiceGenerator cg = e.perturbator.createChoiceGenerator("perturbReturn", ti.getTopFrame(), new Integer(0)); + if (ss.setNextChoiceGenerator(cg)){ + ti.skipInstruction(insnToExecute); + } + } else { + // re-executing, modify the operand stack top and enter + ChoiceGenerator cg = ss.getCurrentChoiceGenerator("perturbReturn", e.cgType); + if (cg != null) { + e.perturbator.perturb(cg, ti.getTopFrame()); + } + } + } + } else if (insnToExecute instanceof JVMInvokeInstruction) { + // first get the method info object corresponding to the invoked method + // We can't use getMethodInfo as the method returned may not be the actual + // method invoked, but rather its caller + MethodInfo mi = ((JVMInvokeInstruction) insnToExecute).getInvokedMethod(); + ParamsPerturbation e = perturbedParams.get(mi); + + if (e != null && isRelevantCallLocation(insnToExecute, e)){ + SystemState ss = vm.getSystemState(); + + if (!ti.isFirstStepInsn()) { + // first time, create and set CG and skip instruction as we want the instruction + // to be executed with the parameter choices we like instead of the ones that + // were passed in + ChoiceGenerator cg = e.perturbator.createChoiceGenerator(mi.getFullName(), ti.getTopFrame(), mi); + // check if the cg returned is null. If it is then we don't want to enter this + // method as we are done exploring it + if (cg != null) { + log.info("--- Creating choice generator: " + mi.getFullName() + " for thread: " + ti); + if (ss.setNextChoiceGenerator(cg)) { + ti.skipInstruction(insnToExecute); + } + } + } else { + // re-executing, modify the operands on stack and enter + ChoiceGenerator cg = ss.getChoiceGenerator(mi.getFullName()); + if (cg != null) { + log.info("--- Using choice generator: " + mi.getFullName() + " in thread: " + ti); + e.perturbator.perturb(cg, ti.getTopFrame()); + } + } + } + } + } + + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + + if (executedInsn instanceof GETFIELD){ + FieldInfo fi = ((JVMInstanceFieldInstruction)executedInsn).getFieldInfo(); + FieldPerturbation p = perturbedFields.get(fi); + if (p != null){ + if (isMatchingInstructionLocation(p, executedInsn)) { // none or managed filePos + StackFrame frame = ti.getTopFrame(); + SystemState ss = vm.getSystemState(); + + if (ti.isFirstStepInsn()) { // retrieve value from CG and replace it on operand stack + ChoiceGenerator cg = ss.getCurrentChoiceGenerator( "perturbGetField", p.cgType); + if (cg != null) { + p.perturbator.perturb(cg, frame); + } else { + log.warning("wrong choice generator type ", cg); + } + + } else { // first time around, create&set the CG and reexecute + ChoiceGenerator cg = p.perturbator.createChoiceGenerator( "perturbGetField", frame, new Integer(0)); + if (ss.setNextChoiceGenerator(cg)){ + assert savedFrame != null; + // we could more efficiently restore the stackframe + // to pre-exec state from last 'this' or classobject ref, but then + // we have to deal with different field value sizes + ti.setTopFrame(savedFrame); + ti.setNextPC(executedInsn); // reexecute + + savedFrame = null; + } + } + } + } + } + } + + protected boolean isMatchingInstructionLocation (Perturbation p, Instruction insn){ + return p.sref == null || p.sref.equals(insn.getFilePos()); + } +} diff --git a/src/main/gov/nasa/jpf/listener/PreciseRaceDetector.java b/src/main/gov/nasa/jpf/listener/PreciseRaceDetector.java new file mode 100644 index 0000000..084dea5 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/PreciseRaceDetector.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.PropertyListenerAdapter; +import gov.nasa.jpf.vm.bytecode.ArrayElementInstruction; +import gov.nasa.jpf.vm.bytecode.FieldInstruction; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.StringSetMatcher; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.bytecode.ReadOrWriteInstruction; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.choice.ThreadChoiceFromSet; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * This is a Race Detection Algorithm that is precise in its calculation of races, i.e. no false warnings. + * It exploits the fact that every thread choice selection point could be due to a possible race. It just runs + * through all the thread choices and checks whether there are more than one thread trying to read & write to the + * same field of an object. + * + * Current limitation is that it is only sound, i.e. will not miss a race, if the sync-detection is switched off + * during model checking. This is due to the fact that the sync-detection guesses that an acess is lock-protected + * when it in reality might not be. + * + * The listener also checks races for array elements, but in order to do so you have to set + * "cg.threads.break_arrays=true" (note that it is false by default because this can cause serious state + * explosion) + * + * This algorithm came out of a discussion with Franck van Breugel and Sergey Kulikov from the University of York. + * All credits for it goes to Franck and Sergey, all the bugs are mine. + * + * NOTE - the PreciseRaceDetector is machine type agnostic + * + * Author: Willem Visser + * + */ + +public class PreciseRaceDetector extends PropertyListenerAdapter { + + static class Race { + Race prev; // linked list + + ThreadInfo ti1, ti2; + ReadOrWriteInstruction insn1, insn2; + ElementInfo ei; + boolean isRead1, isRead2; + + boolean isRace() { + return insn2 != null && ti1 != null && ti2 != null && ( ! ti1.equals(ti2) ); + } + + void printOn(PrintWriter pw){ + pw.print(" "); + pw.print( ti1.getName()); + pw.print(" at "); + pw.println(insn1.getSourceLocation()); + String line = insn1.getSourceLine(); + if (line != null){ + pw.print("\t\t\"" + line.trim()); + } + pw.print("\" "); + pw.print( insn1.isRead() ? "READ: " : "WRITE: "); + pw.println(insn1); + + if (insn2 != null){ + pw.print(" "); + pw.print(ti2.getName()); + pw.print(" at "); + pw.println(insn2.getSourceLocation()); + line = insn2.getSourceLine(); + if (line != null){ + pw.print("\t\t\"" + line.trim()); + } + pw.print("\" "); + pw.print( insn2.isRead() ? "READ: " : "WRITE: "); + pw.println(insn2); + } + } + } + + static class FieldRace extends Race { + FieldInfo fi; + + static Race check (Race prev, ThreadInfo ti, ReadOrWriteInstruction insn, ElementInfo ei, FieldInfo fi){ + for (Race r = prev; r != null; r = r.prev){ + if (r instanceof FieldRace){ + FieldRace fr = (FieldRace)r; + if (fr.ei == ei && fr.fi == fi){ + + if (!((FieldInstruction)fr.insn1).isRead() || !((FieldInstruction)insn).isRead()){ + fr.ti2 = ti; + fr.insn2 = insn; + return fr; + } + } + } + } + + FieldRace fr = new FieldRace(); + fr.ei = ei; + fr.ti1 = ti; + fr.insn1 = insn; + fr.fi = fi; + fr.prev = prev; + return fr; + } + + @Override + void printOn(PrintWriter pw){ + pw.print("race for field "); + pw.print(ei); + pw.print('.'); + pw.println(fi.getName()); + + super.printOn(pw); + } + } + + static class ArrayElementRace extends Race { + int idx; + + static Race check (Race prev, ThreadInfo ti, ReadOrWriteInstruction insn, ElementInfo ei, int idx){ + for (Race r = prev; r != null; r = r.prev){ + if (r instanceof ArrayElementRace){ + ArrayElementRace ar = (ArrayElementRace)r; + if (ar.ei == ei && ar.idx == idx){ + if (!((ArrayElementInstruction)ar.insn1).isRead() || !((ArrayElementInstruction)insn).isRead()){ + ar.ti2 = ti; + ar.insn2 = insn; + return ar; + } + } + } + } + + ArrayElementRace ar = new ArrayElementRace(); + ar.ei = ei; + ar.ti1 = ti; + ar.insn1 = insn; + ar.idx = idx; + ar.prev = prev; + return ar; + } + + @Override + void printOn(PrintWriter pw){ + pw.print("race for array element "); + pw.print(ei); + pw.print('['); + pw.print(idx); + pw.println(']'); + + super.printOn(pw); + } + } + + // this is where we store if we detect one + protected Race race; + + + // our matchers to determine which code we have to check + protected StringSetMatcher includes = null; // means all + protected StringSetMatcher excludes = null; // means none + + + public PreciseRaceDetector (Config conf) { + includes = StringSetMatcher.getNonEmpty(conf.getStringArray("race.include")); + excludes = StringSetMatcher.getNonEmpty(conf.getStringArray("race.exclude")); + } + + @Override + public boolean check(Search search, VM vm) { + return (race == null); + } + + @Override + public void reset() { + race = null; + } + + + @Override + public String getErrorMessage () { + if (race != null){ + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + race.printOn(pw); + pw.flush(); + return sw.toString(); + + } else { + return null; + } + } + + protected boolean checkRace (ThreadInfo[] threads){ + Race candidate = null; + + for (int i = 0; i < threads.length; i++) { + ThreadInfo ti = threads[i]; + Instruction insn = ti.getPC(); + MethodInfo mi = insn.getMethodInfo(); + + if (StringSetMatcher.isMatch(mi.getBaseName(), includes, excludes)) { + if (insn instanceof FieldInstruction) { + FieldInstruction finsn = (FieldInstruction) insn; + FieldInfo fi = finsn.getFieldInfo(); + ElementInfo ei = finsn.peekElementInfo(ti); + + candidate = FieldRace.check(candidate, ti, finsn, ei, fi); + + } else if (insn instanceof ArrayElementInstruction) { + ArrayElementInstruction ainsn = (ArrayElementInstruction) insn; + ElementInfo ei = ainsn.peekArrayElementInfo(ti); + + // these insns have been through their top half since they created CGs, but they haven't + // removed the operands from the stack + int idx = ainsn.peekIndex(ti); + + candidate = ArrayElementRace.check(candidate, ti, ainsn, ei, idx); + } + } + + if (candidate != null && candidate.isRace()){ + race = candidate; + return true; + } + } + + return false; + } + + + //----------- our VMListener interface + + // All we rely on here is that the scheduler breaks transitions at all + // insns that could be races. We then just have to look at all currently + // executed insns and don't rely on any past-exec info, PROVIDED that we only + // use execution parameters (index or reference values) that are retrieved + // from the operand stack, and not cached in the insn from a previous exec + // (all the insns we look at are pre-exec, i.e. don't have their caches + // updated yet) + @Override + public void choiceGeneratorSet(VM vm, ChoiceGenerator newCG) { + + if (newCG instanceof ThreadChoiceFromSet) { + ThreadInfo[] threads = ((ThreadChoiceFromSet)newCG).getAllThreadChoices(); + checkRace(threads); + } + } + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insnToExecute) { + if (race != null) { + // we're done, report as quickly as possible + //ti.skipInstruction(); + ti.breakTransition("dataRace"); + } + } + +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/listener/ReferenceLocator.java b/src/main/gov/nasa/jpf/listener/ReferenceLocator.java new file mode 100644 index 0000000..d32f8bc --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/ReferenceLocator.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMInstanceFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.InstanceInvocation; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.PrintWriter; +import java.util.Arrays; + +/** + * tiny utility listener that can be used to find out where a certain + * object (specified by reference) gets allocated or accessed (call or field), + * and when it gets gc'ed + */ +public class ReferenceLocator extends ListenerAdapter { + + PrintWriter pw; + int[] createRefs; + int[] releaseRefs; + int[] useRefs; + + public ReferenceLocator (Config conf){ + createRefs = sort( conf.getIntArray("refloc.create")); + releaseRefs = sort( conf.getIntArray("refloc.release")); + useRefs = sort( conf.getIntArray("refloc.use")); + + // <2do> we might want to configure output destination + pw = new PrintWriter(System.out, true); + } + + protected int[] sort(int[] a){ + if (a != null){ + Arrays.sort(a); + } + return a; + } + + protected void printLocation(String msg, ThreadInfo ti){ + pw.println(msg); + for (StackFrame frame : ti) { + pw.print("\tat "); + pw.println(frame.getStackTraceInfo()); + } + + pw.println(); + } + + @Override + public void objectCreated (VM vm, ThreadInfo ti, ElementInfo ei){ + int ref = ei.getObjectRef(); + + if (createRefs != null && Arrays.binarySearch(createRefs, ref) >= 0){ + printLocation("[ReferenceLocator] object " + ei + " created at:", ti); + } + } + + @Override + public void objectReleased (VM vm, ThreadInfo ti, ElementInfo ei){ + int ref = ei.getObjectRef(); + + if (releaseRefs != null && Arrays.binarySearch(releaseRefs, ref) >= 0){ + pw.println("[ReferenceLocator] object " + ei + " released"); + } + } + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){ + + if (useRefs != null){ + if (executedInsn instanceof InstanceInvocation) { + int ref = ((InstanceInvocation)executedInsn).getCalleeThis(ti); + if (Arrays.binarySearch(useRefs, ref) >= 0){ + printLocation("[ReferenceLocator] call on object " + ti.getElementInfo(ref) + " at:", ti); + } + } else if (executedInsn instanceof JVMInstanceFieldInstruction){ + int ref = ((JVMInstanceFieldInstruction)executedInsn).getLastThis(); + if (Arrays.binarySearch(useRefs, ref) >= 0){ + printLocation("[ReferenceLocator] field access of " + ti.getElementInfo(ref) + " at:", ti); + } + } + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/SearchStats.java b/src/main/gov/nasa/jpf/listener/SearchStats.java new file mode 100644 index 0000000..2a97b4b --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/SearchStats.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.search.heuristic.HeuristicSearch; + +import java.io.PrintStream; + +/** + * An alternative to SearchMonitor that just reports statistics at the end. + */ +public class SearchStats extends ListenerAdapter { + PrintStream out = System.out; + + long time; + long startTime; + long startFreeMemory; + + int searchLevel=0; + int maxSearchLevel=0; + + int newStates; + int endStates; + int backtracks; + int revisitedStates; + int processedStates; + int restoredStates; + + int steps; + + long maxMemory; + long totalMemory; + long freeMemory; + + boolean isHeuristic = false; + int queueSize = 0; + + int currentHeapCount = 0; + int maxHeapCount = 0; + + /* + * SearchListener interface + */ + @Override + public void stateAdvanced(Search search) { + steps += search.getTransition().getStepCount(); + + if (isHeuristic) + queueSize = ((HeuristicSearch)(search)).getQueueSize(); + + if (search.isNewState()) { + searchLevel = search.getDepth(); + if (searchLevel > maxSearchLevel) + maxSearchLevel = searchLevel; + + newStates++; + + currentHeapCount = search.getVM().getHeap().size(); + + if (currentHeapCount > maxHeapCount) + maxHeapCount = currentHeapCount; + + if (search.isEndState()) { + endStates++; + } + } else { + revisitedStates++; + } + } + + @Override + public void stateProcessed(Search search) { + processedStates++; + } + + @Override + public void stateBacktracked(Search search) { + searchLevel = search.getDepth(); + backtracks++; + } + + @Override + public void stateRestored(Search search) { + searchLevel = search.getDepth(); + restoredStates++; + } + + @Override + public void propertyViolated(Search search) { + } + + @Override + public void searchStarted(Search search) { + if (search instanceof HeuristicSearch) { + isHeuristic = true; + } + + startTime = System.currentTimeMillis(); + + Runtime rt = Runtime.getRuntime(); + startFreeMemory = rt.freeMemory(); + totalMemory = rt.totalMemory(); + maxMemory = rt.maxMemory(); + } + + @Override + public void searchConstraintHit(Search search) { + } + + void reportRuntime () { + long td = time - startTime; + + int h = (int) (td / 3600000); + int m = (int) (td / 60000) % 60; + int s = (int) (td / 1000) % 60; + + out.print(" abs time: "); + if (h < 10) out.print('0'); + out.print( h); + out.print(':'); + if (m < 10) out.print('0'); + out.print( m); + out.print(':'); + if (s < 10) out.print('0'); + out.print( s); + + out.print( " ("); + out.print(td); + out.println(" ms)"); + } + + @Override + public void searchFinished(Search search) { + report("------ Search statistics: ------"); + } + + void report (String header) { + time = System.currentTimeMillis(); + + out.println(header); + + reportRuntime(); + + out.println(); + out.print(" search depth: "); + out.print(searchLevel); + out.print(" (max: "); + out.print(maxSearchLevel); + out.println(")"); + + out.print(" new states: "); + out.println(newStates); + + out.print(" revisited states: "); + out.println(revisitedStates); + + out.print(" end states: "); + out.println(endStates); + + out.print(" backtracks: "); + out.println(backtracks); + + out.print(" processed states: "); + out.print( processedStates); + out.print(" ("); + // a little ad-hoc rounding + double d = (double) backtracks / (double)processedStates; + int n = (int) d; + int m = (int) ((d - /*(double)*/ n) * 10.0); + out.print( n); + out.print('.'); + out.print(m); + out.println( " bt/proc state)"); + + out.print(" restored states: "); + out.println(restoredStates); + + if (isHeuristic) { + out.print(" queue size: "); + out.println(queueSize); + } + + out.println(); + out.print(" total memory [kB]: "); + out.print(totalMemory / 1024); + out.print(" (max: "); + out.print(maxMemory / 1024); + out.println(")"); + + out.print(" free memory [kB]: "); + out.println(freeMemory / 1024); + + out.print(" max heap objects: "); + out.print(maxHeapCount); + + out.println(); + } +} diff --git a/src/main/gov/nasa/jpf/listener/SimpleDot.java b/src/main/gov/nasa/jpf/listener/SimpleDot.java new file mode 100644 index 0000000..9d4c486 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/SimpleDot.java @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.Error; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.JPFConfigException; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.Property; +import gov.nasa.jpf.jvm.bytecode.EXECUTENATIVE; +import gov.nasa.jpf.jvm.bytecode.JVMFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.INVOKESTATIC; +import gov.nasa.jpf.jvm.bytecode.JVMInstanceFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.InstanceInvocation; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.LockInstruction; +import gov.nasa.jpf.jvm.bytecode.PUTFIELD; +import gov.nasa.jpf.jvm.bytecode.PUTSTATIC; +import gov.nasa.jpf.jvm.bytecode.JVMStaticFieldInstruction; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.FileUtils; +import gov.nasa.jpf.util.Misc; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.ExceptionInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.NoUncaughtExceptionsProperty; +import gov.nasa.jpf.vm.NotDeadlockedProperty; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; + +/** + * an alternative Graphviz dot-file generator for simple,educational state graphs + * except of creating funny wallpapers, it doesn't help much in real life if the + * state count gets > 50, but for the small ones it's actually quite readable. + * Good for papers. + * + * normal states are labeled with their numeric ids, end states are double circled. + * start, end and error states are color filled + * + * edges have two labels: the choice value at the beginning and the CG cause + * at the end. Only the first incoming edge into a state shows the CG cause + * + * we only render one backtrack edge per from-state + * + * <2do> GraphViz doesn't seem to handle color or fontname for head/tail labels correctly + */ +public class SimpleDot extends ListenerAdapter { + + static final String GRAPH_ATTRS = "pad=0.5"; + static final String GENERIC_NODE_ATTRS = "shape=circle,style=filled,fillcolor=white"; + static final String GENERIC_EDGE_ATTRS = "fontsize=10,fontname=Helvetica,fontcolor=blue,color=cadetblue,style=\"setlinewidth(0.5)\",arrowhead=empty,arrowsize=0.5"; + static final String START_NODE_ATTRS = "fillcolor=green"; + static final String END_NODE_ATTRS = "shape=doublecircle,fillcolor=cyan"; + static final String ERROR_NODE_ATTRS = "color=red,fillcolor=lightcoral"; + static final String BACKTRACK_EDGE_ATTRS = "arrowhead=onormal,color=gray52,style=\"dotted\""; + static final String RESTORED_EDGE_ATTRS = "arrowhead=onormal,color=red,style=\"dotted\""; + static final String NEW_EDGE_ATTRS = "arrowhead=normal"; + static final String VISITED_EDGE_ATTRS = "arrowhead=vee"; + + + //--- configurable Graphviz attributes + protected String graphAttrs; + protected String genericNodeAttrs; + protected String genericEdgeAttrs; + protected String startNodeAttrs; + protected String endNodeAttrs; + protected String errorNodeAttrs; + protected String newEdgeAttrs; + protected String visitedEdgeAttrs; + protected String backtrackEdgeAttrs; + protected String restoreEdgeAttrs; + + protected boolean showTarget; + protected boolean printFile; + + protected VM vm; + protected String app; + protected File file; + protected PrintWriter pw; + + protected int lastId = -1; // where we come from + protected String lastErrorId; + protected ElementInfo lastEi; + protected ThreadInfo lastTi; // the last started thread + + // helper because GraphViz cannot eliminate duplicate edges + HashSet seenEdges; + + public SimpleDot( Config config, JPF jpf){ + + graphAttrs = config.getString("dot.graph_attr", GRAPH_ATTRS); + genericNodeAttrs = config.getString("dot.node_attr", GENERIC_NODE_ATTRS); + genericEdgeAttrs = config.getString("dot.edge_attr", GENERIC_EDGE_ATTRS); + newEdgeAttrs = config.getString("dot.new_edge_attr", NEW_EDGE_ATTRS); + visitedEdgeAttrs = config.getString("dot.visited_edge_attr", VISITED_EDGE_ATTRS); + startNodeAttrs = config.getString("dot.start_node_attr", START_NODE_ATTRS); + endNodeAttrs = config.getString("dot.end_node_attr", END_NODE_ATTRS); + errorNodeAttrs = config.getString("dot.error_node_attr", ERROR_NODE_ATTRS); + backtrackEdgeAttrs = config.getString("dot.bt_edge_attr", BACKTRACK_EDGE_ATTRS); + restoreEdgeAttrs = config.getString("dot.restore_edge_attr", RESTORED_EDGE_ATTRS); + + printFile = config.getBoolean("dot.print_file", false); + showTarget = config.getBoolean("dot.show_target", false); + + // app and filename are not known until the search is started + + jpf.addPublisherExtension(ConsolePublisher.class, this); + } + + void initialize (VM vm){ + Config config = vm.getConfig(); + + app = vm.getSUTName(); + app = app.replace("+", "__"); + app = app.replace('.', '_'); + + String fname = config.getString("dot.file"); + if (fname == null){ + fname = app + ".dot"; + } + + try { + file = new File(fname); + FileWriter fw = new FileWriter(file); + pw = new PrintWriter(fw); + } catch (IOException iox){ + throw new JPFConfigException("unable to open SimpleDot output file: " + fname); + } + + seenEdges = new HashSet(); + } + + //--- the listener interface + + @Override + public void searchStarted(Search search){ + vm = search.getVM(); + + initialize(vm); + + printHeader(); + printStartState("S"); + } + + @Override + public void stateAdvanced(Search search){ + int id = search.getStateId(); + long edgeId = ((long)lastId << 32) | id; + + if (id <0 || seenEdges.contains(edgeId)){ + return; // skip the root state and property violations (reported separately) + } + + + if (search.isErrorState()) { + String eid = "e" + search.getNumberOfErrors(); + printTransition(getStateId(lastId), eid, getLastChoice(), getError(search)); + printErrorState(eid); + lastErrorId = eid; + + } else if (search.isNewState()) { + + if (search.isEndState()) { + printTransition(getStateId(lastId), getStateId(id), getLastChoice(), "return"); + printEndState(getStateId(id)); + } else { + printTransition(getStateId(lastId), getStateId(id), getLastChoice(), getNextCG()); + } + + } else { // already visited state + printTransition(getStateId(lastId), getStateId(id), getLastChoice(), null); + } + + seenEdges.add(edgeId); + lastId = id; + } + + @Override + public void stateBacktracked(Search search){ + int id = search.getStateId(); + long edgeId = ((long)lastId << 32) | id; + + if (!seenEdges.contains(edgeId)) { + if(lastErrorId!=null) { + printBacktrack(lastErrorId, getStateId(id)); + lastErrorId = null; + } else { + printBacktrack(getStateId(lastId), getStateId(id)); + } + seenEdges.add(edgeId); + } + lastId = id; + } + + @Override + public void stateRestored(Search search) { + int id = search.getStateId(); + long edgeId = ((long)lastId << 32) | id; + + if (!seenEdges.contains(edgeId)) { + printRestored(getStateId(lastId), getStateId(id)); + seenEdges.add(edgeId); + } + lastId = id; + } + + @Override + public void searchFinished (Search search){ + pw.println("}"); + pw.close(); + } + + @Override + public void threadStarted (VM vm, ThreadInfo ti){ + lastTi = ti; + } + + @Override + public void objectWait (VM vm, ThreadInfo ti, ElementInfo ei){ + lastEi = ei; + lastTi = ti; + } + + @Override + public void publishFinished (Publisher publisher) { + PrintWriter ppw = publisher.getOut(); + publisher.publishTopicStart("SimpleDot"); + + ppw.println("dot file generated: " + file.getPath()); + + if (printFile){ + ppw.println(); + FileUtils.printFile(ppw,file); + } + } + + + //--- data collection + + protected String getStateId (int id){ + return id < 0 ? "S" : Integer.toString(id); + } + + protected String getLastChoice() { + ChoiceGenerator cg = vm.getChoiceGenerator(); + Object choice = cg.getNextChoice(); + + if (choice instanceof ThreadInfo){ + int idx = ((ThreadInfo)choice).getId(); + return "T"+idx; + } else { + return choice.toString(); // we probably want more here + } + } + + // this is the only method that's more tricky - we have to find a balance + // between being conscious enough to not clutter the graph, and expressive + // enough to understand it. + // <2do> this doesn't deal well with custom or data CGs yet + protected String getNextCG(){ + ChoiceGenerator cg = vm.getNextChoiceGenerator(); // that's the next one + Instruction insn = cg.getInsn(); + + if (insn instanceof EXECUTENATIVE) { + return getNativeExecCG((EXECUTENATIVE)insn); + + } else if (insn instanceof JVMFieldInstruction) { // shared object field access + return getFieldAccessCG((JVMFieldInstruction)insn); + + } else if (insn instanceof LockInstruction){ // monitor_enter + return getLockCG((LockInstruction)insn); + + } else if (insn instanceof JVMInvokeInstruction){ // sync method invoke + return getInvokeCG((JVMInvokeInstruction)insn); + } + + return insn.getMnemonic(); // our generic fallback + } + + protected String getNativeExecCG (EXECUTENATIVE insn){ + MethodInfo mi = insn.getExecutedMethod(); + String s = mi.getName(); + + if (s.equals("start")) { + s = "T" + lastTi.getId() + ".start"; + } else if (s.equals("wait")) { + s = "T" + lastTi.getId() + ".wait"; + } + + return s; + } + + protected String getFieldAccessCG (JVMFieldInstruction insn){ + String s; + + if (insn instanceof JVMInstanceFieldInstruction) { + + if (insn instanceof PUTFIELD) { + s = "put"; + } else /* if (insn instanceof GETFIELD) */ { + s = "get"; + } + + if (showTarget){ + int ref = ((JVMInstanceFieldInstruction) insn).getLastThis(); + s = getInstanceRef(ref) + '.' + s; + } + + } else /* if (insn instanceof StaticFieldInstruction) */ { + if (insn instanceof PUTSTATIC) { + s = "put"; + } else /* if (insn instanceof GETSTATIC) */ { + s = "get"; + } + + if (showTarget){ + String clsName = ((JVMStaticFieldInstruction) insn).getLastClassName(); + s = Misc.stripToLastDot(clsName) + '.' + s; + } + } + + String varId = insn.getFieldName(); + s = s + ' ' + varId; + + return s; + } + + protected String getLockCG(LockInstruction insn){ + String s = "sync"; + + if (showTarget){ + int ref = insn.getLastLockRef(); + s = getInstanceRef(ref) + '.' + s; + } + + return s; + } + + protected String getInvokeCG (JVMInvokeInstruction insn){ + MethodInfo mi = insn.getInvokedMethod(); + String s = mi.getName() + "()"; + + if (showTarget){ + if (insn instanceof InstanceInvocation) { + int ref = ((InstanceInvocation) insn).getLastObjRef(); + s = getInstanceRef(ref) + '.' + s; + + } else if (insn instanceof INVOKESTATIC) { + String clsName = ((INVOKESTATIC) insn).getInvokedClassName(); + s = Misc.stripToLastDot(clsName) + '.' + s; + } + } + + return s; + } + + protected String getError (Search search){ + String e; + Error error = search.getLastError(); + Property prop = error.getProperty(); + + if (prop instanceof NoUncaughtExceptionsProperty){ + ExceptionInfo xi = ((NoUncaughtExceptionsProperty)prop).getUncaughtExceptionInfo(); + return Misc.stripToLastDot(xi.getExceptionClassname()); + + } else if (prop instanceof NotDeadlockedProperty){ + return "deadlock"; + } + + // fallback + return Misc.stripToLastDot(prop.getClass().getName()); + } + + protected static String getInstanceRef (int ref){ + return "@" + Integer.toHexString(ref).toUpperCase(); + } + + protected static String getClassObjectRef (int ref){ + return "#" + Integer.toHexString(ref).toUpperCase(); + } + + //--- dot file stuff + + protected void printHeader(){ + pw.print("digraph "); + pw.print(app); + pw.println(" {"); + + pw.print("node ["); + pw.print(genericNodeAttrs); + pw.println(']'); + + pw.print("edge ["); + pw.print(genericEdgeAttrs); + pw.println(']'); + + pw.println(graphAttrs); + + pw.println(); + pw.print("label=\""); + pw.print(app); + pw.print("\""); + pw.println(); + } + + protected void printTransition(String fromState, String toState, String choiceVal, String cgCause){ + pw.println(); + pw.print(fromState); + pw.print(" -> "); + pw.print( toState); + pw.print(" [label=\""); + pw.print(choiceVal); + pw.print('"'); + if (cgCause != null){ + pw.print(NEW_EDGE_ATTRS); + pw.print(",headlabel=\""); + pw.print(cgCause); + pw.print('"'); + } else { + pw.print(VISITED_EDGE_ATTRS); + } + pw.println(']'); + } + + protected void printBacktrack (String fromState, String toState){ + pw.println(); + pw.print(fromState); + pw.print(" -> "); + pw.print( toState); + + pw.print(" ["); + pw.print(backtrackEdgeAttrs); + pw.print(']'); + + pw.println(" // backtrack"); + } + + protected void printRestored (String fromState, String toState){ + pw.println(); + pw.print(fromState); + pw.print(" -> "); + pw.print( toState); + + pw.print(" ["); + pw.print(restoreEdgeAttrs); + pw.print(']'); + + pw.println(" // restored"); + } + + protected void printStartState(String stateId){ + pw.print(stateId); + + pw.print(" ["); + pw.print(startNodeAttrs); + pw.print(']'); + + pw.println(" // start state"); + } + + protected void printEndState(String stateId){ + pw.print(stateId); + + pw.print(" ["); + pw.print(endNodeAttrs); + pw.print(']'); + + pw.println(" // end state"); + } + + protected void printErrorState(String error){ + pw.print(error); + + pw.print(" ["); + pw.print(errorNodeAttrs); + pw.print(']'); + + pw.println(" // error state"); + } +} diff --git a/src/main/gov/nasa/jpf/listener/SimpleIdleFilter.java b/src/main/gov/nasa/jpf/listener/SimpleIdleFilter.java new file mode 100644 index 0000000..3d448fd --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/SimpleIdleFilter.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.ObjVector; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.util.logging.Logger; + + +/** + * This is the simple version of IdleFilter. This one simply breaks all back-edges + * encountered to make sure JPF's partial-order reduction doesn't add meaningless + * transitions forever. This is our dual of the cycle-proviso in classic po-reduction theory. + * + * One can set how many back-edges to consider before breaking, but by default it is 1 + * + */ +public class SimpleIdleFilter extends ListenerAdapter { + + static Logger log = JPF.getLogger("gov.nasa.jpf.listener.SimpleIdleFilter"); + + static class ThreadStat { + String tname; + + int backJumps; + + int loopStartPc; + + int loopEndPc; + + int loopStackDepth; + + ThreadStat(String tname) { + this.tname = tname; + } + } + + ObjVector threadStats = new ObjVector(); + + ThreadStat ts; + + int maxBackJumps; + + // ----------------------------------------------------- SearchListener + // interface + + public SimpleIdleFilter(Config config) { + maxBackJumps = config.getInt("idle.max_backjumps", 1); + } + + @Override + public void stateAdvanced(Search search) { + ts.backJumps = 0; + ts.loopStackDepth = 0; + ts.loopStartPc = ts.loopEndPc = 0; + } + + @Override + public void stateBacktracked(Search search) { + ts.backJumps = 0; + ts.loopStackDepth = 0; + ts.loopStartPc = ts.loopEndPc = 0; + } + + // ----------------------------------------------------- VMListener interface + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + + if (!executedInsn.isBackJump()) { // Put this test first for a performance optimization. + return; + } + + int tid = ti.getId(); + ts = threadStats.get(tid); + if (ts == null) { + ts = new ThreadStat(ti.getName()); + threadStats.set(tid, ts); + } + + ts.backJumps++; + + int loopStackDepth = ti.getStackDepth(); + int loopPc = nextInsn.getPosition(); + + if ((loopStackDepth != ts.loopStackDepth) || (loopPc != ts.loopStartPc)) { + // new loop, reset + ts.loopStackDepth = loopStackDepth; + ts.loopStartPc = loopPc; + ts.loopEndPc = executedInsn.getPosition(); + ts.backJumps = 0; + } else { + if (ts.backJumps > maxBackJumps) { + ti.reschedule("idleFilter"); // this breaks the executePorStep loop + } + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/StackDepthChecker.java b/src/main/gov/nasa/jpf/listener/StackDepthChecker.java new file mode 100644 index 0000000..6c07905 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/StackDepthChecker.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; + +/** + * listener that throws a java.lang.StackOverflowError in case a thread + * exceeds a configured max stack depth + * + * <2do> - maybe we should only count visible stackframes, i.e. the ones for + * which we have invoke insns on the stack + */ +public class StackDepthChecker extends ListenerAdapter { + + static JPFLogger log = JPF.getLogger("gov.nasa.jpf.listener.StackDepthChecker"); + + protected int maxDepth; + + public StackDepthChecker (Config config, JPF jpf){ + maxDepth = config.getInt( "sdc.max_stack_depth", 42); + } + + @Override + public void methodEntered (VM vm, ThreadInfo thread, MethodInfo mi){ + + ThreadInfo ti = ThreadInfo.getCurrentThread(); + int depth = ti.getStackDepth(); // note this is only an approximation since it also returns natives and overlays + + if (depth > maxDepth){ + log.info("configured vm.max_stack_depth exceeded: ", depth); + + // NOTE - we get this notification from inside of the InvokeInstruction.enter(), + // i.e. before we get the instructionExecuted(). Throwing exceptions is + // therefore a bit harder since we have to set the next pc explicitly + + Instruction nextPc = ti.createAndThrowException("java.lang.StackOverflowError"); + StackFrame topFrame = ti.getModifiableTopFrame(); + topFrame.setPC(nextPc); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/StackTracker.java b/src/main/gov/nasa/jpf/listener/StackTracker.java new file mode 100644 index 0000000..1217440 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/StackTracker.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.INVOKESPECIAL; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.VirtualInvocation; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadInfo; + +import java.io.PrintWriter; + +/** + * simple tool to log stack invocations + * + * at this point, it doesn't do fancy things yet, but gives a more high + * level idea of what got executed by JPF than the ExecTracker + */ +public class StackTracker extends ListenerAdapter { + + static final String INDENT = " "; + + MethodInfo lastMi; + PrintWriter out; + long nextLog; + int logPeriod; + + public StackTracker (Config conf, JPF jpf) { + out = new PrintWriter(System.out, true); + logPeriod = conf.getInt("jpf.stack_tracker.log_period", 5000); + } + + void logStack(ThreadInfo ti) { + long time = System.currentTimeMillis(); + + if (time < nextLog) { + return; + } + + nextLog = time + logPeriod; + + out.println(); + out.print("Thread: "); + out.print(ti.getId()); + out.println(":"); + + out.println(ti.getStackTrace()); + out.println(); + } + + @Override + public void executeInstruction (VM vm, ThreadInfo ti, Instruction insnToExecute) { + MethodInfo mi = insnToExecute.getMethodInfo(); + + if (mi != lastMi) { + logStack(ti); + lastMi = mi; + + } else if (insnToExecute instanceof JVMInvokeInstruction) { + MethodInfo callee; + + // that's the only little gist of it - if this is a VirtualInvocation, + // we have to dig the callee out by ourselves (it's not known + // before execution) + + if (insnToExecute instanceof VirtualInvocation) { + VirtualInvocation callInsn = (VirtualInvocation)insnToExecute; + int objref = callInsn.getCalleeThis(ti); + callee = callInsn.getInvokedMethod(ti, objref); + + } else if (insnToExecute instanceof INVOKESPECIAL) { + INVOKESPECIAL callInsn = (INVOKESPECIAL)insnToExecute; + callee = callInsn.getInvokedMethod(ti); + + } else { + JVMInvokeInstruction callInsn = (JVMInvokeInstruction)insnToExecute; + callee = callInsn.getInvokedMethod(ti); + } + + if (callee != null) { + if (callee.isMJI()) { + logStack(ti); + } + } else { + out.println("ERROR: unknown callee of: " + insnToExecute); + } + } + } + + @Override + public void stateAdvanced(Search search) { + lastMi = null; + } + + @Override + public void stateBacktracked(Search search) { + lastMi = null; + } +} diff --git a/src/main/gov/nasa/jpf/listener/StateCountEstimator.java b/src/main/gov/nasa/jpf/listener/StateCountEstimator.java new file mode 100644 index 0000000..f50da27 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/StateCountEstimator.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Path; +import gov.nasa.jpf.vm.Transition; + +import java.io.PrintWriter; +import java.util.Formatter; + +/** + * From already visited states, estimates the total number of states by the branching factor. + */ + +public class StateCountEstimator extends ListenerAdapter +{ + private final PrintWriter m_out; + private final StringBuilder m_buffer = new StringBuilder(); + private final Formatter m_formatter = new Formatter(m_buffer); + private final int m_logPeriod; + private double m_lastPercent; + private long m_nextLog; + private long m_startTime; + + public StateCountEstimator(Config config) + { + m_out = new PrintWriter(System.out, true); + m_logPeriod = config.getInt("jpf.state_count_estimator.log_period", 0); + } + + @Override + public void searchStarted(Search search) + { + m_nextLog = 0; + m_lastPercent = 0.0; + m_startTime = System.currentTimeMillis(); + } + + @Override + public void searchFinished(Search search) + { + log(search); + } + + @Override + public void stateProcessed(Search search) + { + if (m_nextLog > System.currentTimeMillis()) + return; + + if (log(search)) + m_nextLog = m_logPeriod + System.currentTimeMillis(); + } + + private boolean log(Search search) + { + VM vm; + Path path; + Transition trans; + ChoiceGenerator cg; + double percent, delta; + long currentState, expectedState, currentTime, expectedTime; + int i, size, processed; + + vm = search.getVM(); + path = vm.getPath(); + size = path.size(); + percent = 0.0; + delta = 1.0; + processed = 0; + + for (i = 0; i < size; i++) + { + trans = path.get(i); + cg = trans.getChoiceGenerator(); + delta /= cg.getTotalNumberOfChoices(); + processed = cg.getProcessedNumberOfChoices() - 1; + percent += delta * processed; + } + + if (size == 0) + percent = 1.0; + + if (m_lastPercent > percent) // Sometimes a state is declared as processed but doesn't show up in the path so the percentage appears to go backwards. + return(false); + + m_lastPercent = percent; + + currentState = vm.getStateCount(); + expectedState = (long) (currentState / percent); + + currentTime = System.currentTimeMillis() - m_startTime; + expectedTime = (long) (currentTime / percent); + + m_formatter.format("State: %,d / %,d (%g%%) Time: ", currentState, expectedState, 100.0 * percent); + + formatTime(expectedTime); + m_buffer.append(" - "); + formatTime(currentTime); + m_buffer.append(" = "); + formatTime(expectedTime - currentTime); + + m_out.println(m_buffer.toString()); + m_buffer.setLength(0); + + return(true); + } + + private void formatTime(long time) + { + long days, hours, minutes, seconds; + boolean commit; + + seconds = time / 1000; + minutes = seconds / 60; + hours = minutes / 60; + days = hours / 24; + + seconds %= 60; + minutes %= 60; + hours %= 24; + + commit = false; + + if ((commit) || (days != 0)) + { + commit = true; + m_buffer.append(days); + m_buffer.append(' '); + } + + if ((commit) || (hours != 0)) + { + if ((commit) && (hours < 10)) + m_buffer.append('0'); + + m_buffer.append(hours); + m_buffer.append(':'); + commit = true; + } + + if ((commit) || (minutes != 0)) + { + if ((commit) && (minutes < 10)) + m_buffer.append('0'); + + m_buffer.append(minutes); + m_buffer.append(':'); + commit = true; + } + + if ((commit) && (seconds < 10)) + m_buffer.append('0'); + + m_buffer.append(seconds); + } +} diff --git a/src/main/gov/nasa/jpf/listener/StateSpaceAnalyzer.java b/src/main/gov/nasa/jpf/listener/StateSpaceAnalyzer.java new file mode 100644 index 0000000..9b34d22 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/StateSpaceAnalyzer.java @@ -0,0 +1,802 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.MONITORENTER; +import gov.nasa.jpf.jvm.bytecode.MONITOREXIT; +import gov.nasa.jpf.jvm.bytecode.JVMReturnInstruction; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.report.PublisherExtension; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.BooleanChoiceGenerator; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.DoubleChoiceGenerator; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.IntChoiceGenerator; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadChoiceGenerator; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * a listener that collects information about ChoiceGenerators, choices and + * where they are used. The purpose is to find out what causes the state space + * size, and to give hints of how to reduce it. + * The interesting part is that this is a listener that doesn't work off traces, + * but needs to collect info up to a point where we want it to report. That's + * state space or resource related, i.e. a combination of + * + * - number of transitions + * - memory consumption + * - elapsed time + * + * once the limit is reached, we stop the search and report. + * + * There are two parts we are interested in: + * + * - what CGs do we have + * - what creates those CGs (thread,insn,source) = last step insn + */ +public class StateSpaceAnalyzer extends ListenerAdapter implements PublisherExtension { + // Search termination conditions + + private final long m_maxTime; + private final long m_maxMemory; + private final int m_maxStates; + private final int m_maxChoices; + private final ArrayList m_groupers = new ArrayList(); + private final int m_maxOutputLines; // how many detail lines do we display in the report + private long m_terminateTime; + private int m_choiceCount; + + public StateSpaceAnalyzer(Config config, JPF jpf) { + m_maxStates = config.getInt("ssa.max_states", -1); + m_maxTime = config.getDuration("ssa.max_time", -1); + m_maxMemory = config.getMemorySize("ssa.max_memory", -1); + m_maxChoices = config.getInt("ssa.max_choices", -1); + m_maxOutputLines = config.getInt("ssa.max_output_lines", 10); + + initGroupers(config); + + jpf.addPublisherExtension(ConsolePublisher.class, this); + } + + private void initGroupers(Config config) { + HashMap accessors; + CGGrouper grouper; + int i; + + if (config.getStringArray("ssa.sort_order") == null) { + config.setProperty("ssa.sort_order", "type"); + config.setProperty("ssa.sort_order2", "package,class,method,instruction,type"); + } + + accessors = new HashMap(5); + accessors.put("package", new CGPackageAccessor()); + accessors.put("class", new CGClassAccessor()); + accessors.put("method", new CGMethodAccessor()); + accessors.put("instruction", new CGInstructionAccessor()); + accessors.put("type", new CGTypeAccessor()); + + m_groupers.add(initGrouper(config, "ssa.sort_order", accessors)); + + for (i = 2; true; i++) { + grouper = initGrouper(config, "ssa.sort_order" + i, accessors); + if (grouper == null) { + break; + } + + m_groupers.add(grouper); + } + } + + private CGGrouper initGrouper(Config config, String parameter, Map accessors) { + CGGrouper grouper; + CGAccessor list[]; + StringBuilder name; + String key, sortOrder[]; + int i; + + sortOrder = config.getStringArray(parameter); + if ((sortOrder == null) || (sortOrder.length <= 0)) { + return (null); + } + + name = new StringBuilder(); + list = new CGAccessor[sortOrder.length]; + + for (i = 0; i < sortOrder.length; i++) { + key = sortOrder[i].toLowerCase(); + name.append(key); + name.append(", "); + + list[i] = accessors.get(key); + + if (list[i] == null) { + config.exception("Unknown sort key: " + sortOrder[i] + ". Found in parameter: " + parameter); + } + } + + name.setLength(name.length() - 2); + grouper = new CGGrouper(list, name.toString()); + + return (grouper); + } + + @Override + public void choiceGeneratorSet(VM vm, ChoiceGenerator newCG) { + int i; + + // NOTE: we get this from SystemState.nextSuccessor, i.e. when the CG + // is actually used (which doesn't necessarily mean it produces a new state, + // but it got created from a new state) + + // The original code stored each choice generator in an ArrayList. For long + // running tests, this would grow and cause an OutOfMemoryError. Now, the + // generators are dealt with as they are created. This means a bit more + // processing up front but huge memory savings in the long run. If the + // machine has multiple processors, a better solution would be to have a + // background thread process the generators. + + m_choiceCount += newCG.getTotalNumberOfChoices(); + + for (i = m_groupers.size(); --i >= 0; ) + m_groupers.get(i).add(newCG); + } + + @Override + public void searchStarted(Search search) { + int i; + + for (i = m_groupers.size(); --i >= 0; ) + m_groupers.get(i).clear(); + + m_choiceCount = 0; + m_terminateTime = m_maxTime + System.currentTimeMillis(); + } + + @Override + public void stateAdvanced(Search search) { + if (shouldTerminate(search)) { + search.terminate(); + } + } + + private boolean shouldTerminate(Search search) { + if ((m_maxStates >= 0) && (search.getVM().getStateCount() >= m_maxStates)) { + return (true); + } + + if ((m_maxTime >= 0) && (System.currentTimeMillis() >= m_terminateTime)) { + return (true); + } + + if ((m_maxMemory >= 0) && (Runtime.getRuntime().totalMemory() >= m_maxMemory)) { + return (true); + } + + if ((m_maxChoices >= 0) && (m_choiceCount >= m_maxChoices)) { + return (true); + } + + return (false); + } + + @Override + public void publishFinished(Publisher publisher) { + CGGrouper groupers[]; + + groupers = new CGGrouper[m_groupers.size()]; + m_groupers.toArray(groupers); + + if (publisher instanceof ConsolePublisher) { + new PublishConsole((ConsolePublisher) publisher, groupers, m_maxOutputLines).publish(); + } + } + + private enum CGType { + + FieldAccess, + ObjectWait, + ObjectNotify, + SyncEnter, + SyncExit, + ThreadStart, + ThreadTerminate, + ThreadSuspend, + ThreadResume, + SyncCall, + SyncReturn, + AtomicOp, + DataChoice + } + + private interface CGAccessor { + + public Object getValue(ChoiceGenerator generator); + } + + private static class CGPackageAccessor implements CGAccessor { + + @Override + public Object getValue(ChoiceGenerator generator) { + ClassInfo ci; + MethodInfo mi; + Instruction instruction; + + instruction = generator.getInsn(); + if (instruction == null) { + return (null); + } + + mi = instruction.getMethodInfo(); + if (mi == null) { + return (null); + } + + ci = mi.getClassInfo(); + if (ci == null) { + return (null); + } + + return (ci.getPackageName()); + } + } + + private static class CGClassAccessor implements CGAccessor { + + @Override + public Object getValue(ChoiceGenerator generator) { + ClassInfo ci; + MethodInfo mi; + Instruction instruction; + + instruction = generator.getInsn(); + if (instruction == null) { + return (null); + } + + mi = instruction.getMethodInfo(); + if (mi == null) { + return (null); + } + + ci = mi.getClassInfo(); + if (ci == null) { + return (null); + } + + return (ci.getName()); + } + } + + private static class CGMethodAccessor implements CGAccessor { + + @Override + public Object getValue(ChoiceGenerator generator) { + MethodInfo mi; + Instruction instruction; + + instruction = generator.getInsn(); + if (instruction == null) { + return (null); + } + + mi = instruction.getMethodInfo(); + if (mi == null) { + return (null); + } + + return (mi.getFullName()); + } + } + + private static class CGInstructionAccessor implements CGAccessor { + + @Override + public Object getValue(ChoiceGenerator generator) { + return (generator.getInsn()); + } + } + + private static class CGTypeAccessor implements CGAccessor { + + private static final String OBJECT_CLASS_NAME = Object.class.getName(); + private static final String THREAD_CLASS_NAME = Thread.class.getName(); + + @Override + public Object getValue(ChoiceGenerator generator) { + if (generator instanceof ThreadChoiceGenerator) { + return (getType((ThreadChoiceGenerator) generator)); + } + + if (generator instanceof BooleanChoiceGenerator) { + return (CGType.DataChoice); + } + + if (generator instanceof DoubleChoiceGenerator) { + return (CGType.DataChoice); + } + + if (generator instanceof IntChoiceGenerator) { + return (CGType.DataChoice); + } + + if (generator instanceof BooleanChoiceGenerator) { + return (CGType.DataChoice); + } + + return (null); + } + + private static CGType getType(ThreadChoiceGenerator generator) { + Instruction instruction; + + instruction = generator.getInsn(); + if (instruction == null) { + return (null); + } + + if (instruction instanceof JVMFieldInstruction) { + return (CGType.FieldAccess); + } + + if (instruction instanceof JVMInvokeInstruction) { + return (getType((JVMInvokeInstruction) instruction)); + } + + if (instruction instanceof JVMReturnInstruction) { + return (getType(generator, (JVMReturnInstruction) instruction)); + } + + if (instruction instanceof MONITORENTER) { + return (CGType.SyncEnter); + } + + if (instruction instanceof MONITOREXIT) { + return (CGType.SyncExit); + } + + return (null); + } + + private static CGType getType(JVMInvokeInstruction instruction) { + MethodInfo mi; + + if (is(instruction, OBJECT_CLASS_NAME, "wait")) { + return (CGType.ObjectWait); + } + + if (is(instruction, OBJECT_CLASS_NAME, "notify")) { + return (CGType.ObjectNotify); + } + + if (is(instruction, OBJECT_CLASS_NAME, "notifyAll")) { + return (CGType.ObjectNotify); + } + + if (is(instruction, THREAD_CLASS_NAME, "start")) { + return (CGType.ThreadStart); + } + + if (is(instruction, THREAD_CLASS_NAME, "suspend")) { + return (CGType.ThreadSuspend); + } + + if (is(instruction, THREAD_CLASS_NAME, "resume")) { + return (CGType.ThreadResume); + } + + mi = instruction.getInvokedMethod(); + if (mi.getClassName().startsWith("java.util.concurrent.atomic.")) { + return (CGType.AtomicOp); + } + + if (mi.isSynchronized()) { + return (CGType.SyncCall); + } + + return (null); + } + + private static boolean is(JVMInvokeInstruction instruction, String className, String methodName) { + MethodInfo mi; + ClassInfo ci; + + mi = instruction.getInvokedMethod(); + if (!methodName.equals(mi.getName())) { + return (false); + } + + ci = mi.getClassInfo(); + + if (!className.equals(ci.getName())) { + return (false); + } + + return (true); + } + + private static CGType getType(ThreadChoiceGenerator generator, JVMReturnInstruction instruction) { + MethodInfo mi; + + if (generator.getThreadInfo().getStackDepth() <= 1) // The main thread has 0 frames. Other threads have 1 frame. + { + return (CGType.ThreadTerminate); + } + + mi = instruction.getMethodInfo(); + if (mi.isSynchronized()) { + return (CGType.SyncReturn); + } + + return (null); + } + } + + private static class TreeNode { + + private final HashMap m_childNodes; + private final ArrayList m_sortedValues; + private final CGAccessor m_accessors[]; + private final Object m_value; + private final int m_level; + private String m_sampleGeneratorClassName; + private Instruction m_sampleGeneratorInstruction; + private int m_choiceCount; + private int m_generatorCount; + + TreeNode(CGAccessor accessors[], int level, Object value) { + m_accessors = accessors; + m_level = level; + m_value = value; + + if (level >= accessors.length) { + m_childNodes = null; + m_sortedValues = null; + } else { + m_sortedValues = new ArrayList(); + m_childNodes = new HashMap(); + } + } + + public void add(ChoiceGenerator generator) { + TreeNode child; + Object value; + + m_generatorCount++; + m_choiceCount += generator.getTotalNumberOfChoices(); + + if (isLeaf()) { + if (m_sampleGeneratorClassName == null) { + m_sampleGeneratorClassName = generator.getClass().getName(); + m_sampleGeneratorInstruction = generator.getInsn(); + } + + return; + } + + value = m_accessors[m_level].getValue(generator); + child = m_childNodes.get(value); + if (child == null) { + child = new TreeNode(m_accessors, m_level + 1, value); + m_childNodes.put(value, child); + } + + child.add(generator); + } + + public int getLevel() { + return (m_level); + } + + public Object getValue() { + return (m_value); + } + + public int getChoiceCount() { + return (m_choiceCount); + } + + public int getGeneratorCount() { + return (m_generatorCount); + } + + public String getSampleGeneratorClassName() { + return (m_sampleGeneratorClassName); + } + + public Instruction getSampleGeneratorInstruction() { + return (m_sampleGeneratorInstruction); + } + + public boolean isLeaf() { + return (m_childNodes == null); + } + + public void sort() { + Comparator comparator; + + if (isLeaf()) { + return; + } + + m_sortedValues.clear(); + m_sortedValues.addAll(m_childNodes.keySet()); + + comparator = new Comparator() { + + @Override + public int compare(Object value1, Object value2) { + TreeNode node1, node2; + + node1 = m_childNodes.get(value1); + node2 = m_childNodes.get(value2); + + return (node2.getChoiceCount() - node1.getChoiceCount()); // Sort descending + } + }; + + Collections.sort(m_sortedValues, comparator); + + for (TreeNode child : m_childNodes.values()) { + child.sort(); + } + } + + public List tour() { + List result; + + result = new ArrayList(); + tour(result); + + return (result); + } + + public void tour(List list) { + TreeNode child; + Object value; + int i; + + list.add(this); + + if (isLeaf()) { + return; + } + + for (i = 0; i < m_sortedValues.size(); i++) { + value = m_sortedValues.get(i); + child = m_childNodes.get(value); + child.tour(list); + } + } + + @Override + public String toString() { + StringBuilder result; + + result = new StringBuilder(); + + if (m_value == null) { + result.append("(null)"); + } else { + result.append(m_value); + } + + result.append(" - L"); + result.append(m_level); + result.append(" / C"); + result.append(m_choiceCount); + result.append(" / G"); + result.append(m_generatorCount); + result.append(" / N"); + result.append(m_childNodes.size()); + + return (result.toString()); + } + } + + private static class CGGrouper { + + private final CGAccessor m_accessors[]; + private final String m_name; + private TreeNode m_root; + private boolean m_sorted; + + CGGrouper(CGAccessor accessors[], String name) { + if (accessors.length <= 0) { + throw new IllegalArgumentException("accessors.length <= 0"); + } + + if (name == null) { + throw new NullPointerException("name == null"); + } + + m_accessors = accessors; + m_name = name; + + clear(); + } + + public void clear() { + m_sorted = false; + m_root = new TreeNode(m_accessors, 0, "All"); + } + + public String getName() { + return(m_name); + } + + public int getLevelCount() { + return(m_accessors.length); + } + + public TreeNode getTree() { + if (!m_sorted) { + m_sorted = true; + m_root.sort(); + } + + return(m_root); + } + + public void add(ChoiceGenerator generator) { + m_sorted = false; + m_root.add(generator); + } + } + + private static abstract class Publish { + + protected final Publisher m_publisher; + protected final CGGrouper m_groupers[]; + protected final int m_maxOutputLines; + protected PrintWriter m_output; + + Publish(Publisher publisher, CGGrouper groupers[], int maxOutputLines) { + m_publisher = publisher; + m_groupers = groupers; + m_maxOutputLines = maxOutputLines; + } + + public abstract void publish(); + } + + private static class PublishConsole extends Publish { + + PublishConsole(ConsolePublisher publisher, CGGrouper[] groupers, int maxOutputLines) { + super(publisher, groupers, maxOutputLines); + m_output = publisher.getOut(); + } + + @Override + public void publish() { + int i; + + for (i = 0; i < m_groupers.length; i++) { + publishSortedData(m_groupers[i]); + } + } + + private void publishSortedData(CGGrouper grouper) { + List tour; + TreeNode node; + int i, lines, levelCount; + + lines = 0; + levelCount = grouper.getLevelCount(); + node = grouper.getTree(); + tour = node.tour(); + + m_publisher.publishTopicStart("Grouped By: " + grouper.getName()); + + for (i = 0; (i < tour.size()) && (lines < m_maxOutputLines); i++) { + node = tour.get(i); + + publishTreeNode(node); + + if (node.isLeaf()) { + publishDetails(node, levelCount + 1); + lines++; + } + } + + if (lines >= m_maxOutputLines) { + m_output.println("..."); + } + } + + private void publishTreeNode(TreeNode node) { + Object value; + + // Tree + publishPadding(node.getLevel()); + + value = node.getValue(); + if (value == null) { + m_output.print("(null)"); + } else { + m_output.print(value); + } + + // Choices + m_output.print(" (choices: "); + m_output.print(node.getChoiceCount()); + + // Generators + m_output.print(", generators: "); + m_output.print(node.getGeneratorCount()); + + m_output.println(')'); + } + + private void publishDetails(TreeNode node, int levelCount) { + ChoiceGenerator generator; + Instruction instruction; + + instruction = node.getSampleGeneratorInstruction(); + + // Location + publishPadding(levelCount); + m_output.print("Location: "); + m_output.println(instruction.getFileLocation()); + + // Code + publishPadding(levelCount); + m_output.print("Code: "); + m_output.println(instruction.getSourceOrLocation().trim()); + + // Instruction + publishPadding(levelCount); + m_output.print("Instruction: "); + m_output.println(instruction.getMnemonic()); + + // Position + publishPadding(levelCount); + m_output.print("Position: "); + m_output.println(instruction.getPosition()); + + // Generator Class + publishPadding(levelCount); + m_output.print("Generator Class: "); + m_output.println(node.getSampleGeneratorClassName()); + } + + private void publishPadding(int levelCount) { + int i; + + for (i = levelCount; i > 0; i--) { + m_output.print(" "); + } + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/StateSpaceDot.java b/src/main/gov/nasa/jpf/listener/StateSpaceDot.java new file mode 100644 index 0000000..59e4df2 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/StateSpaceDot.java @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.Error; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Step; +import gov.nasa.jpf.vm.Transition; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/* + * Add a state space observer to JPF and build a graph of the state space + * that is explored by JPF. The graph can be generated in different formats. + * The current formats that are supported are DOT (visualized by a tool + * like GraphViz from ATT - http://www.graphviz.org/) and gdf (used by GUESS + * from HP - http://www.hpl.hp.com/research/idl/projects/graphs/). + * The graph is stored in a file called "jpf-state-space." where + * extension is ".dot" or ".gdf". By default it generates a DOT graph. + * + * Options: + * -gdf: Generate the graph in GDF format. The default is DOT. + * -transition-numbers: Include transition numbers in transition labels. + * -show-source: Include source lines in transition labels. + * -labelvisible: Indicates if the label on the transitions is visible (used only with the -gdf option) + * -help: Prints this help information and stops. + * + * @date 9/12/03 + * @author Owen O'Malley (Initial version generating the DOT graph) + * + * @date 7/17/05 + * @author Masoud Mansouri-Samani (Extended to also generate the gdf graph) + */ +public class StateSpaceDot extends ListenerAdapter { + // NODE styles constants + static final int RECTANGLE = 1; + static final int ELLIPSE = 2; + static final int ROUND_RECTANGLE = 3; + static final int RECTANGLE_WITH_TEXT = 4; + static final int ELLIPSE_WITH_TEXT = 5; + static final int ROUND_RECTANGLE_WITH_TEXT = 6; + + private static final String DOT_EXT = "dot"; + private static final String GDF_EXT = "gdf"; + private static final String OUT_FILENAME_NO_EXT = "jpf-state-space"; + + // State and transition node styles used + private static final int state_node_style = ELLIPSE_WITH_TEXT; + private static final int transition_node_style = RECTANGLE_WITH_TEXT; + + // File formats supported + private static final int DOT_FORMAT=0; + private static final int GDF_FORMAT=1; + + private BufferedWriter graph = null; + private int edge_id = 0; + private static boolean transition_numbers=false; + private static boolean show_source=false; + private static int format=DOT_FORMAT; + private String out_filename = OUT_FILENAME_NO_EXT+"."+DOT_EXT; + private static boolean labelvisible=false; + private static boolean helpRequested=false; + + + /* In gdf format all the edges must come after all the nodes of the graph + * are generated. So we first output the nodes as we come across them but + * we store the strings for edges in the gdfEdges list and output them when + * the search ends. + */ + ArrayList gdfEdges=new ArrayList(); + + private StateInformation prev_state = null; + + public StateSpaceDot(Config conf, JPF jpf) { + + VM vm = jpf.getVM(); + vm.recordSteps(true); + } + + @Override + public void searchStarted(Search search) { + try { + beginGraph(); + } catch (IOException e) {} + } + + @Override + public void searchFinished(Search search) { + try { + endGraph(); + } catch (IOException e) {} + } + + @Override + public void stateAdvanced(Search search) { + int id = search.getStateId(); + boolean has_next =search.hasNextState(); + boolean is_new = search.isNewState(); + try { + if (format==DOT_FORMAT) { + graph.write("/* searchAdvanced(" + id + ", " + makeDotLabel(search, id) + + ", " + has_next + ") */"); + graph.newLine(); + } + if (prev_state != null) { + addEdge(prev_state.id, id, search); + } else { + prev_state = new StateInformation(); + } + addNode(prev_state); + prev_state.reset(id, has_next, is_new); + } catch (IOException e) {} + } + + @Override + public void stateRestored (Search search) { + prev_state.reset(search.getStateId(), false, false); + } + + @Override + public void stateProcessed (Search search) { + // nothing to do + } + + @Override + public void stateBacktracked(Search search) { + try { + addNode(prev_state); + prev_state.reset(search.getStateId(), false, false); + if (format==DOT_FORMAT) { + graph.write("/* searchBacktracked(" + prev_state + ") */"); + graph.newLine(); + } + } catch (IOException e) {} + } + + @Override + public void searchConstraintHit(Search search) { + try { + if (format==DOT_FORMAT) { + graph.write("/* searchConstraintHit(" + search.getStateId() + ") */"); + graph.newLine(); + } + } catch (IOException e) {} + } + + private String getErrorMsg(Search search) { + List errs = search.getErrors(); + if (errs.isEmpty()) { + return null; + } else { + return errs.get(0).getDescription(); + } + } + + @Override + public void propertyViolated(Search search) { + try { + prev_state.error = getErrorMsg(search); + if (format==DOT_FORMAT) { + graph.write("/* propertyViolated(" + search.getStateId() + ") */"); + graph.newLine(); + } + } catch (IOException e) {} + } + + /** + * Put the header for the graph into the file. + */ + private void beginGraph() throws IOException { + graph = new BufferedWriter(new FileWriter(out_filename)); + if (format==GDF_FORMAT) { + graph.write("nodedef>name,label,style,color"); + } else { // dot + graph.write("digraph jpf_state_space {"); + } + graph.newLine(); + } + + /** + * In the case of the DOT graph it is just adding the final "}" at the end. + * In the case of GPF format we must output edge definition and all the + * edges that we have found. + */ + private void endGraph() throws IOException { + if(prev_state != null) + addNode(prev_state); + if (format==GDF_FORMAT) { + graph.write("edgedef>node1,node2,label,labelvisible,directed,thread INT"); + graph.newLine(); + + // Output all the edges that we have accumulated so far + int size=gdfEdges.size(); + for (int i=0; inode1,node2,label,labelvisible,directed,thread INT + + // Old State -> Transition - labeled with the source info if any. + gdfEdges.add( + makeGdfEdgeString("st"+old_id, "tr"+my_id, + makeGdfLabel(state, my_id), + thread)); + + // Transition node: name,label,style,color + graph.write("tr" + my_id + ",\"" +my_id+"\","+transition_node_style); + + graph.newLine(); + // Transition -> New State - labeled with the last output if any. + + String lastOutputLabel= + replaceString(convertGdfSpecial(trans.getOutput()), "\"", "\'\'"); + gdfEdges.add( + makeGdfEdgeString("tr"+my_id, "st"+new_id, lastOutputLabel, thread)); + } else { // DOT + graph.write(" st" + old_id + " -> tr" + my_id + ";"); + graph.newLine(); + graph.write(" tr" + my_id + " [label=\"" + makeDotLabel(state, my_id) + + "\",shape=box]"); + graph.newLine(); + graph.write(" tr" + my_id + " -> st" + new_id + ";"); + } + } + + /** + * Show the usage message. + */ + static void showUsage() { + System.out + .println("Usage: \"java [] gov.nasa.jpf.tools.StateSpaceDot [] []"); + System.out.println(" : "); + System.out.println(" -gdf: Generate the graph in GDF format. The default is DOT."); + System.out.println(" -transition-numbers: Include transition numbers in transition labels."); + System.out.println(" -show-source: Include source lines in transition labels."); + System.out.println(" -labelvisible: Indicates if the label on the transitions is visible (used only with the -gdf option)"); + System.out.println(" -help: Prints this help information and stops."); + System.out.println(" :"); + System.out.println(" Options and command line arguments passed directly to JPF."); + System.out.println(" Note: With -gdf option transition edges could also include program output "); + System.out.println(" but in order to enable this JPF's vm.path_output option must be set to "); + System.out.println(" true."); + } + + void filterArgs (String[] args) { + for (int i=0; i.n) + boolean storeMultiple; + + // do we want to terminate after first store, even if it's triggered by a + // property violation? + boolean terminateOnStore; + + boolean storeOnConstraintHit; + + // search depth at what we store the tace + int storeDepth; + + // calls that should trigger a store + StringSetMatcher storeCalls; + + // thread starts that should trigger a store + StringSetMatcher storeThreads; + + // do we want verbose output + boolean verbose; + + Search search; + VM vm; + + public TraceStorer (Config config, JPF jpf){ + + traceFileName = config.getString("trace.file", "trace"); + storeMultiple = config.getBoolean("trace.multiple", false); + storeDepth = config.getInt("trace.depth", Integer.MAX_VALUE); + verbose = config.getBoolean("trace.verbose", false); + + terminateOnStore = config.getBoolean("trace.terminate", false); + storeOnConstraintHit = config.getBoolean("trace.store_constraint", false); + + storeCalls = StringSetMatcher.getNonEmpty(config.getStringArray("trace.store_calls")); + storeThreads = StringSetMatcher.getNonEmpty(config.getStringArray("trace.store_threads")); + + vm = jpf.getVM(); + search = jpf.getSearch(); + } + + void storeTrace(String reason) { + String fname = traceFileName; + + if (storeMultiple){ + fname = fname + '.' + nTrace++; + } + + vm.storeTrace(fname, reason, verbose); // <2do> maybe some comment would be in order + } + + @Override + public void propertyViolated (Search search){ + // Ok, this is unconditional + storeTrace("violated property: " + search.getLastError().getDetails()); + + // no need to terminate (and we don't want to interfere with search.multiple_errors) + } + + @Override + public void stateAdvanced (Search search){ + if (search.getDepth() == storeDepth){ + storeTrace("search depth reached: " + storeDepth); + checkSearchTermination(); + } + } + + @Override + public void searchConstraintHit (Search search){ + if (storeOnConstraintHit){ + storeTrace("search constraint hit: " + search.getLastSearchConstraint()); + } + } + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){ + if (storeCalls != null){ + if (executedInsn instanceof JVMInvokeInstruction) { + JVMInvokeInstruction iinsn = (JVMInvokeInstruction)executedInsn; + String clsName = iinsn.getInvokedMethodClassName(); + String mthName = iinsn.getInvokedMethodName(); + String mn = clsName + '.' + mthName; + + if (storeCalls.matchesAny(mn)){ + storeTrace("call: " + mn); + checkVMTermination(ti); + } + } + } + } + + @Override + public void threadStarted(VM vm, ThreadInfo ti) { + if (storeThreads != null){ + String tname = ti.getName(); + if (storeThreads.matchesAny( tname)){ + storeTrace("thread started: " + tname); + checkVMTermination(ti); + } + } + } + + boolean checkVMTermination(ThreadInfo ti) { + if (terminateOnStore){ + ti.breakTransition("storeTraceTermination"); + search.terminate(); + return true; + } + + return false; + } + + boolean checkSearchTermination() { + if (terminateOnStore){ + search.terminate(); + return true; + } + + return false; + } +} diff --git a/src/main/gov/nasa/jpf/listener/VarRecorder.java b/src/main/gov/nasa/jpf/listener/VarRecorder.java new file mode 100644 index 0000000..8727943 --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/VarRecorder.java @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.JVMArrayElementInstruction; +import gov.nasa.jpf.jvm.bytecode.ArrayLoadInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMLocalVariableInstruction; +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.bytecode.LocalVariableInstruction; +import gov.nasa.jpf.util.StringSetMatcher; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.FieldInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.Step; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Types; + +import java.util.HashMap; + +/** + * Simple listener tool to record the values of variables as they are accessed. + * Records the information in Step.setComment() so that when the trace is + * written the values can be written too. + */ +public class VarRecorder extends ListenerAdapter { + + private final HashMap pendingComment = new HashMap(); + + private final StringSetMatcher includes; + private final StringSetMatcher excludes; + private final boolean recordFields; + private final boolean recordLocals; + private final boolean recordArrays; + + private ClassInfo lastClass; + private boolean recordClass; + + public VarRecorder(Config config) { + includes = StringSetMatcher.getNonEmpty(config.getStringArray("var_recorder.include")); + excludes = StringSetMatcher.getNonEmpty(config.getStringArray("var_recorder.exclude")); + recordFields = config.getBoolean("var_recorder.fields", true); + recordLocals = config.getBoolean("var_recorder.locals", true); + recordArrays = config.getBoolean("var_recorder.arrays", true); + } + + @Override + public void executeInstruction(VM vm, ThreadInfo ti, Instruction insnToExecute) { + String name, value; + byte type; + + if (!canRecord(vm, insnToExecute)) + return; + + if (!(insnToExecute instanceof StoreInstruction)) + if (!(insnToExecute instanceof ArrayLoadInstruction)) + return; + + type = getType(ti, insnToExecute); + name = getName(ti, insnToExecute, type); + + if (insnToExecute instanceof ArrayLoadInstruction) { + setComment(vm, ti, name, "", "", true); + saveVariableType(ti, type); + } else { + value = getValue(ti, insnToExecute, type); + setComment(vm, ti, name, " <- ", value, true); + } + } + + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + String name, value; + byte type; + + if (!canRecord(vm, executedInsn)) + return; + + if (executedInsn instanceof StoreInstruction) { + name = pendingComment.remove(ti); + setComment(vm, ti, name, "", "", false); + return; + } + + type = getType(ti, executedInsn); + value = getValue(ti, executedInsn, type); + + if (executedInsn instanceof ArrayLoadInstruction) + name = pendingComment.remove(ti); + else + name = getName(ti, executedInsn, type); + + if (isArrayReference(vm, ti)) + saveVariableName(ti, name); + else + saveVariableType(ti, type); + + setComment(vm, ti, name, " -> ", value, false); + } + + private final void setComment(VM vm, ThreadInfo ti, String name, String operator, String value, boolean pending) { + Step step; + String comment; + + if (name == null) + return; + + if (value == null) + return; + + comment = name + operator + value; + + if (pending) { + pendingComment.put(ti, comment); + } else { + step = vm.getLastStep(); + step.setComment(name + operator + value); + } + } + + private final boolean canRecord(VM vm, Instruction inst) { + ClassInfo ci; + MethodInfo mi; + + if (vm.getLastStep() == null) + return(false); + + if (!(inst instanceof LocalVariableInstruction)) + if (!(inst instanceof JVMArrayElementInstruction)) + return(false); + + mi = inst.getMethodInfo(); + if (mi == null) + return(false); + + ci = mi.getClassInfo(); + if (ci == null) + return(false); + + if (lastClass != ci) { + lastClass = ci; + recordClass = StringSetMatcher.isMatch(ci.getName(), includes, excludes); + } + + return(recordClass); + } + + // <2do> general purpose listeners should not use anonymous attribute types such as String + + private final void saveVariableName(ThreadInfo ti, String name) { + StackFrame frame = ti.getModifiableTopFrame(); + frame.addOperandAttr(name); + } + + private final void saveVariableType(ThreadInfo ti, byte type) { + StackFrame frame; + String str; + + frame = ti.getModifiableTopFrame(); + if (frame.getTopPos() < 0) { + return; + } + + str = encodeType(type); + frame.addOperandAttr(str); + } + + private final boolean isArrayReference(VM vm, ThreadInfo ti) { + StackFrame frame = ti.getTopFrame(); + + if (frame.getTopPos() < 0) { + return(false); + } + + if (!frame.isOperandRef()) { + return(false); + } + + int objRef = frame.peek(); + if (objRef == MJIEnv.NULL) { + return(false); + } + + ElementInfo ei = ti.getElementInfo(objRef); + if (ei == null) { + return(false); + } + + return(ei.isArray()); + } + + private byte getType(ThreadInfo ti, Instruction inst) { + StackFrame frame; + FieldInfo fi; + String type; + + frame = ti.getTopFrame(); + if ((frame.getTopPos() >= 0) && (frame.isOperandRef())) { + return (Types.T_REFERENCE); + } + + type = null; + + if (((recordLocals) && (inst instanceof JVMLocalVariableInstruction)) + || ((recordFields) && (inst instanceof JVMFieldInstruction))) { + if (inst instanceof JVMLocalVariableInstruction) { + type = ((JVMLocalVariableInstruction) inst).getLocalVariableType(); + } else { + fi = ((JVMFieldInstruction) inst).getFieldInfo(); + type = fi.getType(); + } + } + + if ((recordArrays) && (inst instanceof JVMArrayElementInstruction)) { + return (getTypeFromInstruction(inst)); + } + + if (type == null) { + return (Types.T_VOID); + } + + return (decodeType(type)); + } + + private final static byte getTypeFromInstruction(Instruction inst) { + if (inst instanceof JVMArrayElementInstruction) + return(getTypeFromInstruction((JVMArrayElementInstruction) inst)); + + return(Types.T_VOID); + } + + private final static byte getTypeFromInstruction(JVMArrayElementInstruction inst) { + String name; + + name = inst.getClass().getName(); + name = name.substring(name.lastIndexOf('.') + 1); + + switch (name.charAt(0)) { + case 'A': return(Types.T_REFERENCE); + case 'B': return(Types.T_BYTE); // Could be a boolean but it is better to assume a byte. + case 'C': return(Types.T_CHAR); + case 'F': return(Types.T_FLOAT); + case 'I': return(Types.T_INT); + case 'S': return(Types.T_SHORT); + case 'D': return(Types.T_DOUBLE); + case 'L': return(Types.T_LONG); + } + + return(Types.T_VOID); + } + + private final static String encodeType(byte type) { + switch (type) { + case Types.T_BYTE: return("B"); + case Types.T_CHAR: return("C"); + case Types.T_DOUBLE: return("D"); + case Types.T_FLOAT: return("F"); + case Types.T_INT: return("I"); + case Types.T_LONG: return("J"); + case Types.T_REFERENCE: return("L"); + case Types.T_SHORT: return("S"); + case Types.T_VOID: return("V"); + case Types.T_BOOLEAN: return("Z"); + case Types.T_ARRAY: return("["); + } + + return("?"); + } + + private final static byte decodeType(String type) { + if (type.charAt(0) == '?'){ + return(Types.T_REFERENCE); + } else { + return Types.getBuiltinType(type); + } + } + + private String getName(ThreadInfo ti, Instruction inst, byte type) { + String name; + int index; + boolean store; + + if (((recordLocals) && (inst instanceof JVMLocalVariableInstruction)) || + ((recordFields) && (inst instanceof JVMFieldInstruction))) { + name = ((LocalVariableInstruction) inst).getVariableId(); + name = name.substring(name.lastIndexOf('.') + 1); + + return(name); + } + + if ((recordArrays) && (inst instanceof JVMArrayElementInstruction)) { + store = inst instanceof StoreInstruction; + name = getArrayName(ti, type, store); + index = getArrayIndex(ti, type, store); + return(name + '[' + index + ']'); + } + + return(null); + } + + private String getValue(ThreadInfo ti, Instruction inst, byte type) { + StackFrame frame; + int lo, hi; + + frame = ti.getTopFrame(); + + if (((recordLocals) && (inst instanceof JVMLocalVariableInstruction)) || + ((recordFields) && (inst instanceof JVMFieldInstruction))) + { + if (frame.getTopPos() < 0) + return(null); + + lo = frame.peek(); + hi = frame.getTopPos() >= 1 ? frame.peek(1) : 0; + + return(decodeValue(type, lo, hi)); + } + + if ((recordArrays) && (inst instanceof JVMArrayElementInstruction)) + return(getArrayValue(ti, type)); + + return(null); + } + + private String getArrayName(ThreadInfo ti, byte type, boolean store) { + String attr; + int offset; + + offset = calcOffset(type, store) + 1; + // <2do> String is really not a good attribute type to retrieve! + StackFrame frame = ti.getTopFrame(); + attr = frame.getOperandAttr( offset, String.class); + + if (attr != null) { + return(attr); + } + + return("?"); + } + + private int getArrayIndex(ThreadInfo ti, byte type, boolean store) { + int offset; + + offset = calcOffset(type, store); + + return(ti.getTopFrame().peek(offset)); + } + + private final static int calcOffset(byte type, boolean store) { + if (!store) + return(0); + + return(Types.getTypeSize(type)); + } + + private String getArrayValue(ThreadInfo ti, byte type) { + StackFrame frame; + int lo, hi; + + frame = ti.getTopFrame(); + lo = frame.peek(); + hi = frame.getTopPos() >= 1 ? frame.peek(1) : 0; + + return(decodeValue(type, lo, hi)); + } + + private final static String decodeValue(byte type, int lo, int hi) { + switch (type) { + case Types.T_ARRAY: return(null); + case Types.T_VOID: return(null); + + case Types.T_BOOLEAN: return(String.valueOf(Types.intToBoolean(lo))); + case Types.T_BYTE: return(String.valueOf(lo)); + case Types.T_CHAR: return(String.valueOf((char) lo)); + case Types.T_DOUBLE: return(String.valueOf(Types.intsToDouble(lo, hi))); + case Types.T_FLOAT: return(String.valueOf(Types.intToFloat(lo))); + case Types.T_INT: return(String.valueOf(lo)); + case Types.T_LONG: return(String.valueOf(Types.intsToLong(lo, hi))); + case Types.T_SHORT: return(String.valueOf(lo)); + + case Types.T_REFERENCE: + ElementInfo ei = VM.getVM().getHeap().get(lo); + if (ei == null) + return(null); + + ClassInfo ci = ei.getClassInfo(); + if (ci == null) + return(null); + + if (ci.getName().equals("java.lang.String")) + return('"' + ei.asString() + '"'); + + return(ei.toString()); + + default: + System.err.println("Unknown type: " + type); + return(null); + } + } +} diff --git a/src/main/gov/nasa/jpf/listener/VarTracker.java b/src/main/gov/nasa/jpf/listener/VarTracker.java new file mode 100644 index 0000000..9615e5a --- /dev/null +++ b/src/main/gov/nasa/jpf/listener/VarTracker.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.listener; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.ALOAD; +import gov.nasa.jpf.jvm.bytecode.ArrayStoreInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.GETFIELD; +import gov.nasa.jpf.jvm.bytecode.GETSTATIC; +import gov.nasa.jpf.vm.bytecode.ReadInstruction; +import gov.nasa.jpf.vm.bytecode.StoreInstruction; +import gov.nasa.jpf.vm.bytecode.LocalVariableInstruction; +import gov.nasa.jpf.report.ConsolePublisher; +import gov.nasa.jpf.report.Publisher; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.util.MethodSpec; +import gov.nasa.jpf.util.StringSetMatcher; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.MJIEnv; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.bytecode.WriteInstruction; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + + +/** + * simple listener tool to find out which variables (locals and fields) are + * changed how often and from where. This should give a good idea if a state + * space blows up because of some counter/timer vars, and where to apply the + * necessary abstractions to close/shrink it + * + */ +public class VarTracker extends ListenerAdapter { + + // our matchers to determine which variables we have to report + StringSetMatcher includeVars = null; // means all + StringSetMatcher excludeVars = null; // means none + + // filter methods from which access happens + MethodSpec methodSpec; + + int maxVars; // maximum number of variables shown + + ArrayList queue = new ArrayList(); + ThreadInfo lastThread; + HashMap stat = new HashMap(); + int nStates = 0; + int maxDepth; + + + public VarTracker (Config config, JPF jpf){ + + includeVars = StringSetMatcher.getNonEmpty(config.getStringArray("vt.include")); + excludeVars = StringSetMatcher.getNonEmpty(config.getStringArray("vt.exclude", + new String[] {"java.*", "javax.*"} )); + + maxVars = config.getInt("vt.max_vars", 25); + + methodSpec = MethodSpec.createMethodSpec(config.getString("vt.methods", "!java.*.*")); + + jpf.addPublisherExtension(ConsolePublisher.class, this); + } + + @Override + public void publishPropertyViolation (Publisher publisher) { + PrintWriter pw = publisher.getOut(); + publisher.publishTopicStart("field access "); + + report(pw); + } + + void print (PrintWriter pw, int n, int length) { + String s = Integer.toString(n); + int l = length - s.length(); + + for (int i=0; i values = stat.values(); + List valueList = new ArrayList(); + valueList.addAll(values); + Collections.sort(valueList); + + int n = 0; + for (VarStat s : valueList) { + + if (n++ > maxVars) { + break; + } + + print(pw, s.nChanges, 12); + pw.print(" "); + pw.println(s.id); + } + } + + @Override + public void stateAdvanced(Search search) { + + if (search.isNewState()) { // don't count twice + int stateId = search.getStateId(); + nStates++; + int depth = search.getDepth(); + if (depth > maxDepth) maxDepth = depth; + + if (!queue.isEmpty()) { + for (Iterator it = queue.iterator(); it.hasNext(); ){ + VarChange change = it.next(); + String id = change.getVariableId(); + VarStat s = stat.get(id); + if (s == null) { + s = new VarStat(id, stateId); + stat.put(id, s); + } else { + // no good - we should filter during reg (think of large vectors or loop indices) + if (s.lastState != stateId) { // count only once per new state + s.nChanges++; + s.lastState = stateId; + } + } + } + } + } + + queue.clear(); + } + + // <2do> - general purpose listeners should not use types such as String for storing + // attributes, there is no good way to make sure you retrieve your own attributes + @Override + public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) { + String varId; + + if (executedInsn instanceof ALOAD) { + // a little extra work - we need to keep track of variable names, because + // we cannot easily retrieve them in a subsequent xASTORE, which follows + // a pattern like: ..GETFIELD.. some-stack-operations .. xASTORE + StackFrame frame = ti.getTopFrame(); + int objRef = frame.peek(); + if (objRef != MJIEnv.NULL) { + ElementInfo ei = ti.getElementInfo(objRef); + if (ei.isArray()) { + varId = ((LocalVariableInstruction) executedInsn).getVariableId(); + + // <2do> unfortunately, we can't filter here because we don't know yet + // how the array ref will be used (we would only need the attr for + // subsequent xASTOREs) + frame = ti.getModifiableTopFrame(); + frame.addOperandAttr(varId); + } + } + + } else if ((executedInsn instanceof ReadInstruction) && ((JVMFieldInstruction)executedInsn).isReferenceField()){ + varId = ((JVMFieldInstruction)executedInsn).getFieldName(); + + StackFrame frame = ti.getModifiableTopFrame(); + frame.addOperandAttr(varId); + + + // here come the changes - note that we can't update the stats right away, + // because we don't know yet if the state this leads into has already been + // visited, and we want to detect only var changes that lead to *new* states + // (objective is to find out why we have new states). Note that variable + // changes do not necessarily contribute to the state hash (@FilterField) + } else if (executedInsn instanceof StoreInstruction) { + if (executedInsn instanceof ArrayStoreInstruction) { + // did we have a name for the array? + // stack is ".. ref idx [l]value => .." + // <2do> String is not a good attribute type to retrieve + Object attr = ((ArrayStoreInstruction)executedInsn).getArrayOperandAttr(ti); + if (attr != null) { + varId = attr + "[]"; + } else { + varId = "?[]"; + } + } else { + varId = ((LocalVariableInstruction)executedInsn).getVariableId(); + } + queueIfRelevant(ti, executedInsn, varId); + + } else if (executedInsn instanceof WriteInstruction){ + varId = ((WriteInstruction) executedInsn).getFieldInfo().getFullName(); + queueIfRelevant(ti, executedInsn, varId); + } + } + + void queueIfRelevant(ThreadInfo ti, Instruction insn, String varId){ + if (isMethodRelevant(insn.getMethodInfo()) && isVarRelevant(varId)) { + queue.add(new VarChange(varId)); + lastThread = ti; + } + } + + boolean isMethodRelevant (MethodInfo mi){ + return methodSpec.matches(mi); + } + + boolean isVarRelevant (String varId) { + if (!StringSetMatcher.isMatch(varId, includeVars, excludeVars)){ + return false; + } + + // filter subsequent changes in the same transition (to avoid gazillions of + // VarChanges for loop variables etc.) + // <2do> this is very inefficient - improve + for (int i=0; i expand into types to record value ranges +class VarStat implements Comparable { + String id; // class[@objRef].field || class[@objref].method.local + int nChanges; + + int lastState; // this was changed in (<2do> don't think we need this) + + // might have more info in the future, e.g. total number of changes vs. + // number of states incl. this var change, source locations, threads etc. + + VarStat (String varId, int stateId) { + id = varId; + nChanges = 1; + + lastState = stateId; + } + + int getChangeCount () { + return nChanges; + } + + @Override + public int compareTo (VarStat other) { + if (other.nChanges > nChanges) { + return 1; + } else if (other.nChanges == nChanges) { + return 0; + } else { + return -1; + } + } +} + +// <2do> expand into types to record values +class VarChange { + String id; + + VarChange (String varId) { + id = varId; + } + + String getVariableId () { + return id; + } +} diff --git a/src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.java b/src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.java new file mode 100644 index 0000000..58636c0 --- /dev/null +++ b/src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.java @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.perturb; + +import java.util.Random; +import java.util.Vector; +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.IntChoiceGenerator; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.Types; +import gov.nasa.jpf.vm.choice.IntChoiceFromSet; + +/** + * This file implements a generic data abstraction module that can be used + * with the Perturbator to execute a method with a choice of values for the + * method parameters. + * + * This module handles all basic types and selects values for them as follows: + * int, short: random negative integer | 0 | random positive integer + * float: random negative floating point | 0 | random positive floating point + * char: two random values in [0, 255] and an explicit 0 + * boolean: true | false + * + * An instance of this class is expected to be specialized for each method that we + * want perturbed. The cstor creates a vector of valuations for the parameters + * using all choices for each basic type such that each vector can be written + * directly into the method stack frame for parameters + * + */ + +public class GenericDataAbstractor implements OperandPerturbator { + + // A valuations helper class + public class Valuation { + protected int valuation[] = null; + + public Valuation(int size) { + valuation = new int[size]; + } + // create an object from an existing valuation + public Valuation(Valuation seedValuation) { + valuation = seedValuation.valuation.clone(); + } + public Valuation(Valuation val, int size) { + valuation = new int[size]; + int[] valuationArray = val.getValuation(); + for (int i = 0; i < valuationArray.length; i++) + valuation[i] = valuationArray[i]; + } + public int[] getValuation() { + return valuation; + } + public void add(int index, int element) { + valuation[index] = element; + } + } + + static long seed = 5; + + protected MethodInfo mi; + protected StackFrame stackFrame; + protected int nParams; + protected byte[] paramTypes = null; + protected String[] paramTypeNames = null; + protected String[] paramNames = null; + protected Vector valuations = new Vector(); + protected int choices; + protected int operandSize; + protected Valuation valuation = null; + protected boolean isStatic; + protected Random randomizer = new Random(seed); + + public GenericDataAbstractor (Config conf, String keyPrefix){ + // this will expand to read parameters from the configuration + // to specialize the behavior of the abstractor + mi = null; + choices = 0; + } + + // At the time of instance creation we don't have the MethodInfo object + // for the method that needs its parameters perturbed. Therefore, we + // should set MethodInfo using a call to the following method before + // we can use this instance to perturb a method invocation + public void setMethodInfo(MethodInfo m, StackFrame frame) { + if (mi != null) + return; + + mi = m; + stackFrame = frame; + // Need to figure out the right number of parameters. + paramTypes = mi.getArgumentTypes(); + paramTypeNames = mi.getArgumentTypeNames(); + nParams = paramTypes.length; + isStatic = mi.isStatic(); + + // now compute the operand size in 32-bit words + operandSize = 0; + for (byte type : paramTypes) { + if (type == Types.T_LONG || type == Types.T_DOUBLE) + operandSize += 2; + else + operandSize++; + } + + // useful when we call the various populate methods that populate + // choice vectors. The parameter name can be used to specialize + // population to parameter names + paramNames = new String[nParams]; + if (nParams != 0) { + String[] localVars = mi.getLocalVariableNames(); + for (int i = 0; i < nParams; i++) { + paramNames[i] = isStatic? localVars[i] : localVars[i + 1]; + } + } + + // We build an array of choices, with each choice being an index into + // an array of integers representing the operand stack values. + // We then use an IntChoiceGenerator to give us an index that is then + // used to access the values we want to replace for the operands on the + // stack + + valuation = new Valuation(operandSize); + valuations.add(valuation); + populateValuations(frame, 0, 0); + + // we now know how many choices there are and hence set choices + choices = valuations.size() - 1; + } + + // Method to populate boolean values + public int[] populateBoolean(MethodInfo mi, String name) { + int[] bVec = {0 /* false */, 1 /* true */}; + + return bVec; + } + + // Method to populate character values + public int[] populateChar(MethodInfo mi, String name) { + int[] iVec = {Math.abs(randomizer.nextInt() % 255), 0, Math.abs(randomizer.nextInt() % 255)}; + + return iVec; + } + + // Method to populate byte values + public int[] populateByte(MethodInfo mi, String name) { + int[] iVec = {Math.abs(randomizer.nextInt() % 128), 0, -1 * Math.abs(randomizer.nextInt() % 127)}; + + return iVec; + } + + // Method to populate integer values + public int[] populateInt(MethodInfo mi, String name) { + int[] iVec = {Math.abs(randomizer.nextInt() % 100), 0, -1 * Math.abs(randomizer.nextInt() % 100)}; + + return iVec; + } + + // Method to populate integer values + public int[] populateShort(MethodInfo mi, String name) { + return populateInt(mi, name); + } + + // Method to populate long values + public int[] populateLong(MethodInfo mi, String name) { + long[] lVec = {Math.abs(randomizer.nextLong() % 100), 0, -1 * Math.abs(randomizer.nextLong() % 100)}; + int[] iVec = new int[lVec.length * 2]; + + int i = 0; + for (long l : lVec) { + iVec[i++] = Types.hiLong(l); + iVec[i++] = Types.loLong(l); + } + return iVec; + } + + // Method to populate integer values + public int[] populateFloat(MethodInfo mi, String name) { + int[] fVec = {Float.floatToIntBits(randomizer.nextFloat()), 0, + -1 * Float.floatToIntBits(randomizer.nextFloat())}; + + return fVec; + } + + // Method to populate long values + public int[] populateDouble(MethodInfo mi, String name) { + double[] dVec = {-1.414, 0.0, 3.141}; + int[] iVec = new int[dVec.length * 2]; + + int i = 0; + for (double d : dVec) { + iVec[i++] = Types.hiDouble(d); + iVec[i++] = Types.loDouble(d); + } + return iVec; + } + + public void populateValuations(StackFrame frame, int paramIndex, int dataIndex) { + if (paramIndex == nParams) { + // copy the contents of the previous vector as a + // suffix of it will be over-written, retaining + // the valuations for all parameters ahead of the + // suffix + valuation = new Valuation(valuation); + valuations.add(valuation); + } else { + switch (paramTypes[paramIndex]) { + case Types.T_ARRAY: + populateValuations(frame, paramIndex + 1, dataIndex + 1); + break; + case Types.T_BOOLEAN: + int[] bVec = populateBoolean(mi, paramNames[paramIndex]); + for (int i = 0; i < bVec.length; i++) { + valuation.add(dataIndex, bVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_FLOAT: + int[] fVec = populateFloat(mi, paramNames[paramIndex]); + for (int i = 0; i < fVec.length; i++) { + valuation.add(dataIndex, fVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_CHAR: + int[] iVec = populateChar(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_BYTE: + iVec = populateByte(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_INT: + iVec = populateInt(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_SHORT: + iVec = populateShort(mi, paramNames[paramIndex]); + for (int i = 0; i < iVec.length; i++) { + valuation.add(dataIndex, iVec[i]); + populateValuations(frame, paramIndex + 1, dataIndex + 1); + } + break; + case Types.T_LONG: + int[] lVec = populateLong(mi, paramNames[paramIndex]); + int i = 0; + while (i < lVec.length) { + valuation.add(dataIndex, lVec[i++]); + valuation.add(dataIndex + 1, lVec[i++]); + populateValuations(frame, paramIndex + 1, dataIndex + 2); + } + break; + case Types.T_DOUBLE: + int[] dVec = populateDouble(mi, paramNames[paramIndex]); + i = 0; + while (i < dVec.length) { + valuation.add(dataIndex, dVec[i++]); + valuation.add(dataIndex + 1, dVec[i++]); + populateValuations(frame, paramIndex + 1, dataIndex + 2); + } + break; + } + } + } + + @Override + public ChoiceGenerator createChoiceGenerator (String id, StackFrame frame, Object refObject) { + // We expect that the refObject in this case will be a MethodInfo object + // Set it so that we can create valuation vectors + assert refObject instanceof MethodInfo : "wrong refObject type for GenericDataAbstractor: " + + refObject.getClass().getName(); + + setMethodInfo((MethodInfo)refObject, frame); + + if (choices > 0) { + // now create a choices vector which will be used to iterate over the number of + // parameter valuations we want to use. We set each element of the vector simply + // to an index into the valuations vector + int[] indices = new int[choices]; + for (int i = 0; i < choices; i++) { + indices[i] = i; + } + return new IntChoiceFromSet(id, indices); + } else + return null; + } + + @Override + public boolean perturb(ChoiceGeneratorcg, StackFrame frame) { + assert cg instanceof IntChoiceGenerator : "wrong choice generator type for GenericDataAbstractor: " + cg.getClass().getName(); + + int choice = ((IntChoiceGenerator)cg).getNextChoice(); + Valuation valuation = valuations.get(choice); + + // iterate over the number of operands and set the operand array to the values + // we have in the valuation vector + int val = 0; + + int top = frame.getTopPos(); + int stackIdx = frame.getLocalVariableCount() + ((isStatic)? 0 : 1); + int argSize = paramTypes.length; + + for (int j = 0; j < argSize; j++) { // j ranges over actual arguments + if (!frame.isOperandRef(top - stackIdx)) { + frame.setOperand(top - stackIdx++, valuation.getValuation()[val++], false); + if (paramTypes[j] == Types.T_LONG || paramTypes[j] == Types.T_DOUBLE) { + frame.setOperand(top - stackIdx++, valuation.getValuation()[val++], false); + } + } + } + + return cg.hasMoreChoices(); + } + + @Override + public Class> getChoiceGeneratorType(){ + return IntChoiceFromSet.class; + } +} diff --git a/src/main/gov/nasa/jpf/perturb/IntOverUnder.java b/src/main/gov/nasa/jpf/perturb/IntOverUnder.java new file mode 100644 index 0000000..87693c5 --- /dev/null +++ b/src/main/gov/nasa/jpf/perturb/IntOverUnder.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.perturb; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.IntChoiceGenerator; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.choice.IntChoiceFromSet; + +/** + * simple +/- delta perturbation of integer operand values + */ +public class IntOverUnder implements OperandPerturbator { + + protected int delta; + protected int offset; + + public IntOverUnder (Config conf, String keyPrefix) { + delta = conf.getInt(keyPrefix + ".delta", 0); + offset = 0; + } + + public IntOverUnder (int delta){ + this.delta = delta; + offset = 0; + } + + @Override + public ChoiceGenerator createChoiceGenerator (String id, StackFrame frame, Object refObject){ + int val = frame.peek(offset); + + int[] values = new int[3]; + + values[0] = val + delta; + values[1] = val; + values[2] = val - delta; + + // set offset from refObject + offset = (Integer)refObject; + + return new IntChoiceFromSet(id, values); + } + + @Override + public boolean perturb(ChoiceGeneratorcg, StackFrame frame) { + assert cg instanceof IntChoiceGenerator : "wrong choice generator type for IntOverUnder: " + cg.getClass().getName(); + + int val = ((IntChoiceGenerator)cg).getNextChoice(); + frame.setOperand(offset, val, false); + return cg.hasMoreChoices(); + } + + @Override + public Class> getChoiceGeneratorType(){ + return IntChoiceFromSet.class; + } +} diff --git a/src/main/gov/nasa/jpf/perturb/OperandPerturbator.java b/src/main/gov/nasa/jpf/perturb/OperandPerturbator.java new file mode 100644 index 0000000..289e240 --- /dev/null +++ b/src/main/gov/nasa/jpf/perturb/OperandPerturbator.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.perturb; + +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.StackFrame; + + +/** + * basic type for policy objects that perturb operand stacks by means + * of choice generators + */ +public interface OperandPerturbator { + + Class> getChoiceGeneratorType(); + + ChoiceGenerator createChoiceGenerator (String id, StackFrame frame, Object refObject); + + boolean perturb (ChoiceGenerator cg, StackFrame frame); +} diff --git a/src/main/gov/nasa/jpf/report/ConsolePublisher.java b/src/main/gov/nasa/jpf/report/ConsolePublisher.java new file mode 100644 index 0000000..b8db8ae --- /dev/null +++ b/src/main/gov/nasa/jpf/report/ConsolePublisher.java @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.report; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.Error; +import gov.nasa.jpf.util.Left; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.Path; +import gov.nasa.jpf.vm.Step; +import gov.nasa.jpf.vm.Transition; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +public class ConsolePublisher extends Publisher { + + // output destinations + String fileName; + FileOutputStream fos; + + String port; + + // the various degrees of information for program traces + protected boolean showCG; + protected boolean showSteps; + protected boolean showLocation; + protected boolean showSource; + protected boolean showMethod; + protected boolean showCode; + + public ConsolePublisher(Config conf, Reporter reporter) { + super(conf, reporter); + + // options controlling the output destination + fileName = conf.getString("report.console.file"); + port = conf.getString("report.console.port"); + + // options controlling what info should be included in a trace + showCG = conf.getBoolean("report.console.show_cg", true); + showSteps = conf.getBoolean("report.console.show_steps", true); + showLocation = conf.getBoolean("report.console.show_location", true); + showSource = conf.getBoolean("report.console.show_source", true); + showMethod = conf.getBoolean("report.console.show_method", false); + showCode = conf.getBoolean("report.console.show_code", false); + } + + @Override + public String getName() { + return "console"; + } + + @Override + protected void openChannel(){ + + if (fileName != null) { + try { + fos = new FileOutputStream(fileName); + out = new PrintWriter( fos); + } catch (FileNotFoundException x) { + // fall back to System.out + } + } else if (port != null) { + // <2do> + } + + if (out == null){ + out = new PrintWriter(System.out, true); + } + } + + @Override + protected void closeChannel() { + if (fos != null){ + out.close(); + } + } + + @Override + public void publishTopicStart (String topic) { + out.println(); + out.print("====================================================== "); + out.println(topic); + } + + @Override + public void publishTopicEnd (String topic) { + // nothing here + } + + @Override + public void publishStart() { + super.publishStart(); + + if (startItems.length > 0){ // only report if we have output for this phase + publishTopicStart("search started: " + formatDTG(reporter.getStartDate())); + } + } + + @Override + public void publishFinished() { + super.publishFinished(); + + if (finishedItems.length > 0){ // only report if we have output for this phase + publishTopicStart("search finished: " + formatDTG(reporter.getFinishedDate())); + } + } + + @Override + protected void publishJPF() { + out.println(reporter.getJPFBanner()); + out.println(); + } + + @Override + protected void publishDTG() { + out.println("started: " + reporter.getStartDate()); + } + + @Override + protected void publishUser() { + out.println("user: " + reporter.getUser()); + } + + @Override + protected void publishJPFConfig() { + publishTopicStart("JPF configuration"); + + TreeMap map = conf.asOrderedMap(); + Set> eSet = map.entrySet(); + + for (Object src : conf.getSources()){ + out.print("property source: "); + out.println(conf.getSourceName(src)); + } + + out.println("properties:"); + for (Map.Entry e : eSet) { + out.println(" " + e.getKey() + "=" + e.getValue()); + } + } + + @Override + protected void publishPlatform() { + publishTopicStart("platform"); + out.println("hostname: " + reporter.getHostName()); + out.println("arch: " + reporter.getArch()); + out.println("os: " + reporter.getOS()); + out.println("java: " + reporter.getJava()); + } + + + @Override + protected void publishSuT() { + publishTopicStart("system under test"); + out.println( reporter.getSuT()); + } + + @Override + protected void publishError() { + Error e = reporter.getCurrentError(); + + publishTopicStart("error " + e.getId()); + out.println(e.getDescription()); + + String s = e.getDetails(); + if (s != null) { + out.println(s); + } + + } + + @Override + protected void publishConstraint() { + String constraint = reporter.getLastSearchConstraint(); + publishTopicStart("search constraint"); + out.println(constraint); // not much info here yet + } + + @Override + protected void publishResult() { + List errors = reporter.getErrors(); + + publishTopicStart("results"); + + if (errors.isEmpty()) { + out.println("no errors detected"); + } else { + for (Error e : errors) { + out.print("error #"); + out.print(e.getId()); + out.print(": "); + out.print(e.getDescription()); + + String s = e.getDetails(); + if (s != null) { + s = s.replace('\n', ' '); + s = s.replace('\t', ' '); + s = s.replace('\r', ' '); + out.print(" \""); + if (s.length() > 50){ + out.print(s.substring(0,50)); + out.print("..."); + } else { + out.print(s); + } + out.print('"'); + } + + out.println(); + } + } + } + + /** + * this is done as part of the property violation reporting, i.e. + * we have an error + */ + @Override + protected void publishTrace() { + Path path = reporter.getPath(); + int i=0; + + if (path.size() == 0) { + return; // nothing to publish + } + + publishTopicStart("trace " + reporter.getCurrentErrorId()); + + for (Transition t : path) { + out.print("------------------------------------------------------ "); + out.println("transition #" + i++ + " thread: " + t.getThreadIndex()); + + if (showCG){ + out.println(t.getChoiceGenerator()); + } + + if (showSteps) { + String lastLine = null; + MethodInfo lastMi = null; + int nNoSrc=0; + + for (Step s : t) { + if (showSource) { + String line = s.getLineString(); + if (line != null) { + if (!line.equals(lastLine)) { + if (nNoSrc > 0){ + out.println(" [" + nNoSrc + " insn w/o sources]"); + } + + out.print(" "); + if (showLocation) { + out.print(Left.format(s.getLocationString(),30)); + out.print(" : "); + } + out.println(line.trim()); + nNoSrc = 0; + + } + } else { // no source + nNoSrc++; + } + + lastLine = line; + } + + if (showCode) { + Instruction insn = s.getInstruction(); + if (showMethod){ + MethodInfo mi = insn.getMethodInfo(); + if (mi != lastMi) { + ClassInfo mci = mi.getClassInfo(); + out.print(" "); + if (mci != null) { + out.print(mci.getName()); + out.print("."); + } + out.println(mi.getUniqueName()); + lastMi = mi; + } + } + out.print(" "); + out.println(insn); + } + } + + if (showSource && !showCode && (nNoSrc > 0)) { + out.println(" [" + nNoSrc + " insn w/o sources]"); + } + } + } + } + + @Override + protected void publishOutput() { + Path path = reporter.getPath(); + + if (path.size() == 0) { + return; // nothing to publish + } + + publishTopicStart("output " + reporter.getCurrentErrorId()); + + if (path.hasOutput()) { + for (Transition t : path) { + String s = t.getOutput(); + if (s != null){ + out.print(s); + } + } + } else { + out.println("no output"); + } + } + + @Override + protected void publishSnapshot() { + VM vm = reporter.getVM(); + + // not so nice - we have to delegate this since it's using a lot of internals, and is also + // used in debugging + publishTopicStart("snapshot " + reporter.getCurrentErrorId()); + + if (vm.getPathLength() > 0) { + vm.printLiveThreadStatus(out); + } else { + out.println("initial program state"); + } + } + + public static final String STATISTICS_TOPIC = "statistics"; + + // this is useful if somebody wants to monitor progress from a specialized ConsolePublisher + public synchronized void printStatistics (PrintWriter pw){ + publishTopicStart( STATISTICS_TOPIC); + printStatistics( pw, reporter); + } + + // this can be used outside a publisher, to show the same info + public static void printStatistics (PrintWriter pw, Reporter reporter){ + Statistics stat = reporter.getStatistics(); + + pw.println("elapsed time: " + formatHMS(reporter.getElapsedTime())); + pw.println("states: new=" + stat.newStates + ",visited=" + stat.visitedStates + + ",backtracked=" + stat.backtracked + ",end=" + stat.endStates); + pw.println("search: maxDepth=" + stat.maxDepth + ",constraints=" + stat.constraints); + pw.println("choice generators: thread=" + stat.threadCGs + + " (signal=" + stat.signalCGs + ",lock=" + stat.monitorCGs + ",sharedRef=" + stat.sharedAccessCGs + + ",threadApi=" + stat.threadApiCGs + ",reschedule=" + stat.breakTransitionCGs + + "), data=" + stat.dataCGs); + pw.println("heap: " + "new=" + stat.nNewObjects + + ",released=" + stat.nReleasedObjects + + ",maxLive=" + stat.maxLiveObjects + + ",gcCycles=" + stat.gcCycles); + pw.println("instructions: " + stat.insns); + pw.println("max memory: " + (stat.maxUsed >> 20) + "MB"); + + pw.println("loaded code: classes=" + ClassLoaderInfo.getNumberOfLoadedClasses() + ",methods=" + + MethodInfo.getNumberOfLoadedMethods()); + } + + @Override + public void publishStatistics() { + printStatistics(out); + } + +} diff --git a/src/main/gov/nasa/jpf/report/Publisher.java b/src/main/gov/nasa/jpf/report/Publisher.java new file mode 100644 index 0000000..3935bfc --- /dev/null +++ b/src/main/gov/nasa/jpf/report/Publisher.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.report; + +import gov.nasa.jpf.Config; + +import java.io.PrintWriter; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * abstract base for all format specific publishers. Note that this interface + * also has to work for non-stream based reporting, i.e. within Eclipse + * (we don't want to re-parse from text reports there) + */ +public abstract class Publisher { + + // output phases + public static final int START = 1; + public static final int TRANSITION = 2; + public static final int PROBE = 3; + public static final int CONSTRAINT = 4; + public static final int PROPERTY_VIOLATION = 5; + public static final int FINISHED = 6; + + protected Config conf; + protected Reporter reporter; // our master + + protected String[] startItems = {}; + protected String[] transitionItems = {}; + protected String[] propertyViolationItems = {}; + protected String[] constraintItems = {}; + protected String[] finishedItems = {}; + protected String[] probeItems = {}; + + DateFormat dtgFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, + DateFormat.SHORT); + + ArrayList extensions; + + /** + * to be initialized in openChannel + * NOTE - not all publishers need to have one + */ + protected PrintWriter out; + + public PrintWriter getOut () { + return out; + } + + protected Publisher (Config conf, Reporter reporter){ + this.conf = conf; + this.reporter = reporter; + + setTopicItems(); + } + + public void setItems (int category, String[] newTopics){ + switch (category){ + case START: + startItems = newTopics; break; + case PROBE: + probeItems = newTopics; break; + case TRANSITION: + transitionItems = newTopics; break; + case CONSTRAINT: + constraintItems = newTopics; break; + case PROPERTY_VIOLATION: + propertyViolationItems = newTopics; break; + case FINISHED: + finishedItems = newTopics; break; + default: + Reporter.log.warning("unknown publisher topic: " + category); + } + } + + public abstract String getName(); + + protected void setTopicItems () { + setTopicItems(getName()); + } + + protected void setTopicItems (String name) { + String prefix = "report." + name; + startItems = conf.getStringArray(prefix + ".start", startItems); + transitionItems = conf.getStringArray(prefix + ".transition", transitionItems); + probeItems = conf.getStringArray(prefix + ".probe", transitionItems); + propertyViolationItems = conf.getStringArray(prefix + ".property_violation", propertyViolationItems); + constraintItems = conf.getStringArray(prefix + ".constraint", constraintItems); + finishedItems = conf.getStringArray(prefix + ".finished", finishedItems); + } + + public void addExtension (PublisherExtension ext) { + if (extensions == null) { + extensions = new ArrayList(); + } + extensions.add(ext); + } + + // <2do> should not be a list we can add to + private static final List EMPTY_LIST = new ArrayList(0); + + public List getExtensions(){ + if (extensions != null){ + return extensions; + } else { + return EMPTY_LIST; // make life easier for callers + } + } + + public String getLastErrorId() { + return reporter.getCurrentErrorId(); + } + + public boolean hasTopic (String topic) { + for (String s : startItems) { + if (s.equalsIgnoreCase(topic)){ + return true; + } + } + for (String s : transitionItems) { + if (s.equalsIgnoreCase(topic)){ + return true; + } + } + for (String s : constraintItems) { + if (s.equalsIgnoreCase(topic)){ + return true; + } + } + for (String s : propertyViolationItems) { + if (s.equalsIgnoreCase(topic)){ + return true; + } + } + for (String s : finishedItems) { + if (s.equalsIgnoreCase(topic)){ + return true; + } + } + + return false; + } + + public String formatDTG (Date date) { + return dtgFormatter.format(date); + } + + /** + static public String _formatHMS (long t) { + t /= 1000; // convert to sec + + long s = t % 60; + long h = t / 3600; + long m = (t % 3600) / 60; + + StringBuilder sb = new StringBuilder(); + sb.append(h); + sb.append(':'); + if (m < 10){ + sb.append('0'); + } + sb.append(m); + sb.append(':'); + if (s < 10){ + sb.append('0'); + } + sb.append(s); + + return sb.toString(); + } + **/ + + static char[] tBuf = { '0', '0', ':', '0', '0', ':', '0', '0' }; + + static synchronized public String formatHMS (long t) { + int h = (int) (t / 3600000); + int m = (int) ((t / 60000) % 60); + int s = (int) ((t / 1000) % 60); + + tBuf[0] = (char) ('0' + (h / 10)); + tBuf[1] = (char) ('0' + (h % 10)); + + tBuf[3] = (char) ('0' + (m / 10)); + tBuf[4] = (char) ('0' + (m % 10)); + + tBuf[6] = (char) ('0' + (s / 10)); + tBuf[7] = (char) ('0' + (s % 10)); + + return new String(tBuf); + } + + public String getReportFileName (String key) { + String fname = conf.getString(key); + if (fname == null){ + fname = conf.getString("report.file"); + if (fname == null) { + fname = "report"; + } + } + + return fname; + } + + public void publishTopicStart (String topic) { + // to be done by subclasses + } + + public void publishTopicEnd (String topic) { + // to be done by subclasses + } + + public boolean hasToReportStatistics() { + for (String s : finishedItems) { + if ("statistics".equalsIgnoreCase(s)){ + return true; + } + } + return false; + } + + //--- open/close streams etc + protected void openChannel(){} + protected void closeChannel(){} + + //--- if you have different preferences about when to report things, override those + public void publishStart() { + for (String item : startItems) { + if ("jpf".equalsIgnoreCase(item)){ + publishJPF(); + } else if ("platform".equalsIgnoreCase(item)){ + publishPlatform(); + } else if ("user".equalsIgnoreCase(item)) { + } else if ("dtg".equalsIgnoreCase(item)) { + publishDTG(); + } else if ("config".equalsIgnoreCase(item)){ + publishJPFConfig(); + } else if ("sut".equalsIgnoreCase(item)){ + publishSuT(); + } + } + + if (extensions != null) { + for (PublisherExtension e : extensions) { + e.publishStart(this); + } + } + } + + public void publishTransition() { + for (String topic : transitionItems) { + if ("statistics".equalsIgnoreCase(topic)){ + publishStatistics(); + } + } + + if (extensions != null) { + for (PublisherExtension e : extensions) { + e.publishTransition(this); + } + } + } + + public void publishConstraintHit() { + for (String item : constraintItems) { + if ("constraint".equalsIgnoreCase(item)) { + publishConstraint(); + } else if ("trace".equalsIgnoreCase(item)){ + publishTrace(); + } else if ("snapshot".equalsIgnoreCase(item)){ + publishSnapshot(); + } else if ("output".equalsIgnoreCase(item)){ + publishOutput(); + } else if ("statistics".equalsIgnoreCase(item)){ + publishStatistics(); // not sure if that is good for anything + } + } + + if (extensions != null) { + for (PublisherExtension e : extensions) { + e.publishConstraintHit(this); + } + } + } + + public void publishProbe(){ + for (String topic : probeItems) { + if ("statistics".equalsIgnoreCase(topic)){ + publishStatistics(); + } + } + + if (extensions != null) { + for (PublisherExtension e : extensions) { + e.publishProbe(this); + } + } + } + + public void publishPropertyViolation() { + + for (String topic : propertyViolationItems) { + if ("error".equalsIgnoreCase(topic)) { + publishError(); + } else if ("trace".equalsIgnoreCase(topic)){ + publishTrace(); + } else if ("snapshot".equalsIgnoreCase(topic)){ + publishSnapshot(); + } else if ("output".equalsIgnoreCase(topic)){ + publishOutput(); + } else if ("statistics".equalsIgnoreCase(topic)){ + publishStatistics(); // not sure if that is good for anything + } + } + + if (extensions != null) { + for (PublisherExtension e : extensions) { + e.publishPropertyViolation(this); + } + } + + } + + public void publishFinished() { + if (extensions != null) { + for (PublisherExtension e : extensions) { + e.publishFinished(this); + } + } + + for (String topic : finishedItems) { + if ("result".equalsIgnoreCase(topic)){ + publishResult(); + } else if ("statistics".equalsIgnoreCase(topic)){ + publishStatistics(); + } + } + } + + protected void publishProlog() {} // XML headers etc + protected void publishEpilog() {} // likewise at the end + + //--- our standard topics (only placeholders here) + protected void publishJPF() {} + protected void publishJPFConfig() {} + protected void publishPlatform() {} + protected void publishUser() {} + protected void publishDTG() {} + protected void publishJava() {} + protected void publishSuT() {} + protected void publishResult() {} + protected void publishError() {} + protected void publishConstraint() {} + protected void publishTrace() {} + protected void publishOutput() {} + protected void publishSnapshot() {} + protected void publishStatistics() {} + + //--- internal helpers +} diff --git a/src/main/gov/nasa/jpf/report/PublisherExtension.java b/src/main/gov/nasa/jpf/report/PublisherExtension.java new file mode 100644 index 0000000..41dc7bb --- /dev/null +++ b/src/main/gov/nasa/jpf/report/PublisherExtension.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.report; + +/** + * used to add sections to publishers + */ +public interface PublisherExtension { + + void publishStart (Publisher publisher); + void publishTransition (Publisher publisher); + void publishPropertyViolation (Publisher publisher); + void publishConstraintHit (Publisher publisher); + void publishFinished (Publisher publisher); + void publishProbe (Publisher publisher); +} diff --git a/src/main/gov/nasa/jpf/report/PublisherExtensionAdapter.java b/src/main/gov/nasa/jpf/report/PublisherExtensionAdapter.java new file mode 100644 index 0000000..3950e92 --- /dev/null +++ b/src/main/gov/nasa/jpf/report/PublisherExtensionAdapter.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.report; + +/** + * this is just a little helper class to ease standalone PublisherExtension implementations + */ +public class PublisherExtensionAdapter implements PublisherExtension { + + @Override + public void publishConstraintHit(Publisher publisher) {} + + @Override + public void publishFinished(Publisher publisher) {} + + @Override + public void publishPropertyViolation(Publisher publisher) {} + + @Override + public void publishStart(Publisher publisher) {} + + @Override + public void publishTransition(Publisher publisher) {} + + @Override + public void publishProbe(Publisher publisher) {} + +} diff --git a/src/main/gov/nasa/jpf/report/Reporter.java b/src/main/gov/nasa/jpf/report/Reporter.java new file mode 100644 index 0000000..209cbd9 --- /dev/null +++ b/src/main/gov/nasa/jpf/report/Reporter.java @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.report; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.Error; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.JPFListener; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.search.SearchListenerAdapter; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Path; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.logging.Logger; + +/** + * this is our default report generator, which is heavily configurable + * via our standard properties. Note this gets instantiated and + * registered automatically via JPF.addListeners(), so you don't + * have to add it explicitly + */ + +public class Reporter extends SearchListenerAdapter { + + public static Logger log = JPF.getLogger("report"); + + protected Config conf; + protected JPF jpf; + protected Search search; + protected VM vm; + + protected Date started, finished; + protected Statistics stat; // the object that collects statistics + protected List publishers = new ArrayList(); + + protected Thread probeTimer; + + public Reporter (Config conf, JPF jpf) { + this.conf = conf; + this.jpf = jpf; + search = jpf.getSearch(); + vm = jpf.getVM(); + int probeInterval = conf.getInt("report.probe_interval"); + boolean reportStats = conf.getBoolean("report.statistics", false) || (probeInterval > 0); + + started = new Date(); + + addConfiguredPublishers(conf); + + for (Publisher publisher : publishers) { + if (reportStats || publisher.hasToReportStatistics()) { + reportStats = true; + } + + if (publisher instanceof JPFListener) { + jpf.addListener((JPFListener)publisher); + } + } + + if (reportStats){ + getRegisteredStatistics(); + } + + if (probeInterval > 0){ + probeTimer = createProbeIntervalTimer(probeInterval); + } + } + + protected Thread createProbeIntervalTimer (final int probeInterval){ + Thread timer = new Thread( new Runnable(){ + @Override + public void run(){ + log.info("probe timer running"); + while (!search.isDone()){ + try { + Thread.sleep( probeInterval * 1000); + search.probeSearch(); // this is only a request + } catch (InterruptedException ix) { + // nothing + } + } + log.info("probe timer terminating"); + } + }, "probe-timer"); + timer.setDaemon(true); + + // we don't start before the Search is started + + return timer; + } + + /** + * called after the JPF run is finished. Shouldn't be public, but is called by JPF + */ + public void cleanUp(){ + // nothing yet + } + + public Statistics getRegisteredStatistics(){ + + if (stat == null){ // none yet, initialize + // first, check if somebody registered one explicitly + stat = vm.getNextListenerOfType(Statistics.class, null); + if (stat == null){ + stat = conf.getInstance("report.statistics.class@stat", Statistics.class); + if (stat == null) { + stat = new Statistics(); + } + jpf.addListener(stat); + } + } + + return stat; + } + + + void addConfiguredPublishers (Config conf) { + String[] def = { "console" }; + + Class[] argTypes = { Config.class, Reporter.class }; + Object[] args = { conf, this }; + + for (String id : conf.getStringArray("report.publisher", def)){ + Publisher p = conf.getInstance("report." + id + ".class", + Publisher.class, argTypes, args); + if (p != null){ + publishers.add(p); + } else { + log.warning("could not instantiate publisher class: " + id); + } + } + } + + public void addPublisher( Publisher newPublisher){ + publishers.add(newPublisher); + } + + public List getPublishers() { + return publishers; + } + + public boolean hasToReportTrace() { + for (Publisher p : publishers) { + if (p.hasTopic("trace")) { + return true; + } + } + + return false; + } + + public boolean hasToReportOutput() { + for (Publisher p : publishers) { + if (p.hasTopic("output")) { + return true; + } + } + + return false; + } + + + public boolean addPublisherExtension (Class publisherCls, PublisherExtension e) { + boolean added = false; + for (Publisher p : publishers) { + Class pCls = p.getClass(); + if (publisherCls.isAssignableFrom(pCls)) { + p.addExtension(e); + added = true; + } + } + + return added; + } + + public void setPublisherItems (Class publisherCls, + int category, String[] topics){ + for (Publisher p : publishers) { + if (publisherCls.isInstance(p)) { + p.setItems(category,topics); + return; + } + } + } + + boolean contains (String key, String[] list) { + for (String s : list) { + if (s.equalsIgnoreCase(key)){ + return true; + } + } + return false; + } + + + //--- the publishing phases + + protected void publishStart() { + for (Publisher publisher : publishers) { + publisher.openChannel(); + publisher.publishProlog(); + publisher.publishStart(); + } + } + + protected void publishTransition() { + for (Publisher publisher : publishers) { + publisher.publishTransition(); + } + } + + protected void publishPropertyViolation() { + for (Publisher publisher : publishers) { + publisher.publishPropertyViolation(); + } + } + + protected void publishConstraintHit() { + for (Publisher publisher : publishers) { + publisher.publishConstraintHit(); + } + } + + protected void publishFinished() { + for (Publisher publisher : publishers) { + publisher.publishFinished(); + publisher.publishEpilog(); + publisher.closeChannel(); + } + } + + protected void publishProbe(){ + for (Publisher publisher : publishers) { + publisher.publishProbe(); + } + } + + //--- the listener interface that drives report generation + + @Override + public void searchStarted (Search search){ + publishStart(); + + if (probeTimer != null){ + probeTimer.start(); + } + } + + @Override + public void stateAdvanced (Search search) { + publishTransition(); + } + + @Override + public void searchConstraintHit(Search search) { + publishConstraintHit(); + } + + @Override + public void searchProbed (Search search){ + publishProbe(); + } + + @Override + public void propertyViolated (Search search) { + publishPropertyViolation(); + } + + @Override + public void searchFinished (Search search){ + finished = new Date(); + + publishFinished(); + + if (probeTimer != null){ + // we could interrupt, but it's a daemon anyways + probeTimer = null; + } + } + + + //--- various getters + + public Date getStartDate() { + return started; + } + + public Date getFinishedDate () { + return finished; + } + + public VM getVM() { + return vm; + } + + public Search getSearch() { + return search; + } + + public List getErrors () { + return search.getErrors(); + } + + public Error getCurrentError () { + return search.getCurrentError(); + } + + public String getLastSearchConstraint () { + return search.getLastSearchConstraint(); + } + + public String getCurrentErrorId () { + Error e = getCurrentError(); + if (e != null) { + return "#" + e.getId(); + } else { + return ""; + } + } + + public int getNumberOfErrors() { + return search.getErrors().size(); + } + + public Statistics getStatistics() { + return stat; + } + + public Statistics getStatisticsSnapshot () { + return stat.clone(); + } + + /** + * in ms + */ + public long getElapsedTime () { + Date d = (finished != null) ? finished : new Date(); + long t = d.getTime() - started.getTime(); + return t; + } + + public Path getPath (){ + return vm.getClonedPath(); + } + + public String getJPFBanner () { + StringBuilder sb = new StringBuilder(); + + sb.append("JavaPathfinder core system v"); + sb.append(JPF.VERSION); + + String rev = getRevision(); + if (rev != null){ + sb.append(" (rev "); + sb.append(rev); + sb.append(')'); + } + + sb.append(" - (C) 2005-2014 United States Government. All rights reserved."); + + if (conf.getBoolean("report.show_repository", false)) { + String repInfo = getRepositoryInfo(); + if (repInfo != null) { + sb.append( repInfo); + } + } + + return sb.toString(); + } + + + protected String getRevision() { + try { + InputStream is = JPF.class.getResourceAsStream(".version"); + if (is != null){ + int len = is.available(); + byte[] data = new byte[len]; + is.read(data); + is.close(); + return new String(data).trim(); + + } else { + return null; + } + + } catch (Throwable t){ + return null; + } + } + + protected String getRepositoryInfo() { + try { + InputStream is = JPF.class.getResourceAsStream("build.properties"); + if (is != null){ + Properties revInfo = new Properties(); + revInfo.load(is); + + StringBuffer sb = new StringBuffer(); + String date = revInfo.getProperty("date"); + String author = revInfo.getProperty("author"); + String rev = revInfo.getProperty("rev"); + String machine = revInfo.getProperty("hostname"); + String loc = revInfo.getProperty("location"); + String upstream = revInfo.getProperty("upstream"); + + return String.format("%s %s %s %s %s", date,author,rev,machine,loc); + } + } catch (IOException iox) { + return null; + } + + return null; + } + + + public String getHostName () { + try { + InetAddress in = InetAddress.getLocalHost(); + String hostName = in.getHostName(); + return hostName; + } catch (Throwable t) { + return "localhost"; + } + } + + public String getUser() { + return System.getProperty("user.name"); + } + + public String getSuT() { + return vm.getSUTDescription(); + } + + public String getJava (){ + String vendor = System.getProperty("java.vendor"); + String version = System.getProperty("java.version"); + return vendor + "/" + version; + } + + public String getArch () { + String arch = System.getProperty("os.arch"); + Runtime rt = Runtime.getRuntime(); + String type = arch + "/" + rt.availableProcessors(); + + return type; + } + + public String getOS () { + String name = System.getProperty("os.name"); + String version = System.getProperty("os.version"); + return name + "/" + version; + } + +} diff --git a/src/main/gov/nasa/jpf/report/Statistics.java b/src/main/gov/nasa/jpf/report/Statistics.java new file mode 100644 index 0000000..152189c --- /dev/null +++ b/src/main/gov/nasa/jpf/report/Statistics.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.report; + +import gov.nasa.jpf.ListenerAdapter; +import gov.nasa.jpf.jvm.bytecode.EXECUTENATIVE; +import gov.nasa.jpf.jvm.bytecode.JVMFieldInstruction; +import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; +import gov.nasa.jpf.jvm.bytecode.LockInstruction; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ClassInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.Instruction; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.MethodInfo; +import gov.nasa.jpf.vm.ThreadChoiceGenerator; + +/** + * simple structure to hold statistics info created by Reporters/Publishers + * this is kind of a second tier SearchListener, which does not + * explicitly have to be registered + * + * <2do> this should get generic and accessible enough to replace all the + * other statistics collectors, otherwise there is too much redundancy. + * If users have special requirements, they should subclass Statistics + * and set jpf.report.statistics.class accordingly + * + * Note that Statistics might be accessed by a background thread + * reporting JPF progress, hence we have to synchronize + */ +public class Statistics extends ListenerAdapter implements Cloneable { + + // we make these public since we don't want to add a gazillion of + // getters for these purely informal numbers + + public long maxUsed = 0; + public long newStates = 0; + public long backtracked = 0; + public long restored = 0; + public int processed = 0; + public int constraints = 0; + public long visitedStates = 0; + public long endStates = 0; + public int maxDepth = 0; + + public int gcCycles = 0; + public long insns = 0; + public int threadCGs = 0; + public int sharedAccessCGs = 0; + public int monitorCGs = 0; + public int signalCGs = 0; + public int threadApiCGs = 0; + public int breakTransitionCGs = 0; + public int dataCGs = 0; + public long nNewObjects = 0; + public long nReleasedObjects = 0; + public int maxLiveObjects = 0; + + @Override + public Statistics clone() { + try { + return (Statistics)super.clone(); + } catch (CloneNotSupportedException e) { + return null; // can't happen + } + } + + @Override + public void gcBegin (VM vm) { + int heapSize = vm.getHeap().size(); + if (heapSize > maxLiveObjects){ + maxLiveObjects = heapSize; + } + + gcCycles++; + } + + @Override + public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){ + insns++; + } + + @Override + public void choiceGeneratorSet (VM vm, ChoiceGenerator newCG){ + ChoiceGenerator cg = VM.getVM().getChoiceGenerator(); + if (cg instanceof ThreadChoiceGenerator){ + threadCGs++; + + Instruction insn = cg.getInsn(); + if (insn instanceof JVMFieldInstruction) { + sharedAccessCGs++; + } else if (insn instanceof LockInstruction || insn instanceof JVMInvokeInstruction) { + monitorCGs++; + } else if (insn instanceof EXECUTENATIVE) { + MethodInfo mi = insn.getMethodInfo(); + if (mi != null) { + ClassInfo ci = mi.getClassInfo(); + if (ci != null) { + if (ci.isObjectClassInfo()) { + // its got to be either a wait or a notify since we know the java.lang.Object methods + signalCGs++; + } else if (ci.isThreadClassInfo()) { + threadApiCGs++; + } + } else { + // Hmm - a CG from a synthetic method? + } + } else { + // even more Hmmm - a GC from a synthesized instruction + } + } else { + breakTransitionCGs++; // e.g. max_transition_length or idleLoop breakers + } + } else { + dataCGs++; + } + } + + @Override + public void objectCreated (VM vm, ThreadInfo ti, ElementInfo ei){ + nNewObjects++; + } + + @Override + public void objectReleased (VM vm, ThreadInfo ti, ElementInfo ei){ + nReleasedObjects++; + } + + @Override + public void stateAdvanced (Search search){ + long m = Runtime.getRuntime().totalMemory(); + if (m > maxUsed) { + maxUsed = m; + } + + if (search.isNewState()){ + newStates++; + int depth = search.getDepth(); + if (depth > maxDepth){ + maxDepth = depth; + } + } else { + visitedStates++; + } + if (search.isEndState()){ + endStates++; + } + } + + @Override + public void stateBacktracked (Search search){ + backtracked++; + } + + @Override + public void stateProcessed (Search search){ + processed++; + } + + @Override + public void stateRestored (Search search){ + restored++; + } + + @Override + public void searchConstraintHit (Search search){ + constraints++; + } + +} diff --git a/src/main/gov/nasa/jpf/report/XMLPublisher.java b/src/main/gov/nasa/jpf/report/XMLPublisher.java new file mode 100644 index 0000000..ce7999f --- /dev/null +++ b/src/main/gov/nasa/jpf/report/XMLPublisher.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.report; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.Error; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.util.RepositoryEntry; +import gov.nasa.jpf.vm.ChoiceGenerator; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Path; +import gov.nasa.jpf.vm.StackFrame; +import gov.nasa.jpf.vm.Step; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.Transition; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +public class XMLPublisher extends Publisher { + + public XMLPublisher(Config conf, Reporter reporter) { + super(conf, reporter); + } + + @Override + public String getName() { + return "xml"; + } + + @Override + protected void openChannel(){ + if (out == null) { + String fname = getReportFileName("report.xml.file") + ".xml"; + try { + out = new PrintWriter(fname); + } catch (FileNotFoundException fnfx) { + // log here + } + } + } + + @Override + protected void closeChannel() { + if (out != null){ + out.close(); + out = null; + } + } + + + @Override + protected void publishProlog() { + out.println(""); + out.println(""); + } + + @Override + public void publishTopicStart(String topic) { + out.println(" <" + topic + ">"); + } + + @Override + public void publishTopicEnd(String topic) { + out.println(" "); + } + + @Override + protected void publishEpilog() { + out.println(""); + } + + @Override + protected void publishJPF() { + out.println(" " + JPF.VERSION + ""); + } + + @Override + protected void publishJPFConfig() { + TreeMap map = conf.asOrderedMap(); + Set> eSet = map.entrySet(); + + out.println(" "); + + for (Object src : conf.getSources()){ + out.println(" "); + } + + for (Map.Entry e : eSet) { + out.println(" "); + } + out.println(" "); + + } + + @Override + protected void publishPlatform() { + out.println(" "); + out.println(" " + reporter.getHostName() + ""); + out.println(" " + reporter.getArch() + ""); + out.println(" " + reporter.getOS() + ""); + out.println(" " + reporter.getJava() + ""); + out.println(" "); + } + + @Override + protected void publishUser() { + out.println(" " + reporter.getUser() + ""); + } + + @Override + protected void publishDTG() { + out.println(" " + reporter.getStartDate() + ""); + } + + @Override + protected void publishSuT() { + out.println(" "); + String mainCls = reporter.getSuT(); + if (mainCls != null) { + String mainPath = reporter.getSuT(); + if (mainPath != null) { + out.println(" " + mainPath + ""); + + RepositoryEntry rep = RepositoryEntry.getRepositoryEntry(mainPath); + if (rep != null) { + out.println(" " + rep.getRepository() + ""); + out.println(" " + rep.getRevision() + ""); + } + } else { + out.println(" " + mainCls + ".class" + ""); + } + } else { + // no app specified + } + out.println(" "); + } + + @Override + protected void publishResult() { + List errors = reporter.getErrors(); + + out.print(" "); + } else { + out.println("errors\">"); + int i=0; + for (Error e : errors) { + out.print(" "); + out.print(" "); + out.print(e.getProperty().getClass().getName()); + out.println(""); + out.print("
"); + out.print(e.getDetails()); + out.println("
"); + out.println("
"); + } + out.println("
"); + } + } + + // not sure how much effort we want to put into readability here + @Override + protected void publishTrace() { + Path path = reporter.getPath(); + int i=0; + + if (path.size() == 0) { + return; // nothing to publish + } + + out.println(" "); + for (Transition t : path) { + ChoiceGenerator cg = t.getChoiceGenerator(); + out.println(" "); + out.println(" "); + for (Step s : t) { + out.print(" "); + String insn = s.getInstruction().toString(); + if (insn.indexOf('<') >= 0) { // and clash with XML + insn = insn.replaceAll("<", "<"); + insn = insn.replaceAll(">", ">"); + } + out.print(insn); + out.println(""); + } + out.println(" "); + } + out.println(" "); + } + + @Override + protected void publishOutput() { + Path path = reporter.getPath(); + + if (path.size() == 0) { + return; // nothing to publish + } + + if (path.hasOutput()) { + out.println(" "); + for (Transition t : path) { + String s = t.getOutput(); + if (s != null){ + out.print(s); + } + } + out.println(" "); + } + } + + @Override + protected void publishSnapshot() { + VM vm = reporter.getVM(); + + out.println(" "); + for (ThreadInfo ti : vm.getLiveThreads()) { + out.println(" "); + // owned locks + for (ElementInfo e : ti.getLockedObjects()) { + out.println(" "); + } + // requested locks + ElementInfo ei = ti.getLockObject(); + if (ei != null) { + out.println(" "); + } + // stack frames + for (StackFrame frame : ti){ + if (!frame.isDirectCallFrame()){ + out.println(" " + frame.getStackTraceInfo() + ""); + } + } + out.println(" "); + } + out.println(" "); + } + + @Override + protected void publishStatistics() { + Statistics stat = reporter.getStatistics(); + out.println(" "); + out.println(" " + formatHMS(reporter.getElapsedTime()) + ""); + out.println(" " + stat.newStates + ""); + out.println(" " + stat.visitedStates + ""); + out.println(" " + stat.backtracked + ""); + out.println(" " + stat.endStates + ""); + out.println(" " + (stat.maxUsed >>20) + ""); + out.println(" "); + } + +} diff --git a/src/main/gov/nasa/jpf/search/DFSearch.java b/src/main/gov/nasa/jpf/search/DFSearch.java new file mode 100644 index 0000000..8e6658f --- /dev/null +++ b/src/main/gov/nasa/jpf/search/DFSearch.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + + +/** + * standard depth first model checking (but can be bounded by search depth + * and/or explicit Verify.ignoreIf) + */ +public class DFSearch extends Search { + + public DFSearch (Config config, VM vm) { + super(config,vm); + } + + @Override + public boolean requestBacktrack () { + doBacktrack = true; + + return true; + } + + /** + * state model of the search + * next new -> action + * T T forward + * T F backtrack, forward + * F T backtrack, forward + * F F backtrack, forward + * + * end condition + * backtrack failed (no saved states) + * | property violation (currently only checked in new states) + * | search constraint (depth or memory or time) + * + * <2do> we could split the properties into forward and backtrack properties, + * the latter ones being usable for liveness properties that are basically + * condition accumulators for sub-paths of the state space, to be checked when + * we backtrack to the state where they were introduced. + */ + @Override + public void search () { + boolean depthLimitReached = false; + + depth = 0; + + notifySearchStarted(); + + while (!done) { + if (checkAndResetBacktrackRequest() || !isNewState() || isEndState() || isIgnoredState() || depthLimitReached ) { + if (!backtrack()) { // backtrack not possible, done + break; + } + + depthLimitReached = false; + depth--; + notifyStateBacktracked(); + } + + if (forward()) { + depth++; + notifyStateAdvanced(); + + if (currentError != null){ + notifyPropertyViolated(); + + if (hasPropertyTermination()) { + break; + } + // for search.multiple_errors we go on and treat this as a new state + // but hasPropertyTermination() will issue a backtrack request + } + + if (depth >= depthLimit) { + depthLimitReached = true; + notifySearchConstraintHit("depth limit reached: " + depthLimit); + continue; + } + + if (!checkStateSpaceLimit()) { + notifySearchConstraintHit("memory limit reached: " + minFreeMemory); + // can't go on, we exhausted our memory + break; + } + + } else { // forward did not execute any instructions + notifyStateProcessed(); + } + } + + notifySearchFinished(); + } + + + @Override + public boolean supportsBacktrack () { + return true; + } +} diff --git a/src/main/gov/nasa/jpf/search/PathSearch.java b/src/main/gov/nasa/jpf/search/PathSearch.java new file mode 100644 index 0000000..8437582 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/PathSearch.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + + +/** + * PathSearch is not really a Search object, just a simple 'forward' + * driver for the VM that loops until there is no next instruction or + * a property doesn't hold + * + */ +public class PathSearch extends Search { + + public PathSearch (Config config, VM vm) { + super(config,vm); + } + + @Override + public boolean requestBacktrack () { + doBacktrack = true; + + return true; + } + + @Override + public void search () { + depth++; + + if (hasPropertyTermination()) { + return; + } + + notifySearchStarted(); + + while (true) { + while (doBacktrack) { // might be set by StateListeners + + if (depth > 0) { + vm.backtrack(); + depth--; + + notifyStateBacktracked(); + } + + doBacktrack = false; + } + + forward(); + // isVisitedState is never true, because we don't really search, just replay + notifyStateAdvanced(); + + if (currentError != null){ + notifyPropertyViolated(); + + if (hasPropertyTermination()) { + break; + } + } + + if (isEndState()) { + break; + } + + depth++; + } + + notifySearchFinished(); + } + + @Override + public boolean supportsBacktrack () { + return true; + } +} diff --git a/src/main/gov/nasa/jpf/search/RandomSearch.java b/src/main/gov/nasa/jpf/search/RandomSearch.java new file mode 100644 index 0000000..e9e79e8 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/RandomSearch.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.RestorableVMState; + + +/** + * this is a straight execution pseudo-search - it doesn't search at + * all (i.e. it doesn't backtrack), but just behaves like a 'normal' VM, + * going forward() until there is no next state then it restarts the search + * until it hits a certain number of paths executed + * + * <2do> this needs to be updated & tested + */ +public class RandomSearch extends Search { + int path_limit = 0; + + public RandomSearch (Config config, VM vm) { + super(config, vm); + + path_limit = config.getInt("search.RandomSearch.path_limit", 0); + } + + @Override + public void search () { + int depth = 0; + int paths = 0; + depth++; + + if (hasPropertyTermination()) { + return; + } + + //vm.forward(); + RestorableVMState init_state = vm.getRestorableState(); + + notifySearchStarted(); + while (!done) { + if ((depth < depthLimit) && forward()) { + notifyStateAdvanced(); + + if (currentError != null){ + notifyPropertyViolated(); + + if (hasPropertyTermination()) { + return; + } + } + + if (isEndState()){ + return; + } + + depth++; + + } else { // no next state or reached depth limit + // <2do> we could check for more things here. If the last insn wasn't + // the main return, or a System.exit() call, we could flag a JPFException + if (depth >= depthLimit) { + notifySearchConstraintHit("depth limit reached: " + depthLimit); + } + checkPropertyViolation(); + done = (paths >= path_limit); + paths++; + System.out.println("paths = " + paths); + depth = 1; + vm.restoreState(init_state); + vm.resetNextCG(); + } + } + notifySearchFinished(); + } +} diff --git a/src/main/gov/nasa/jpf/search/Search.java b/src/main/gov/nasa/jpf/search/Search.java new file mode 100644 index 0000000..e447741 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/Search.java @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.ConfigChangeListener; +import gov.nasa.jpf.Error; +import gov.nasa.jpf.JPF; +import gov.nasa.jpf.JPFException; +import gov.nasa.jpf.JPFListenerException; +import gov.nasa.jpf.Property; +import gov.nasa.jpf.State; +import gov.nasa.jpf.report.Reporter; +import gov.nasa.jpf.util.IntVector; +import gov.nasa.jpf.util.JPFLogger; +import gov.nasa.jpf.util.Misc; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Path; +import gov.nasa.jpf.vm.ThreadList; +import gov.nasa.jpf.vm.Transition; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * the mother of all search classes. Mostly takes care of listeners, keeping + * track of state attributes and errors. This class mainly keeps the + * general search info like depth, configured properties etc. + */ +public abstract class Search { + + protected static JPFLogger log = JPF.getLogger("gov.nasa.jpf.search"); + + /** error encountered during last transition, null otherwise */ + protected Error currentError = null; + protected ArrayList errors = new ArrayList(); + + protected int depth = 0; + protected VM vm; + + protected ArrayList properties; + + protected boolean matchDepth; + protected long minFreeMemory; + protected int depthLimit; + protected boolean getAllErrors; + + // message explaining the last search constraint hit + protected String lastSearchConstraint; + + // these states control the search loop + protected boolean done = false; + protected boolean doBacktrack = false; + + // do we have a probe request + protected AtomicBoolean notifyProbeListeners = new AtomicBoolean(false); + + /** search listeners. We keep them in a simple array to avoid + creating objects on each notification */ + protected SearchListener[] listeners = new SearchListener[0]; + + /** this is a special SearchListener that is always notified last, so that + * PublisherExtensions can be sure the notification has been processed by all listeners */ + protected Reporter reporter; + + protected final Config config; // to later-on access settings that are only used once (not ideal) + + // don't forget to unregister or we have a HUGE memory leak if the same Config object is + // reused for several JPF runs + class ConfigListener implements ConfigChangeListener { + + @Override + public void propertyChanged(Config config, String key, String oldValue, String newValue) { + // Different Config instance + if (!config.equals(Search.this.config)) { + return; + } + + // Check if Search configuration changed + if (key.startsWith("search.")){ + String k = key.substring(7); + if ("match_depth".equals(k) || + "min_free".equals(k) || + "multiple_errors".equals(k)){ + initialize(config); + } + } + } + + @Override + public void jpfRunTerminated (Config config){ + config.removeChangeListener(this); + } + } + + /** storage to keep track of state depths */ + protected final IntVector stateDepth = new IntVector(); + + protected Search (Config config, VM vm) { + this.vm = vm; + this.config = config; + + initialize( config); + + properties = getProperties(config); + if (properties.isEmpty()) { + log.severe("no property"); + } + + config.addChangeListener( new ConfigListener()); + } + + protected void initialize( Config conf){ + depthLimit = conf.getInt("search.depth_limit", Integer.MAX_VALUE); + matchDepth = conf.getBoolean("search.match_depth"); + minFreeMemory = conf.getMemorySize("search.min_free", 1024<<10); + getAllErrors = conf.getBoolean("search.multiple_errors"); + } + + /** + * called after the JPF run is finished. Shouldn't be public, but is called by JPF + */ + public void cleanUp(){ + // nothing here, the ConfigListener removes itself + } + + public Config getConfig() { + return config; + } + + public abstract void search (); + + public void setReporter(Reporter reporter){ + this.reporter = reporter; + } + + public void addListener (SearchListener newListener) { + log.info("SearchListener added: ", newListener); + listeners = Misc.appendElement(listeners, newListener); + } + + public boolean hasListenerOfType (Class listenerCls) { + return Misc.hasElementOfType(listeners, listenerCls); + } + + public T getNextListenerOfType(Class type, T prev){ + return Misc.getNextElementOfType(listeners, type, prev); + } + + + public void removeListener (SearchListener removeListener) { + listeners = Misc.removeElement(listeners, removeListener); + } + + + public void addProperty (Property newProperty) { + properties.add(newProperty); + } + + public void removeProperty (Property oldProperty) { + properties.remove(oldProperty); + } + + /** + * return set of configured properties + * note there is a name clash here - JPF 'properties' have nothing to do with + * Java properties (java.util.Properties) + */ + protected ArrayList getProperties (Config config) { + Class[] argTypes = { Config.class, Search.class }; + Object[] args = { config, this }; + + ArrayList list = config.getInstances("search.properties", Property.class, + argTypes, args); + + return list; + } + + // check for property violation, return true if not done + protected boolean hasPropertyTermination () { + if (currentError != null){ + if (done){ + return true; + } else { // we search for multiple errors, so we ignore and go on + doBacktrack = true; + } + } + + return false; + } + + // this should only be called once per transition, otherwise it keeps adding the same error + protected boolean checkPropertyViolation () { + for (Property p : properties) { + if (!p.check(this, vm)) { + error(p, vm.getClonedPath(), vm.getThreadList()); + return true; + } + } + + return false; + } + + public List getErrors () { + return errors; + } + + public int getNumberOfErrors(){ + return errors.size(); + } + + public String getLastSearchConstraint() { + return lastSearchConstraint; + } + + /** + * request a probe + * + * This does not do the actual listener notification, it only stores + * the request, which is then processed from within JPFs inner execution loop. + * As a consequence, probeSearch() can be called async, and searchProbed() listeners + * don't have to bother with synchronization or inconsistent JPF states (notification + * happens from within JPFs main thread after a completed Instruction execution) + */ + public void probeSearch(){ + notifyProbeListeners.set(true); + } + + /** + * this does the actual notification and resets the request, hence this call + * should only happen from within JPFs main thread + */ + public void checkAndResetProbeRequest(){ + if (notifyProbeListeners.compareAndSet(true, false)){ + notifySearchProbed(); + } + } + + /** + * @return error encountered during *last* transition (null otherwise) + */ + public Error getCurrentError(){ + return currentError; + } + + public Error getLastError() { + int i=errors.size()-1; + if (i >=0) { + return errors.get(i); + } else { + return null; + } + } + + public boolean hasErrors(){ + return !errors.isEmpty(); + } + + public VM getVM() { + return vm; + } + + public boolean isEndState () { + return vm.isEndState(); + } + + public boolean isErrorState(){ + return (currentError != null); + } + + public boolean hasNextState () { + return !isEndState(); + } + + public boolean transitionOccurred(){ + return vm.transitionOccurred(); + } + + public boolean isNewState () { + boolean isNew = vm.isNewState(); + + if (matchDepth) { + int id = vm.getStateId(); + + if (isNew) { + setStateDepth(id, depth); + } else { + return depth < getStateDepth(id); + } + } + + return isNew; + } + + public boolean isVisitedState () { + return !isNewState(); + } + + public boolean isIgnoredState(){ + return vm.isIgnoredState(); + } + + public boolean isProcessedState(){ + return vm.getChoiceGenerator().isProcessed(); + } + + public boolean isDone(){ + return done; + } + + public int getDepth () { + return depth; + } + + public String getSearchConstraint () { + return lastSearchConstraint; + } + + public Transition getTransition () { + return vm.getLastTransition(); + } + + public int getStateId () { + return vm.getStateId(); + } + + public int getPurgedStateId () { + return -1; // a lot of Searches don't purge any states + } + + + /** + * this is somewhat redundant to SystemState.setIgnored(), but we don't + * want to mix the case of overriding state matching with backtracking when + * searching for multiple errors + */ + public boolean requestBacktrack () { + return doBacktrack = true; + } + + + protected boolean checkAndResetBacktrackRequest() { + if (doBacktrack){ + doBacktrack = false; + return true; + } else { + return false; + } + } + + public boolean supportsBacktrack () { + return true; + } + + public boolean supportsRestoreState () { + // not supported by default + return false; + } + + public int getDepthLimit () { + return depthLimit; + } + + public void setDepthLimit(int limit){ + depthLimit = limit; + } + + protected SearchState getSearchState () { + return new SearchState(this); + } + + // can be used by SearchListeners to create path-less errors (liveness) + public void error (Property property) { + error(property, null, null); + } + + public void error (Property property, Path path, ThreadList threadList) { + + if (getAllErrors) { + // otherwise we are going to overwrite it if we go on + try { + property = property.clone(); + path = path.clone(); + threadList = (ThreadList) threadList.clone(); // this makes it a snapshot (deep) clone + } catch (CloneNotSupportedException cnsx){ + throw new JPFException("failed to clone error information: " + cnsx); + } + done = false; + + } else { + done = true; + } + + currentError = new Error(errors.size()+1, property, path, threadList); + + errors.add(currentError); + + // we should not reset the property until listeners have been notified + // (the listener might be the property itself, in which case it could get + // confused if propertyViolated() notifications happen after a reset) + } + + public void resetProperties(){ + for (Property p : properties) { + p.reset(); + } + } + + protected void notifyStateAdvanced () { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].stateAdvanced(this); + } + if (reporter != null){ + // reporter always comes last to ensure all listeners have been notified + reporter.stateAdvanced(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during stateAdvanced() notification", t); + } + } + + protected void notifyStateProcessed() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].stateProcessed(this); + } + if (reporter != null){ + reporter.stateProcessed(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during stateProcessed() notification", t); + } + } + + protected void notifyStateStored() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].stateStored(this); + } + if (reporter != null){ + reporter.stateStored(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during stateStored() notification", t); + } + } + + protected void notifyStateRestored() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].stateRestored(this); + } + if (reporter != null){ + reporter.stateRestored(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during stateRestored() notification", t); + } + } + + protected void notifyStateBacktracked() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].stateBacktracked(this); + } + if (reporter != null){ + reporter.stateBacktracked(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during stateBacktracked() notification", t); + } + } + + protected void notifyStatePurged() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].statePurged(this); + } + if (reporter != null){ + reporter.statePurged(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during statePurged() notification", t); + } + } + + public void notifySearchProbed() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].searchProbed(this); + } + if (reporter != null){ + reporter.searchProbed(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during searchProbed() notification", t); + } + } + + + protected void notifyPropertyViolated() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].propertyViolated(this); + } + if (reporter != null){ + reporter.propertyViolated(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during propertyViolated() notification", t); + } + + // reset properties if getAllErrors is set + if (getAllErrors){ + resetProperties(); + } + } + + protected void notifySearchStarted() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].searchStarted(this); + } + if (reporter != null){ + reporter.searchStarted(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during searchStarted() notification", t); + } + } + + public void notifySearchConstraintHit(String details) { + try { + lastSearchConstraint = details; + for (int i = 0; i < listeners.length; i++) { + listeners[i].searchConstraintHit(this); + } + if (reporter != null){ + reporter.searchConstraintHit(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during searchConstraintHit() notification", t); + } + } + + protected void notifySearchFinished() { + try { + for (int i = 0; i < listeners.length; i++) { + listeners[i].searchFinished(this); + } + if (reporter != null){ + reporter.searchFinished(this); + } + } catch (Throwable t) { + throw new JPFListenerException("exception during searchFinished() notification", t); + } + } + + protected boolean forward () { + currentError = null; + + boolean ret = vm.forward(); + + checkPropertyViolation(); + return ret; + } + + protected boolean backtrack () { + return vm.backtrack(); + } + + public void setIgnoredState (boolean cond) { + vm.ignoreState(cond); + } + + protected void restoreState (State state) { + // not supported by default + } + + /** this can be used by listeners to terminate the search */ + public void terminate () { + done = true; + } + + protected void setStateDepth (int stateId, int depth) { + stateDepth.set(stateId, depth + 1); + } + + public int getStateDepth (int stateId) { + int depthPlusOne = stateDepth.get(stateId); + if (depthPlusOne <= 0) { + throw new JPFException("Asked for depth of unvisited state"); + } else { + return depthPlusOne - 1; + } + } + + /** + * check if we have a minimum amount of free memory left. If not, we rather want to stop in time + * (with a threshold amount left) so that we can report something useful, and not just die silently + * with a OutOfMemoryError (which isn't handled too gracefully by most VMs) + */ + public boolean checkStateSpaceLimit () { + Runtime rt = Runtime.getRuntime(); + + long avail = rt.freeMemory(); + + // we could also just check for a max number of states, but what really + // limits us is the memory required to store states + + if (avail < minFreeMemory) { + // try to collect first + rt.gc(); + avail = rt.freeMemory(); + + if (avail < minFreeMemory) { + // Ok, we give up, threshold reached + return false; + } + } + + return true; + } +} + diff --git a/src/main/gov/nasa/jpf/search/SearchListener.java b/src/main/gov/nasa/jpf/search/SearchListener.java new file mode 100644 index 0000000..c137ecc --- /dev/null +++ b/src/main/gov/nasa/jpf/search/SearchListener.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + +import gov.nasa.jpf.JPFListener; + +/** + * interface to register for notification by the Search object. + * Observer role in same-name pattern + */ +public interface SearchListener extends JPFListener { + + /** + * got the next state + * Note - this will be notified before any potential propertyViolated, in which + * case the currentError will be already set + */ + void stateAdvanced (Search search); + + /** + * state is fully explored + */ + void stateProcessed (Search search); + + /** + * state was backtracked one step + */ + void stateBacktracked (Search search); + + /** + * some state is not going to appear in any path anymore + */ + void statePurged (Search search); + + /** + * somebody stored the state + */ + void stateStored (Search search); + + /** + * a previously generated state was restored + * (can be on a completely different path) + */ + void stateRestored (Search search); + + /** + * there was a probe request, e.g. from a periodical timer + * note this is called synchronously from within the JPF execution loop + * (after instruction execution) + */ + void searchProbed (Search search); + + /** + * JPF encountered a property violation. + * Note - this is always preceeded by a stateAdvanced + */ + void propertyViolated (Search search); + + /** + * we get this after we enter the search loop, but BEFORE the first forward + */ + void searchStarted (Search search); + + /** + * there was some contraint hit in the search, we back out + * could have been turned into a property, but usually is an attribute of + * the search, not the application + */ + void searchConstraintHit (Search search); + + /** + * we're done, either with or without a preceeding error + */ + void searchFinished (Search search); +} + diff --git a/src/main/gov/nasa/jpf/search/SearchListenerAdapter.java b/src/main/gov/nasa/jpf/search/SearchListenerAdapter.java new file mode 100644 index 0000000..1493336 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/SearchListenerAdapter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.search; + +/** + * a no-action SearchListener which we can use to override only the + * notifications we are interested in + */ +public class SearchListenerAdapter implements SearchListener { + + @Override + public void stateAdvanced(Search search) {} + + @Override + public void stateProcessed(Search search) {} + + @Override + public void stateBacktracked(Search search) {} + + @Override + public void statePurged(Search search) {} + + @Override + public void stateStored(Search search) {} + + @Override + public void stateRestored(Search search) {} + + @Override + public void searchProbed(Search search) {} + + @Override + public void propertyViolated(Search search) {} + + @Override + public void searchStarted(Search search) {} + + @Override + public void searchConstraintHit(Search search) {} + + @Override + public void searchFinished(Search search) {} + +} diff --git a/src/main/gov/nasa/jpf/search/SearchState.java b/src/main/gov/nasa/jpf/search/SearchState.java new file mode 100644 index 0000000..14eab8c --- /dev/null +++ b/src/main/gov/nasa/jpf/search/SearchState.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + +public class SearchState { + + Search search; + int depth; + + SearchState (Search search) { + this.search = search; + depth = search.depth; + } + + public int getSearchDepth () { + return depth; + } +} diff --git a/src/main/gov/nasa/jpf/search/Simulation.java b/src/main/gov/nasa/jpf/search/Simulation.java new file mode 100644 index 0000000..4f0f99f --- /dev/null +++ b/src/main/gov/nasa/jpf/search/Simulation.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search; + + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + + +/** + * this is a straight execution pseudo-search - it doesn't search at + * all (i.e. it doesn't backtrack), but just behaves like a 'normal' VM, + * going forward() until there is no next state + * + * <2do> of course it doesn't quite behave like a normal VM, since it + * doesn't honor thread priorities yet (needs a special scheduler) + * + * <2do> it's not really clear to me how this differs from a 'PathSearch' + * other than using a different scheduler. Looks like there should be just one + * + * <2do> this needs to be updated & tested + * + */ +public class Simulation extends Search { + + public Simulation (Config config, VM vm) { + super(config, vm); + } + + @Override + public void search () { + int depth = 0; + + depth++; + + if (hasPropertyTermination()) { + return; + } + + notifySearchStarted(); + + while (!done) { + if (forward()) { + + if (currentError != null){ + notifyPropertyViolated(); + + if (hasPropertyTermination()) { + return; + } + } + + depth++; + + } else { // no next state + + // <2do> we could check for more things here. If the last insn wasn't + // the main return, or a System.exit() call, we could flag a JPFException + checkPropertyViolation(); + done = true; + } + } + notifySearchFinished(); + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/BFSHeuristic.java b/src/main/gov/nasa/jpf/search/heuristic/BFSHeuristic.java new file mode 100644 index 0000000..9ba6999 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/BFSHeuristic.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.VM; + + +/** + * breadth first search + */ +public class BFSHeuristic extends SimplePriorityHeuristic { + + public BFSHeuristic (Config config, VM vm) { + super(config,vm); + Search.log.info("BFS Search"); + } + + @Override + protected int computeHeuristicValue () { + int priority = vm.getPathLength(); + + return priority; + } + +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/DFSHeuristic.java b/src/main/gov/nasa/jpf/search/heuristic/DFSHeuristic.java new file mode 100644 index 0000000..df4cc5c --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/DFSHeuristic.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + + +/** + * heuristic state prioritizer that favors search depth + */ +public class DFSHeuristic extends SimplePriorityHeuristic { + + public DFSHeuristic (Config conf, VM vm) { + super(conf, vm); + } + + @Override + protected int computeHeuristicValue () { + return Integer.MAX_VALUE - vm.getPathLength(); + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/GlobalSwitchThread.java b/src/main/gov/nasa/jpf/search/heuristic/GlobalSwitchThread.java new file mode 100644 index 0000000..9d1ddbb --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/GlobalSwitchThread.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + + +/** + * heuristic state prioritizer that tries to minimize re-scheduling + */ +public class GlobalSwitchThread extends SimplePriorityHeuristic { + private int[] threads; + + public GlobalSwitchThread (Config config, VM vm) { + super(config, vm); + + int threadHistorySize = config.getInt("search.heuristic.thread_history_size", 10); + + threads = new int[threadHistorySize]; + + for (int i = 0; i < threads.length; i++) { + threads[i] = -1; + } + } + + @Override + protected int computeHeuristicValue () { + int aliveThreads = vm.getThreadList().getMatchingCount(aliveThread); + + int lastRun = vm.getLastTransition().getThreadIndex(); + int h_value = 0; + + if (aliveThreads > 1) { + for (int i = 0; i < threads.length; i++) { + if (lastRun == threads[i]) { + h_value += ((threads.length - i) * aliveThreads); + } + } + } + + int temp0 = threads[0]; + int temp1; + threads[0] = lastRun; + + for (int i = 1; i < threads.length; i++) { + temp1 = threads[i]; + threads[i] = temp0; + temp0 = temp1; + } + + return h_value; + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/HeuristicSearch.java b/src/main/gov/nasa/jpf/search/heuristic/HeuristicSearch.java new file mode 100644 index 0000000..ae05396 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/HeuristicSearch.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.search.Search; +import gov.nasa.jpf.vm.VM; + +import java.util.ArrayList; +import java.util.List; + + +/** + * a search strategy class that computes all immediate successors of a given + * state, puts them into a priority queue (the priority is provided by a + * Heuristic strategy object), and processes states in the sequence of + * highest priorities. Note that the queue can be search-global, i.e. we might hop + * between search levels. + */ +public abstract class HeuristicSearch extends Search { + + static final String DEFAULT_HEURISTIC_PACKAGE = "gov.nasa.jpf.search.heuristic."; + + protected HeuristicState parentState; + protected List childStates; + + protected boolean isPathSensitive = false; + + /* + * do we use A* adaptation of state priorities, i.e. have a + * distance + cost heuristic (in this context, we just use the + * path length as the "distance") + */ + protected boolean useAstar; + + /* + * a beam search is a HeuristicSearch with a state queue that is reset at each + * search level (i.e. it doesn't hop between search levels when fetching the + * next state from the queue) + */ + protected boolean isBeamSearch; + + + public HeuristicSearch (Config config, VM vm) { + super(config, vm); + + useAstar = config.getBoolean("search.heuristic.astar"); + isBeamSearch = config.getBoolean("search.heuristic.beam_search"); + } + + + // add the current state to the queue + protected abstract HeuristicState queueCurrentState (); + + // return the next queued state, which becomes the new parentState + // implementors can also reset or modify the queue + protected abstract HeuristicState getNextQueuedState (); + + public abstract int getQueueSize(); + public abstract boolean isQueueLimitReached(); + + public HeuristicState getParentState() { + return parentState; + } + + public List getChildStates() { + return childStates; + } + + public void setPathSensitive (boolean isPathSensitive) { + this.isPathSensitive = isPathSensitive; + } + + void backtrackToParent () { + backtrack(); + + depth--; + notifyStateBacktracked(); + } + + /* + * generate the set of all child states for the current parent state + * + * overriding methods can use the return value to determine if they + * have to process the childStates, e.g. to compute priorities + * that require the whole set + * + * @returns false if this is cut short by a property termination or + * explicit termination request + */ + protected boolean generateChildren () { + + childStates = new ArrayList(); + + while (!done) { + + if (!forward()) { + notifyStateProcessed(); + return true; + } + + depth++; + notifyStateAdvanced(); + + if (currentError != null){ + notifyPropertyViolated(); + if (hasPropertyTermination()) { + return false; + } + + // note that we don't store the error state anymore, which means we + // might encounter it along different paths. However, this is probably + // what we want for search.multiple_errors. + + } else { + + if (!isEndState() && !isIgnoredState()) { + boolean isNewState = isNewState(); + + if (isNewState && depth >= depthLimit) { + // we can't do this before we actually generated the VM child state + // since we don't want to report DEPTH_CONSTRAINTs for parents + // that have only visited or end state children + notifySearchConstraintHit("depth limit reached: " + depthLimit); + + } else if (isNewState || isPathSensitive) { + + if (isQueueLimitReached()) { + notifySearchConstraintHit("queue limit reached: " + getQueueSize()); + } + + HeuristicState newHState = queueCurrentState(); + if (newHState != null) { + childStates.add(newHState); + notifyStateStored(); + } + } + + } else { + // end state or ignored transition + } + } + + backtrackToParent(); + } + + return false; + } + + + private void restoreState (HeuristicState hState) { + vm.restoreState(hState.getVMState()); + + // note we have to query the depth from the VM because the state is taken from the queue + // and we have no idea when it was entered there + depth = vm.getPathLength(); + notifyStateRestored(); + } + + @Override + public void search () { + + queueCurrentState(); + notifyStateStored(); + + // kind of stupid, but we need to get it out of the queue, and we + // don't have to restore it since it's the first one + parentState = getNextQueuedState(); + + done = false; + notifySearchStarted(); + + if (!hasPropertyTermination()) { + generateChildren(); + + while (!done && (parentState = getNextQueuedState()) != null) { + restoreState(parentState); + + generateChildren(); + } + } + + notifySearchFinished(); + } + + @Override + public boolean supportsBacktrack () { + // we don't do multi-level backtracks, but automatically do backtrackToParent() + // after each child state generation + return false; + } +} + + diff --git a/src/main/gov/nasa/jpf/search/heuristic/HeuristicState.java b/src/main/gov/nasa/jpf/search/heuristic/HeuristicState.java new file mode 100644 index 0000000..81ce6e9 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/HeuristicState.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.RestorableVMState; + + +/** + * wrapper for states that are processed in an order that is + * defined by a heuristic (i.e. not just depends on the shape + * of the state graph) + */ +public abstract class HeuristicState { + + protected RestorableVMState vmState; + protected int stateId; + + public HeuristicState (VM vm) { + stateId = vm.getStateId(); + vmState = vm.getRestorableState(); + } + + public RestorableVMState getVMState () { + return vmState; + } + + public int getStateId() { + return stateId; + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/Interleaving.java b/src/main/gov/nasa/jpf/search/heuristic/Interleaving.java new file mode 100644 index 0000000..4b1d25a --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/Interleaving.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Path; + + +/** + * Heuristic to maximize thread interleavings. It is particularly good at + * flushing out concurrency errors, since it schedules different threads + * as much as possible. + * + */ +public class Interleaving extends SimplePriorityHeuristic { + + int historyLimit; + + public Interleaving (Config config, VM vm) { + super(config,vm); + + historyLimit = config.getInt("search.heuristic.thread_history_limit", -1); + } + + /* + * heuristic based on how often, how long ago, and within how many + * live threads a certain thread did run + */ + @Override + protected int computeHeuristicValue () { + int aliveThreads = vm.getThreadList().getMatchingCount(aliveThread); + + Path path = vm.getPath(); + int pathSize = path.size(); + + int tid = vm.getCurrentThread().getId(); + int h_value = 0; + + if (aliveThreads > 1) { // otherwise there's nothing to interleave + + for (int i= Math.max(0, pathSize - historyLimit); i this relies on that there are no cascaded SchedulingPoints (which would not work anyways) + for (ThreadChoiceGenerator tcg = vm.getLastChoiceGeneratorOfType(ThreadChoiceGenerator.class); tcg != null;){ + ThreadInfo ti= tcg.getNextChoice(); + ThreadChoiceGenerator tcgPrev = tcg.getPreviousChoiceGeneratorOfType(ThreadChoiceGenerator.class); + + if (tcg.isSchedulingPoint()){ + if (tcgPrev != null){ + ThreadInfo tiPrev = tcgPrev.getNextChoice(); + if (ti != tiPrev){ + if (tcg.contains(tiPrev)){ + // the previous thread is still in the runnable list, so it can't be blocked or terminated + preemptions++; + + if (preemptions >= threshold){ + // we don't care, it gets the lowest priority (highest heuristic value) + return Integer.MAX_VALUE; + } + } + } + } + } + + tcg = tcgPrev; + } + + return preemptions; + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/MostBlocked.java b/src/main/gov/nasa/jpf/search/heuristic/MostBlocked.java new file mode 100644 index 0000000..a9687d5 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/MostBlocked.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + + +/** + * Heuristic state prioriizer that maximizes number of blocked states. This + * is a classic heuristic for finding deadlocks, since a deadlock requires + * all threads to be blocked. + */ +public class MostBlocked extends SimplePriorityHeuristic { + + public MostBlocked (Config config, VM vm) { + super(config,vm); + } + + @Override + protected int computeHeuristicValue () { + int alive = vm.getThreadList().getMatchingCount(aliveThread); + int runnable = vm.getThreadList().getMatchingCount(vm.getTimedoutRunnablePredicate()); + + // pcm - the (iSystemState based) condition was "!runnable && alive" + // the '10000' is just a potential max thread count + int h_value = (10000 - (alive - runnable)); + + return h_value; + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/PreferThreads.java b/src/main/gov/nasa/jpf/search/heuristic/PreferThreads.java new file mode 100644 index 0000000..843bc83 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/PreferThreads.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; +import gov.nasa.jpf.vm.Transition; + + +/** + * a heuristic state prioritizer that favors certain threads (specified + * by thread names during initialization) + * + * <2do> for both efficiency and encapsulation reasons, this should be just + * a Scheduler policy (so that we don't have to expand all children) + */ +public class PreferThreads extends SimplePriorityHeuristic { + String[] preferredThreads; + + public PreferThreads (Config config, VM vm) { + super(config,vm); + + preferredThreads = config.getStringArray("search.heuristic.preferredThreads"); + } + + @Override + protected int computeHeuristicValue () { + Transition t = vm.getLastTransition(); + + if (t == null) { + return 1; + } + + String tn = vm.getThreadName(); + + for (int i = 0; i < preferredThreads.length; i++) { + if (tn.equals(preferredThreads[i])) { + return 0; + } + } + + return 1; + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/PrioritizedState.java b/src/main/gov/nasa/jpf/search/heuristic/PrioritizedState.java new file mode 100644 index 0000000..b620ad6 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/PrioritizedState.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.vm.VM; + +/** + * HeuristicState with a scalar, static priority. + * Due to legacy reasons, lower values represent higher priorities + */ +public class PrioritizedState extends HeuristicState implements Comparable{ + + int heuristicValue; // watch out, this is inverted: 0 is max priority + + public PrioritizedState(VM vm, int heuristicValue) { + super(vm); + + this.heuristicValue = heuristicValue; + } + + public int getPriority () { + return heuristicValue; + } + + /* + * NOTE - since we can't use the Java 1.6 pollFirst()/pollLast() yet, + * we have to use remove(o), which in turn requires "compareTo(a) == 0" to + * be identical to "equals(o) == true", so we should implement both + */ + @Override + public int compareTo (PrioritizedState o) { + int diff = heuristicValue - o.heuristicValue; + if (diff == 0) { + return (stateId - o.stateId); + } else { + return diff; + } + } + @Override + public boolean equals (Object o) { + if (o instanceof PrioritizedState) { + PrioritizedState other = (PrioritizedState) o; + return ((stateId == other.stateId) && (heuristicValue == other.heuristicValue)); + } else { + return false; + } + } + + @Override + public String toString() { + return "{"+stateId+','+heuristicValue+'}'; + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/RandomHeuristic.java b/src/main/gov/nasa/jpf/search/heuristic/RandomHeuristic.java new file mode 100644 index 0000000..3b58c1d --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/RandomHeuristic.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.VM; + +import java.util.Random; + + +/** + * heuristic state prioritizer that returns random priority values + */ +public class RandomHeuristic extends SimplePriorityHeuristic { + + protected Random random; + + public RandomHeuristic (Config config, VM vm) { + super(config,vm); + + random = new Random( config.getInt("choice.seed", 42)); + } + + @Override + protected int computeHeuristicValue () { + return java.lang.Math.abs(random.nextInt()); + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/SimplePriorityHeuristic.java b/src/main/gov/nasa/jpf/search/heuristic/SimplePriorityHeuristic.java new file mode 100644 index 0000000..76c6e99 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/SimplePriorityHeuristic.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.util.Predicate; +import gov.nasa.jpf.vm.ThreadInfo; +import gov.nasa.jpf.vm.VM; + +/** + * a heuristic that is based on static priorities that are determined + * at state storage time + */ +public abstract class SimplePriorityHeuristic extends HeuristicSearch { + + StaticPriorityQueue queue; + + protected Predicate aliveThread; + + public SimplePriorityHeuristic (Config config, VM vm) { + super(config,vm); + + queue = new StaticPriorityQueue(config); + + aliveThread = new Predicate() { + @Override + public boolean isTrue (ThreadInfo ti) { + return (ti.isAlive()); + } + }; + + } + + protected abstract int computeHeuristicValue (); + + protected int computeAstarPathCost (VM vm) { + return vm.getPathLength(); + } + + @Override + protected HeuristicState queueCurrentState () { + int heuristicValue; + + if (vm.isInterestingState()) { + heuristicValue = 0; + } else if (vm.isBoringState()) { + heuristicValue = Integer.MAX_VALUE; + + } else { + heuristicValue = computeHeuristicValue(); + + if (useAstar) { + // <2do> we probably don't want this for isInteresting/isBoring? + heuristicValue += computeAstarPathCost(vm); + } + } + + PrioritizedState hState = new PrioritizedState(vm,heuristicValue); + + queue.add(hState); + + return hState; + } + + @Override + protected HeuristicState getNextQueuedState () { + + //HeuristicState hState = queue.pollFirst(); // only Java 1.6 + //if (isBeanSearch) { queue.clear(); } + //return hState; + + if (queue.size() == 0) { // the dreaded Java 1.5 version + return null; + } + HeuristicState hState = queue.first(); + + if (isBeamSearch) { + queue.clear(); + } else { + queue.remove(hState); + } + + return hState; + } + + @Override + public int getQueueSize() { + return queue.size(); + } + + @Override + public boolean isQueueLimitReached() { + return queue.isQueueLimitReached(); + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/StaticPriorityQueue.java b/src/main/gov/nasa/jpf/search/heuristic/StaticPriorityQueue.java new file mode 100644 index 0000000..c68d677 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/StaticPriorityQueue.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; + +import java.util.Iterator; +import java.util.TreeSet; + +/** + * container for statically prioritized states, based on bounded + * RB trees + * + * TreeSet is a better choice than PriorityQueue since the size + * constraint means we have to remove elements from both ends, which + * is inefficient with heaps. A simple (binary) sorted array using + * block copy can be more efficient, but that very much depends on + * queue size and processor, so it's not really worth the trouble + * + * <2do> this needs to be re-evaluated in light of the stupid fact + * that pollFirst()/pollLast() are only in Java 1.6 and we can't switch + * yet (no Java 1.6 for PPC), which forces us to do some shuffling to + * make remove(last()) work as expected + */ +@SuppressWarnings("serial") +public class StaticPriorityQueue extends TreeSet { + + int maxQueueSize; + + public StaticPriorityQueue (Config config) { + // unbound queues are pretty pointless - we could probably better use + // DFSearch in this case + maxQueueSize = config.getInt("search.heuristic.queue_limit", 1024); + if (maxQueueSize < 0){ + maxQueueSize = Integer.MAX_VALUE; + } + } + + @Override + public boolean add (PrioritizedState s) { + if (size() < maxQueueSize) { // limit not yet reached + return super.add(s); + + } else { + PrioritizedState last = last(); + if (s.compareTo(last) < 0) { + //pollLast(); // that's only Java 1.6 + remove(last); + + return super.add(s); + + } else { + // don't add with this priority value + return false; + } + } + } + + public boolean isQueueLimitReached() { + return size() >= maxQueueSize; + } + + // for debugging purposes + void dump() { + int i=0; + System.err.print('['); + for (Iterator it=iterator(); it.hasNext();) { + if (i++ > 0) { + System.err.print(','); + } + System.err.print(it.next()); + } + System.err.println(']'); + } +} diff --git a/src/main/gov/nasa/jpf/search/heuristic/UserHeuristic.java b/src/main/gov/nasa/jpf/search/heuristic/UserHeuristic.java new file mode 100644 index 0000000..cd83936 --- /dev/null +++ b/src/main/gov/nasa/jpf/search/heuristic/UserHeuristic.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.search.heuristic; + +import gov.nasa.jpf.Config; +import gov.nasa.jpf.vm.ClassLoaderInfo; +import gov.nasa.jpf.vm.ElementInfo; +import gov.nasa.jpf.vm.JPF_gov_nasa_jpf_vm_Verify; +import gov.nasa.jpf.vm.VM; + + +/** + * heuristic state prioritizer that is controlled by the system under test, which can + * use Verify.get/set/resetHeuristicSearchValue() to compute priorities + */ +public class UserHeuristic extends SimplePriorityHeuristic { + public UserHeuristic (Config config, VM vm) { + super(config, vm); + } + + @Override + protected int computeHeuristicValue () { + return JPF_gov_nasa_jpf_vm_Verify.heuristicSearchValue; + } +} diff --git a/src/main/gov/nasa/jpf/tool/GenPeer.java b/src/main/gov/nasa/jpf/tool/GenPeer.java new file mode 100644 index 0000000..59d7101 --- /dev/null +++ b/src/main/gov/nasa/jpf/tool/GenPeer.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2014, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The Java Pathfinder core (jpf-core) platform is licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpf.tool; + +import gov.nasa.jpf.vm.Types; + +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; + + +/** + * tool to automatically generate the framework of a native peer MJI class, + * given it's model class. GenPeer collects all the native methods from the + * model class, and creates the corresponding native peer methods + */ +public class GenPeer { + static final String SYS_PKG = "gov.nasa.jpf.vm"; + static final String MJI_ENV = "gov.nasa.jpf.vm.MJIEnv"; + static final String NATIVEPEER = "gov.nasa.jpf.vm.NativePeer"; + static final String INDENT = " "; + static final String SUPERCLASS = "NativePeer"; + static final String MJI_ANN = "@MJI"; + static final String METHOD_PREFIX = "public"; + static final String ENV_ARG = "MJIEnv env"; + static final String OBJ_ARG = "int objRef"; + static final String CLS_ARG = "int clsObjRef"; + static final String REF_TYPE = "int"; + static final String NULL = "MJIEnv.NULL"; + + static String clsName; + static String[] mths; + + // our options + static boolean isSystemPkg; + static boolean allMethods; + static boolean mangleNames; + static boolean clinit; + + public static void main (String[] args) { + if ((args.length == 0) || !readOptions(args)) { + showUsage(); + + return; + } + + PrintWriter pw = new PrintWriter(System.out, true); + Class cls = getClass(clsName); + + if (cls != null) { + printNativePeer(cls, pw); + } + } + + static Class getClass (String cname) { + Class clazz = null; + + try { + clazz = Class.forName(cname); + } catch (ClassNotFoundException cnfx) { + System.err.println("target class not found: " + cname); + } catch (Throwable x) { + x.printStackTrace(); + } + + return clazz; + } + + static boolean isMJICandidate (Method m) { + if (allMethods) { + return true; + } + + if (mths != null) { + String name = m.getName(); + + for (int i = 0; i < mths.length; i++) { + if (name.equals(mths[i])) { + return true; + } + } + } else { + if ((m.getModifiers() & Modifier.NATIVE) != 0) { + return true; + } + } + + return false; + } + + static void getMangledName (Method m) { + StringBuilder sb = new StringBuilder(50); + + sb.append(m.getName()); + sb.append("__"); + } + + static boolean isPrimitiveType (String t) { + return ("int".equals(t) || "long".equals(t) || "boolean".equals(t) || + "void".equals(t) || // not really, but useful for returnTypes + "byte".equals(t) || "char".equals(t) || "short".equals(t) || + "float".equals(t) || "double".equals(t)); + } + + static void printClinit (PrintWriter pw) { + pw.print(INDENT); + pw.print(METHOD_PREFIX); + pw.print(" void $clinit ("); + pw.print(ENV_ARG); + pw.print(", "); + pw.print(CLS_ARG); + pw.println(") {"); + pw.print(INDENT); + pw.println("}"); + } + + static void printFooter (Class cls, PrintWriter pw) { + pw.println("}"); + } + + static void printHeader (Class cls, PrintWriter pw) { + if (isSystemPkg) { + pw.print("package "); + pw.print(SYS_PKG); + pw.println(';'); + pw.println(); + } + + pw.print("import "); + pw.print(MJI_ENV); + pw.println(";"); + pw.print("import "); + pw.print(NATIVEPEER); + pw.println(";"); + pw.println(); + + String cname = cls.getName().replace('.', '_'); + + pw.print("public class "); + pw.print("JPF_"); + pw.print(cname); + pw.print(" extends "); + pw.print(SUPERCLASS); + pw.println(" {"); + } + + static void printMethodBody (String rt, String t, PrintWriter pw) { + if (!"void".equals(rt)) { + pw.print(INDENT); + pw.print(INDENT); + pw.print(rt); + + if ((rt == REF_TYPE) && (rt != t)) { + pw.print(" r"); + pw.print(t); + pw.print(" = "); + pw.print(NULL); + pw.println(";"); + + pw.print(INDENT); + pw.print(INDENT); + pw.print("return r"); + pw.print(t); + pw.println(";"); + } else { + pw.print(" v = ("); + pw.print(rt); + pw.println(")0;"); + + pw.print(INDENT); + pw.print(INDENT); + pw.println("return v;"); + } + } + } + + static void printMethodName (Method m, PrintWriter pw) { + String name = null; + + if (mangleNames) { + name = Types.getJNIMangledMethodName(m); + } else { + name = m.getName(); + } + + pw.print(name); + } + + static void printMJIAnnotation(PrintWriter pw) { + pw.print(INDENT); + pw.println(MJI_ANN); + } + + static void printMethodStub (String condPrefix, Method m, PrintWriter pw) { + String t = null; + String rt; + + printMJIAnnotation(pw); + + pw.print(INDENT); + pw.print(METHOD_PREFIX); + pw.print(' '); + + if (condPrefix == null) { + t = rt = stripType(m.getReturnType().getName()); + + if (!isPrimitiveType(rt)) { + rt = REF_TYPE; + } + } else { + rt = "boolean"; + } + + pw.print(rt); + + pw.print(' '); + + if (condPrefix != null) { + pw.print(condPrefix); + } + + printMethodName(m, pw); + pw.print(" ("); + + printStdArgs(m, pw); + printTargetArgs(m, pw); + + pw.println(") {"); + + if (condPrefix == null) { + printMethodBody(rt, stripType(null, t), pw); + } else { + pw.print(INDENT); + pw.print(INDENT); + pw.println("return true;"); + } + + pw.print(INDENT); + pw.println('}'); + } + + static void printNativePeer (Class cls, PrintWriter pw) { + Method[] mths = cls.getDeclaredMethods(); + + printHeader(cls, pw); + + if (clinit) { + printClinit(pw); + } + + for (int i = 0; i < mths.length; i++) { + Method m = mths[i]; + + if (isMJICandidate(m)) { + pw.println(); + printMethodStub(null, m, pw); + } + } + + printFooter(cls, pw); + } + + static void printStdArgs (Method m, PrintWriter pw) { + pw.print(ENV_ARG); + pw.print(", "); + + if ((m.getModifiers() & Modifier.STATIC) != 0) { + pw.print(CLS_ARG); + } else { + pw.print(OBJ_ARG); + } + } + + static void printTargetArgs (Method m, PrintWriter pw) { + Class[] pt = m.getParameterTypes(); + + for (int i = 0; i < pt.length; i++) { + String t = stripType(pt[i].getName()); + boolean isPrim = isPrimitiveType(t); + + pw.print(", "); + + if (isPrim) { + pw.print(t); + pw.print(" v"); + pw.print(i); + } else { + pw.print(REF_TYPE); + pw.print(" r"); + pw.print(stripType(null, t)); + pw.print(i); + } + } + } + + static String[] readNames (String[] args, int i) { + ArrayList a = null; + + for (; (i < args.length) && (args[i].charAt(0) != '-'); i++) { + if (a == null) { + a = new ArrayList(); + } + + a.add(args[i]); + } + + if (a != null) { + String[] names = new String[a.size()]; + a.toArray(names); + + return names; + } + + return null; + } + + static boolean readOptions (String[] args) { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + + if ("-s".equals(arg)) { + isSystemPkg = true; + } else if ("-m".equals(arg)) { + mangleNames = true; + } else if ("-a".equals(arg)) { + allMethods = true; + } else if ("-ci".equals(arg)) { + clinit = true; + } else if (arg.charAt(0) != '-') { + // rather simple + if (clsName == null) { + clsName = arg; + } else { + mths = readNames(args, i); + i += mths.length; + } + } else { + System.err.println("unknown option: " + arg); + showUsage(); + + return false; + } + } + + return (clsName != null); + } + + static void showUsage () { + System.out.println( + "usage: 'GenPeer [