Various changes as suggested by reviewers; formatting issues

Jonathan Bell [2013-02-28 22:02:39]
Various changes as suggested by reviewers; formatting issues
Filename
Code/ChroniclerJ/nondeterministic-methods.txt
Code/ChroniclerJ/src/com/rits/cloning/Cloner.java
Code/ChroniclerJ/src/com/rits/cloning/CloningException.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerArrayList.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerCalendar.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerConcurrentHashMap.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomCollection.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomMap.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashMap.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashSet.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerLinkedList.java
Code/ChroniclerJ/src/com/rits/cloning/FastClonerTreeMap.java
Code/ChroniclerJ/src/com/rits/cloning/IFastCloner.java
Code/ChroniclerJ/src/com/rits/cloning/IFreezable.java
Code/ChroniclerJ/src/com/rits/cloning/IInstantiationStrategy.java
Code/ChroniclerJ/src/com/rits/cloning/Immutable.java
Code/ChroniclerJ/src/com/rits/cloning/ObjenesisInstantiationStrategy.java
Code/ChroniclerJ/src/com/rits/perspectives/Perspectives.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackInvocation.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackRegistry.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJExportRunner.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJUncaughtExceptionHandler.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CloningUtils.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Constants.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedLog.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedSerializableLog.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Instrumenter.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/InstrumenterClassWriter.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Log.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Main.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodCall.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodInterceptor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/SerializableLog.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/analysis/MutabilityAnalyzer.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/bench/ChroniclerJLogExplorer.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/FinalizerReplayingMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayClassVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayRunner.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/Replayer.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/AnnotatedMethod.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/Expression.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/FieldExpression.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/MethodExpression.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/SimpleExpression.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackDuplicatingClassVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackLoggingMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CloningAdviceAdapter.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/FinalizerLoggingMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/MainLoggingMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingClassVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/ReflectionInterceptingMethodVisitor.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/CatchClassErrorFieldDictionary.java
Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/StaticReflectionProvider.java
diff --git a/Code/ChroniclerJ/nondeterministic-methods.txt b/Code/ChroniclerJ/nondeterministic-methods.txt
index a2f0537..ffc0836 100644
--- a/Code/ChroniclerJ/nondeterministic-methods.txt
+++ b/Code/ChroniclerJ/nondeterministic-methods.txt
@@ -2086,7 +2086,6 @@ com/sun/corba/se/impl/logging/OMGSystemException.destroyIndestructible:(Lorg/omg
 com/sun/org/apache/xml/internal/security/utils/ElementProxy.length:(Ljava/lang/String;Ljava/lang/String;)I
 javax/swing/plaf/synth/SynthStyle.getBoolean:(Ljavax/swing/plaf/synth/SynthContext;Ljava/lang/Object;Z)Z
 java/awt/Container.containsFocus:()Z
-javax/xml/stream/XMLInputFactory.createXMLStreamReader:(Ljava/io/InputStream;Ljava/lang/String;)Ljavax/xml/stream/XMLStreamReader;
 com/sun/org/apache/xml/internal/res/XMLErrorResources_ko.loadResourceBundle:(Ljava/lang/String;)Lcom/sun/org/apache/xml/internal/res/XMLErrorResources;
 com/sun/xml/internal/txw2/output/DelegatingXMLStreamWriter.writeStartDocument:()V
 sun/management/counter/perf/Prologue.getEntryOffset:()I
@@ -4380,7 +4379,6 @@ sun/tools/java/Environment.error:(JLjava/lang/String;Ljava/lang/Object;Ljava/lan
 com/sun/xml/internal/dtdparser/DTDEventListener.fatalError:(Lorg/xml/sax/SAXParseException;)V
 sun/reflect/misc/ConstructorUtil.getConstructors:(Ljava/lang/Class;)[Ljava/lang/reflect/Constructor;
 com/sun/jmx/snmp/agent/SnmpTableSupport.bindWithTableMeta:()V
-java/io/PrintStream.println:(Ljava/lang/Object;)V
 javax/swing/JInternalFrame.<init>:(Ljava/lang/String;Z)V
 java/awt/List.<init>:(I)V
 sun/org/mozilla/javascript/internal/Context.toString:(Ljava/lang/Object;)Ljava/lang/String;
@@ -6818,7 +6816,6 @@ com/sun/corba/se/impl/logging/ORBUtilSystemException.numInvocationsAlreadyZero:(
 com/sun/xml/internal/ws/resources/WsservletMessages.ERROR_IMPLEMENTOR_REGISTRY_CLASS_NOT_FOUND:(Ljava/lang/Object;)Ljava/lang/String;
 javax/swing/plaf/basic/BasicSliderUI$ComponentHandler.componentResized:(Ljava/awt/event/ComponentEvent;)V
 com/sun/xml/internal/xsom/util/NameGetter.attGroupDecl:(Lcom/sun/xml/internal/xsom/XSAttGroupDecl;)Ljava/lang/String;
-javax/xml/soap/SOAPPart.getEnvelope:()Ljavax/xml/soap/SOAPEnvelope;
 org/w3c/dom/ProcessingInstruction.getData:()Ljava/lang/String;
 com/sun/xml/internal/bind/v2/runtime/output/FastInfosetStreamWriterOutput.text:(Ljava/lang/String;Z)V
 com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.callUserDataHandlers:(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;SLjava/util/Hashtable;)V
@@ -8414,7 +8411,6 @@ com/sun/tools/javac/comp/Check.validate:(Lcom/sun/tools/javac/util/List;)V
 javax/swing/plaf/basic/BasicButtonUI.paintText:(Ljava/awt/Graphics;Ljavax/swing/AbstractButton;Ljava/awt/Rectangle;Ljava/lang/String;)V
 com/sun/tools/example/debug/gui/SingleLeafTreeSelectionModel.setSelectionPaths:([Ljavax/swing/tree/TreePath;)V
 com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.initialize:()Z
-javax/xml/bind/JAXBContext.createUnmarshaller:()Ljavax/xml/bind/Unmarshaller;
 java/nio/DirectIntBufferU.put:(II)Ljava/nio/IntBuffer;
 javax/swing/plaf/metal/MetalInternalFrameTitlePane.access$2700:(Ljavax/swing/plaf/metal/MetalInternalFrameTitlePane;)Ljavax/swing/JInternalFrame;
 com/sun/xml/internal/fastinfoset/sax/SAXDocumentParser.parse:(Lorg/xml/sax/InputSource;)V
@@ -9900,7 +9896,6 @@ sun/nio/cs/KOI8_R$Encoder.access$000:()[S
 javax/sql/rowset/serial/SerialClob.<init>:([C)V
 com/sun/java/swing/plaf/windows/WindowsButtonUI.paintFocus:(Ljava/awt/Graphics;Ljavax/swing/AbstractButton;Ljava/awt/Rectangle;Ljava/awt/Rectangle;Ljava/awt/Rectangle;)V
 java/awt/event/ActionEvent.getModifiers:()I
-java/io/PrintStream.println:(Ljava/lang/String;)V
 com/sun/jmx/interceptor/MBeanServerInterceptor.createMBean:(Ljava/lang/String;Ljavax/management/ObjectName;Ljavax/management/ObjectName;[Ljava/lang/Object;[Ljava/lang/String;)Ljavax/management/ObjectInstance;
 com/sun/tools/jdi/SDE$LineStratum.sourceName:()Ljava/lang/String;
 javax/swing/JFileChooser.<init>:(Ljavax/swing/filechooser/FileSystemView;)V
@@ -27204,7 +27199,6 @@ sun/net/idn/StringPrepDataReader.readIndexes:(I)[I
 com/sun/corba/se/impl/logging/UtilSystemException.badBeginUnmarshalCustomValue:(Lorg/omg/CORBA/CompletionStatus;Ljava/lang/Throwable;)Lorg/omg/CORBA/INTERNAL;
 java/security/KeyFactory.generatePrivate:(Ljava/security/spec/KeySpec;)Ljava/security/PrivateKey;
 com/sun/org/apache/xerces/internal/util/LocatorProxy.getXMLVersion:()Ljava/lang/String;
-javax/xml/soap/SOAPElement.getChildElements:(Ljavax/xml/namespace/QName;)Ljava/util/Iterator;
 com/sun/tools/example/debug/bdi/ExecutionManager.attach:(Ljava/lang/String;)V
 javax/swing/Box.<init>:(I)V
 com/sun/xml/internal/org/jvnet/mimepull/MIMEParser.skipPreamble:()V
@@ -28672,7 +28666,6 @@ javax/swing/text/html/MinimalHTMLWriter.mapStyleName:(Ljava/lang/String;)Ljava/l
 java/net/DatagramSocket.close:()V
 com/sun/management/jmx/MBeanServerImpl.deserialize:(Ljava/lang/String;[B)Ljava/io/ObjectInputStream;
 com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.getClassMember:(Lcom/sun/javadoc/MethodDoc;)Lcom/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap$ClassMember;
-javax/xml/stream/XMLInputFactory.createXMLStreamReader:(Ljava/io/InputStream;)Ljavax/xml/stream/XMLStreamReader;
 sun/security/provider/certpath/IndexedCollectionCertStore.buildIndex:(Ljava/util/Collection;)V
 com/sun/corba/se/impl/protocol/giopmsgheaders/LocateReplyMessage_1_0.read:(Lorg/omg/CORBA/portable/InputStream;)V
 sun/misc/URLClassPath$JarLoader$2.getContentLength:()I
@@ -41234,7 +41227,6 @@ com/sun/org/apache/xpath/internal/patterns/NodeTest.getStaticScore:()Lcom/sun/or
 org/omg/IOP/CodecPackage/InvalidTypeForEncodingHelper.type:()Lorg/omg/CORBA/TypeCode;
 com/sun/org/apache/xerces/internal/xs/ElementPSVI.getActualNormalizedValue:()Ljava/lang/Object;
 sun/awt/datatransfer/DataTransferer.isTextFormat:(J)Z
-java/io/PrintStream.println:(D)V
 sun/jkernel/DownloadManager.getLocalLowKernelJava:()Ljava/lang/String;
 com/sun/corba/se/impl/logging/OMGSystemException.bioReset:(Lorg/omg/CORBA/CompletionStatus;)Lorg/omg/CORBA/NO_IMPLEMENT;
 com/sun/java/util/jar/pack/NativeUnpack.setOption:(Ljava/lang/String;Ljava/lang/String;)Z
@@ -47730,7 +47722,6 @@ sun/awt/image/IntegerInterleavedRaster.setDataElements:(IILjava/lang/Object;)V
 com/sun/org/apache/xalan/internal/xsltc/compiler/util/StringType.toJCType:()Lcom/sun/org/apache/bcel/internal/generic/Type;
 javax/swing/plaf/synth/ParsedSynthStyle$AggregatePainter.paintToolBarDragWindowBorder:(Ljavax/swing/plaf/synth/SynthContext;Ljava/awt/Graphics;IIIII)V
 javax/management/relation/RelationNotification.writeObject:(Ljava/io/ObjectOutputStream;)V
-java/io/PrintStream.println:(Z)V
 org/omg/CosNaming/_BindingIteratorStub.writeObject:(Ljava/io/ObjectOutputStream;)V
 sun/security/krb5/EncryptedData.<init>:(Lsun/security/krb5/EncryptionKey;[BI)V
 sun/net/www/ParseUtil.encodePath:(Ljava/lang/String;Z)Ljava/lang/String;
@@ -57245,7 +57236,6 @@ com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.getTypedChild
 java/lang/management/ManagementFactory.getGarbageCollectorMXBeans:()Ljava/util/List;
 java/io/BufferedOutputStream.write:([BII)V
 com/sun/tools/doclets/internal/toolkit/taglets/Taglet.inPackage:()Z
-javax/xml/soap/SOAPMessage.getSOAPPart:()Ljavax/xml/soap/SOAPPart;
 sun/tools/jstat/OptionOutputFormatter.resolve:()V
 com/sun/corba/se/impl/logging/NamingSystemException.namingCtxRebindctxAlreadyBound:()Lorg/omg/CORBA/INTERNAL;
 com/sun/xml/internal/xsom/impl/scd/SCDParser.Step:()Lcom/sun/xml/internal/xsom/impl/scd/Step;
@@ -57962,7 +57952,6 @@ org/omg/CORBA/portable/ValueOutputStream.start_value:(Ljava/lang/String;)V
 com/sun/security/auth/LdapPrincipal.getName:()Ljava/lang/String;
 org/omg/DynamicAny/_DynAnyStub.get_ulong:()I
 javax/swing/text/AbstractDocument$ElementEdit.undo:()V
-java/beans/PropertyDescriptor.getReadMethod0:()Ljava/lang/reflect/Method;
 com/sun/xml/internal/messaging/saaj/soap/ver1_1/HeaderElement1_1Impl.getRoleAttributeName:()Lcom/sun/xml/internal/messaging/saaj/soap/name/NameImpl;
 sun/font/AttributeValues.getBidiEmbedding:()I
 sun/print/ServiceDialog$IconRadioButton.<init>:(Lsun/print/ServiceDialog;Ljava/lang/String;Ljava/lang/String;ZLjavax/swing/ButtonGroup;Ljava/awt/event/ActionListener;)V
@@ -66928,7 +66917,6 @@ com/sun/corba/se/impl/logging/POASystemException.poaServantNotUnique:(Ljava/lang
 javax/swing/tree/FixedHeightLayoutCache.treeNodesChanged:(Ljavax/swing/event/TreeModelEvent;)V
 com/sun/corba/se/spi/ior/IdentifiableContainerBase.equals:(Ljava/lang/Object;)Z
 org/omg/CosNaming/NamingContextExtPackage/URLStringHelper.read:(Lorg/omg/CORBA/portable/InputStream;)Ljava/lang/String;
-java/beans/PropertyDescriptor.getReadMethod:()Ljava/lang/reflect/Method;
 sun/tools/tree/AddExpression.inlineValue:(Lsun/tools/java/Environment;Lsun/tools/tree/Context;)Lsun/tools/tree/Expression;
 com/sun/xml/internal/xsom/util/XSFinder.annotation:(Lcom/sun/xml/internal/xsom/XSAnnotation;)Ljava/lang/Object;
 java/io/DataOutputStream.writeFloat:(F)V
@@ -69886,7 +69874,6 @@ com/sun/xml/internal/rngom/binary/visitor/PatternVisitor.visitChoice:(Lcom/sun/x
 com/sun/org/apache/xalan/internal/xsltc/compiler/Mode.completeTestSequences:(ILjava/util/Vector;)V
 com/sun/tools/internal/xjc/model/CReferencePropertyInfo.isMixed:()Z
 java/io/Console.access$200:(Ljava/io/Console;)[C
-javax/xml/stream/XMLInputFactory.createXMLStreamReader:(Ljava/lang/String;Ljava/io/Reader;)Ljavax/xml/stream/XMLStreamReader;
 com/sun/org/apache/xml/internal/serializer/NamespaceMappings.lookupPrefix:(Ljava/lang/String;)Ljava/lang/String;
 com/sun/corba/se/impl/naming/cosnaming/NamingContextImpl.dprint:(Ljava/lang/String;)V
 sun/security/krb5/internal/crypto/dk/ArcFourCrypto.calculateChecksum:([BI[BII)[B
@@ -74601,7 +74588,6 @@ com/sun/tools/jdi/VirtualMachineImpl.arrayType:(J)Lcom/sun/tools/jdi/ArrayTypeIm
 sun/security/tools/JarSigner.getAliasInfo:(Ljava/lang/String;)V
 javax/swing/plaf/basic/BasicProgressBarUI.access$500:(Ljavax/swing/plaf/basic/BasicProgressBarUI;)I
 javax/swing/text/JTextComponent.invokeAction:(Ljava/lang/String;Ljavax/swing/Action;)V
-javax/xml/stream/XMLInputFactory.createXMLStreamReader:(Ljava/io/Reader;)Ljavax/xml/stream/XMLStreamReader;
 com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.popSOAPBinding:()Ljavax/jws/soap/SOAPBinding;
 javax/swing/plaf/metal/MetalTitlePane.getWindowDecorationStyle:()I
 java/awt/PageAttributes$ColorType.hashCode:()I
@@ -84801,7 +84787,6 @@ sun/print/PrintJob2D.initPrintJob2D:(Ljava/awt/Frame;Ljava/lang/String;Ljava/awt
 com/sun/org/apache/bcel/internal/classfile/Deprecated.toString:()Ljava/lang/String;
 com/sun/tools/example/debug/tty/ThreadInfo.removeThread:(Lcom/sun/jdi/ThreadReference;)V
 com/sun/corba/se/impl/protocol/CorbaMessageMediatorImpl.handleInput:(Lcom/sun/corba/se/impl/protocol/giopmsgheaders/FragmentMessage_1_1;)V
-java/lang/System.gc:()V
 com/sun/tools/hat/internal/parser/MappedReadBuffer.getLong:(J)J
 com/sun/org/apache/xpath/internal/operations/Operation.deepEquals:(Lcom/sun/org/apache/xpath/internal/Expression;)Z
 java/lang/management/MemoryPoolMXBean.resetPeakUsage:()V
@@ -94103,7 +94088,6 @@ com/sun/jmx/remote/security/JMXPluggableAuthenticator.authenticationFailure:(Lja
 java/io/BufferedReader.fill:()V
 com/sun/xml/internal/ws/api/model/wsdl/WSDLBoundOperation.getInParts:()Ljava/util/Map;
 com/sun/rowset/CachedRowSetImpl.getRow:()I
-java/lang/Throwable.printStackTraceAsCause:(Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V
 com/sun/java/util/jar/pack/CodingChooser.computeSize:(Lcom/sun/java/util/jar/pack/CodingMethod;[III[I)V
 com/sun/xml/internal/ws/api/pipe/Fiber.completionCheck:()V
 java/util/logging/LogManager.readConfiguration:()V
@@ -102891,7 +102875,6 @@ com/sun/tools/javac/zip/ZipFileIndex.getZipFile:()Ljava/io/File;
 com/sun/jmx/snmp/IPAcl/Parser.HostInform:()V
 javax/management/monitor/CounterMonitor.<clinit>:()V
 sun/print/PSPrinterJob.textOut:(Ljava/awt/Graphics;Ljava/lang/String;FFLjava/awt/Font;Ljava/awt/font/FontRenderContext;F)Z
-javax/xml/soap/SOAPElement.getElementName:()Ljavax/xml/soap/Name;
 com/sun/org/apache/bcel/internal/util/ClassPath$ClassFile.getTime:()J
 com/sun/jmx/mbeanserver/MXBeanProxy$Visitor.visitAttribute:(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V
 com/sun/org/apache/xerces/internal/impl/dtd/XMLDTDLoader.setErrorHandler:(Lcom/sun/org/apache/xerces/internal/xni/parser/XMLErrorHandler;)V
@@ -111704,7 +111687,6 @@ org/ietf/jgss/GSSManager.createCredential:(Lorg/ietf/jgss/GSSName;ILorg/ietf/jgs
 javax/swing/FocusManager.<init>:()V
 javax/swing/plaf/basic/BasicMenuItemUI.paintAccText:(Ljava/awt/Graphics;Lsun/swing/MenuItemLayoutHelper;Lsun/swing/MenuItemLayoutHelper$LayoutResult;)V
 com/sun/xml/internal/rngom/digested/DXMLPrinter$DXMLPrinterVisitor.onMixed:(Lcom/sun/xml/internal/rngom/digested/DMixedPattern;)Ljava/lang/Void;
-javax/xml/soap/SOAPElement.getChildElements:()Ljava/util/Iterator;
 com/sun/tools/internal/ws/wsdl/document/WSDLDocument.getPortQNames:(Ljava/lang/String;)[Ljavax/xml/namespace/QName;
 com/sun/tools/example/debug/event/JDIListener.locationTrigger:(Lcom/sun/tools/example/debug/event/LocationTriggerEventSet;)V
 com/sun/tools/internal/ws/resources/WsdlMessages.localizablePARSING_ELEMENT_OR_TYPE_REQUIRED:(Ljava/lang/Object;)Lcom/sun/xml/internal/ws/util/localization/Localizable;
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/Cloner.java b/Code/ChroniclerJ/src/com/rits/cloning/Cloner.java
index c725e22..54cbfd2 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/Cloner.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/Cloner.java
@@ -1,3 +1,4 @@
+
 package com.rits.cloning;

 import java.lang.annotation.Annotation;
@@ -28,678 +29,635 @@ import java.util.regex.Pattern;
 import javax.activation.FileDataSource;

 /**
- * Cloner: deep clone objects.
- *
- * This class is thread safe. One instance can be used by multiple threads on the same time.
+ * Cloner: deep clone objects. This class is thread safe. One instance can be
+ * used by multiple threads on the same time.
  *
- * @author kostantinos.kougios
- *
- * 18 Sep 2008
+ * @author kostantinos.kougios 18 Sep 2008
  */
-public class Cloner
-{
-	private final IInstantiationStrategy					instantiationStrategy;
-	private final Set<Class<?>>								ignored				= new HashSet<Class<?>>();
-	private final Set<Class<?>>								ignoredInstanceOf	= new HashSet<Class<?>>();
-	private final Set<Class<?>>								nullInstead			= new HashSet<Class<?>>();
-	private final Map<Class<?>, IFastCloner>				fastCloners			= new HashMap<Class<?>, IFastCloner>();
-	private final Map<Object, Boolean>						ignoredInstances	= new IdentityHashMap<Object, Boolean>();
-	private final ConcurrentHashMap<Class<?>, List<Field>>	fieldsCache			= new ConcurrentHashMap<Class<?>, List<Field>>();
-	private boolean											dumpClonedClasses	= false;
-	private boolean											cloningEnabled		= true;
-	private boolean											nullTransient		= false;
-	private boolean											cloneSynthetics		= true;
-
-	public Cloner()
-	{
-		this.instantiationStrategy = ObjenesisInstantiationStrategy.getInstance();
-		init();
-	}
-
-	public Cloner(final IInstantiationStrategy instantiationStrategy)
-	{
-		this.instantiationStrategy = instantiationStrategy;
-		init();
-	}
-
-	public boolean isNullTransient()
-	{
-		return nullTransient;
-	}
-
-	/**
-	 * this makes the cloner to set a transient field to null upon cloning.
-	 *
-	 * NOTE: primitive types can't be nulled. Their value will be set to default, i.e. 0 for int
-	 *
-	 * @param nullTransient		true for transient fields to be nulled
-	 */
-	public void setNullTransient(final boolean nullTransient)
-	{
-		this.nullTransient = nullTransient;
-	}
-
-	public void setCloneSynthetics(final boolean cloneSynthetics)
-	{
-		this.cloneSynthetics = cloneSynthetics;
-	}
-
-	private void init()
-	{
-		registerKnownJdkImmutableClasses();
-		registerKnownConstants();
-		registerFastCloners();
-	}
-
-	/**
-	 * registers a std set of fast cloners.
-	 */
-	protected void registerFastCloners()
-	{
-		fastCloners.put(GregorianCalendar.class, new FastClonerCalendar());
-		fastCloners.put(ArrayList.class, new FastClonerArrayList());
-		fastCloners.put(LinkedList.class, new FastClonerLinkedList());
-		fastCloners.put(HashSet.class, new FastClonerHashSet());
-		fastCloners.put(HashMap.class, new FastClonerHashMap());
-		fastCloners.put(TreeMap.class, new FastClonerTreeMap());
-		fastCloners.put(ConcurrentHashMap.class, new FastClonerConcurrentHashMap());
-	}
-
-	protected Object fastClone(final Object o, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final Class<? extends Object> c = o.getClass();
-		final IFastCloner fastCloner = fastCloners.get(c);
-		if (fastCloner != null) return fastCloner.clone(o, this, clones);
-		return null;
-	}
-
-	public void registerConstant(final Object o)
-	{
-		ignoredInstances.put(o, true);
-	}
-
-	public void registerConstant(final Class<?> c, final String privateFieldName)
-	{
-		try
-		{
-			final Field field = c.getDeclaredField(privateFieldName);
-			field.setAccessible(true);
-			final Object v = field.get(null);
-			ignoredInstances.put(v, true);
-		} catch (final SecurityException e)
-		{
-			throw new RuntimeException(e);
-		} catch (final NoSuchFieldException e)
-		{
-			throw new RuntimeException(e);
-		} catch (final IllegalArgumentException e)
-		{
-			throw new RuntimeException(e);
-		} catch (final IllegalAccessException e)
-		{
-			throw new RuntimeException(e);
-		}
-	}
-
-	/**
-	 * registers some known JDK immutable classes. Override this to register your
-	 * own list of jdk's immutable classes
-	 */
-	protected void registerKnownJdkImmutableClasses()
-	{
-		registerImmutable(String.class);
-		registerImmutable(Integer.class);
-		registerImmutable(Long.class);
-		registerImmutable(Boolean.class);
-		registerImmutable(Class.class);
-		registerImmutable(Float.class);
-		registerImmutable(Double.class);
-		registerImmutable(Character.class);
-		registerImmutable(Byte.class);
-		registerImmutable(Short.class);
-		registerImmutable(Void.class);
-
-		registerImmutable(BigDecimal.class);
-		registerImmutable(BigInteger.class);
-		registerImmutable(URI.class);
-		registerImmutable(URL.class);
-		registerImmutable(UUID.class);
-		registerImmutable(Pattern.class);
-	}
-
-	protected void registerKnownConstants()
-	{
-		// registering known constants of the jdk.
-		registerStaticFields(TreeSet.class, HashSet.class, HashMap.class, TreeMap.class);
-	}
-
-	/**
-	 * registers all static fields of these classes. Those static fields won't be cloned when an instance
-	 * of the class is cloned.
-	 *
-	 * This is useful i.e. when a static field object is added into maps or sets. At that point, there is no
-	 * way for the cloner to know that it was static except if it is registered.
-	 *
-	 * @param classes		array of classes
-	 */
-	public void registerStaticFields(final Class<?>... classes)
-	{
-		for (final Class<?> c : classes)
-		{
-			final List<Field> fields = allFields(c);
-			for (final Field field : fields)
-			{
-				final int mods = field.getModifiers();
-				if (Modifier.isStatic(mods) && !field.getType().isPrimitive())
-				{
-					registerConstant(c, field.getName());
-				}
-			}
-		}
-	}
-
-	/**
-	 * spring framework friendly version of registerStaticFields
-	 * @param set		a set of classes which will be scanned for static fields
-	 */
-	public void setExtraStaticFields(final Set<Class<?>> set)
-	{
-		registerStaticFields((Class<?>[]) set.toArray());
-	}
-
-	/**
-	 * instances of classes that shouldn't be cloned can be registered using this method.
-	 *
-	 * @param c		The class that shouldn't be cloned. That is, whenever a deep clone for
-	 * 				an object is created and c is encountered, the object instance of c will
-	 * 				be added to the clone.
-	 */
-	public void dontClone(final Class<?>... c)
-	{
-		for (final Class<?> cl : c)
-		{
-			ignored.add(cl);
-		}
-	}
-	public boolean isIgnored(Class<?> clz)
-	{
-		for(final Class<?> c : ignored)
-		{
-			if (c.isAssignableFrom(clz))
-				return true;
-		}
-		return false;
-	}
-	public void dontCloneInstanceOf(final Class<?>... c)
-	{
-		for (final Class<?> cl : c)
-		{
-			ignoredInstanceOf.add(cl);
-		}
-	}
-
-	public void setDontCloneInstanceOf(final Class<?>... c)
-	{
-		dontCloneInstanceOf(c);
-	}
-
-	/**
-	 * instead of cloning these classes will set the field to null
-	 *
-	 * @param c		the classes to nullify during cloning
-	 */
-	public void nullInsteadOfClone(final Class<?>... c)
-	{
-		for (final Class<?> cl : c)
-		{
-			nullInstead.add(cl);
-		}
-	}
-
-	/**
-	 * spring framework friendly version of nullInsteadOfClone
-	 */
-	public void setExtraNullInsteadOfClone(final Set<Class<?>> set)
-	{
-		nullInstead.addAll(set);
-	}
-
-	/**
-	 * registers an immutable class. Immutable classes are not cloned.
-	 *
-	 * @param c			the immutable class
-	 */
-	public void registerImmutable(final Class<?>... c)
-	{
-		for (final Class<?> cl : c)
-		{
-			ignored.add(cl);
-		}
-	}
-
-	/**
-	 * spring framework friendly version of registerImmutable
-	 */
-	public void setExtraImmutables(final Set<Class<?>> set)
-	{
-		ignored.addAll(set);
-	}
-
-	public void registerFastCloner(final Class<?> c, final IFastCloner fastCloner)
-	{
-		if (fastCloners.containsKey(c)) throw new IllegalArgumentException(c + " already fast-cloned!");
-		fastCloners.put(c, fastCloner);
-	}
-
-	/**
-	 * creates a new instance of c. Override to provide your own implementation
-	 *
-	 * @param <T>		the type of c
-	 * @param c			the class
-	 * @return			a new instance of c
-	 */
-	protected <T> T newInstance(final Class<T> c)
-	{
-		return instantiationStrategy.newInstance(c);
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T> T fastCloneOrNewInstance(final Class<T> c)
-	{
-		try
-		{
-			final T fastClone = (T) fastClone(c, null);
-			if (fastClone != null) return fastClone;
-		} catch (final IllegalAccessException e)
-		{
-			throw new RuntimeException(e);
-		}
-		return newInstance(c);
-
-	}
-
-	/**
-	 * deep clones "o".
-	 *
-	 * @param <T>		the type of "o"
-	 * @param o			the object to be deep-cloned
-	 * @return			a deep-clone of "o".
-	 */
-	public <T> T deepClone(final T o)
-	{
-		if (o == null) return null;
-		if (!cloningEnabled) return o;
-		if (dumpClonedClasses)
-		{
-			System.out.println("start>" + o.getClass());
-		}
-		final Map<Object, Object> clones = new IdentityHashMap<Object, Object>(16);
-		try
-		{
-			return cloneInternal(o, clones);
-		} catch (final IllegalAccessException e)
-		{
-			throw new CloningException("error during cloning of " + o, e);
-		}
-	}
-
-	public <T> T deepCloneDontCloneInstances(final T o, final Object... dontCloneThese)
-	{
-		if (o == null) return null;
-		if (!cloningEnabled) return o;
-		if (dumpClonedClasses)
-		{
-			System.out.println("start>" + o.getClass());
-		}
-		final Map<Object, Object> clones = new IdentityHashMap<Object, Object>(16);
-		for (final Object dc : dontCloneThese)
-		{
-			clones.put(dc, dc);
-		}
-		try
-		{
-			return cloneInternal(o, clones);
-		} catch (final IllegalAccessException e)
-		{
-			throw new CloningException("error during cloning of " + o, e);
-		}
-	}
-
-	/**
-	 * shallow clones "o". This means that if c=shallowClone(o) then
-	 * c!=o. Any change to c won't affect o.
-	 *
-	 * @param <T>		the type of o
-	 * @param o			the object to be shallow-cloned
-	 * @return			a shallow clone of "o"
-	 */
-	public <T> T shallowClone(final T o)
-	{
-		if (o == null) return null;
-		if (!cloningEnabled) return o;
-		try
-		{
-			return cloneInternal(o, null);
-		} catch (final IllegalAccessException e)
-		{
-			throw new CloningException("error during cloning of " + o, e);
-		}
-	}
-
-	// caches immutables for quick reference
-	private final ConcurrentHashMap<Class<?>, Boolean>	immutables				= new ConcurrentHashMap<Class<?>, Boolean>();
-	private boolean										cloneAnonymousParent	= true;
-
-	/**
-	 * override this to decide if a class is immutable. Immutable classes are not cloned.
-	 *
-	 * @param clz		the class under check
-	 * @return			true to mark clz as immutable and skip cloning it
-	 */
-	protected boolean considerImmutable(final Class<?> clz)
-	{
-		return false;
-	}
-
-	protected Class<?> getImmutableAnnotation()
-	{
-		return Immutable.class;
-	}
-
-	/**
-	 * decides if a class is to be considered immutable or not
-	 *
-	 * @param clz		the class under check
-	 * @return			true if the clz is considered immutable
-	 */
-	private boolean isImmutable(final Class<?> clz)
-	{
-		if(
-				clz.getName().equals("java.util.HashSet")
-//clz.getName().startsWith("java.util")
-//&& !clz.getName().equals("java.util.HashMap")
-//&& !clz.getName().equals("java.util.LinkedHashMap")
-//&& !clz.getName().startsWith("java.util.Hashtable")
-//&& !clz.getName().equals("java.util.ArrayList")
-//&& !clz.getName().contains("Map")
-//&& ! clz.getName().startsWith("java.util.Collections")
-////&& !clz.getName().equals("java.util.HashSet") //bad
-//&& !clz.getName().startsWith("java.util.Linked")
-//&& !clz.getName().contains("Vector")
-//&& !clz.getName().equals("java.util.concurrent.CopyOnWriteArrayList")
-//&& !clz.getName().equals("java.util.Arrays$ArrayList")
-				)
-		{
-//				System.out.println(clz.getName());
-			return true;
-		}
-		final Boolean isIm = immutables.get(clz);
-		if (isIm != null) return isIm;
-		if (considerImmutable(clz)) return true;
-		return false;
-
-//		final Class<?> immutableAnnotation = getImmutableAnnotation();
-//		for (final Annotation annotation : clz.getDeclaredAnnotations())
-//		{
-//			if (annotation.annotationType() == immutableAnnotation)
-//			{
-//				immutables.put(clz, Boolean.TRUE);
-//				return true;
-//			}
-//		}
-//		Class<?> c = clz.getSuperclass();
-//		while (c != null && c != Object.class)
-//		{
-//			for (final Annotation annotation : c.getDeclaredAnnotations())
-//			{
-//				if (annotation.annotationType() == Immutable.class)
-//				{
-//					final Immutable im = (Immutable) annotation;
-//					if (im.subClass())
-//					{
-//						immutables.put(clz, Boolean.TRUE);
-//						return true;
-//					}
-//				}
-//			}
-//			c = c.getSuperclass();
-//		}
-//		immutables.put(clz, Boolean.FALSE);
-//		return false;
-	}
-
-	/**
-	 * PLEASE DONT CALL THIS METHOD
-	 * The only reason for been public is because custom IFastCloner's must invoke it
-	 */
-	@SuppressWarnings("unchecked")
-	public <T> T cloneInternal(final T o, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		if (o == null) return null;
-		if (o == this) return null;
-		if (ignoredInstances.containsKey(o)) return o;
-		final Class<T> clz = (Class<T>) o.getClass();
-		if (clz.isEnum()) return o;
-		// skip cloning ignored classes
-		if (nullInstead.contains(clz)) return null;
-		if (isIgnored(clz)) return o;
-		for (final Class<?> iClz : ignoredInstanceOf)
-		{
-			if (iClz.isAssignableFrom(clz)) return o;
-		}
-		if (isImmutable(clz)) return o;
-		if (o instanceof IFreezable)
-		{
-			final IFreezable f = (IFreezable) o;
-			if (f.isFrozen()) return o;
-		}
-		final Object clonedPreviously = clones != null ? clones.get(o) : null;
-		if (clonedPreviously != null) return (T) clonedPreviously;
-
-		final Object fastClone = fastClone(o, clones);
-		if (fastClone != null)
-		{
-			if (clones != null)
-			{
-				clones.put(o, fastClone);
-			}
-			return (T) fastClone;
-		}
-
-		if (dumpClonedClasses)
-		{
-			System.out.println("clone>" + clz);
-		}
-		if (clz.isArray())
-		{
-			final int length = Array.getLength(o);
-			final T newInstance = (T) Array.newInstance(clz.getComponentType(), length);
-			if (clones != null)
-			{
-				clones.put(o, newInstance);
-			}
-			for (int i = 0; i < length; i++)
-			{
-				final Object v = Array.get(o, i);
-				final Object clone = clones != null ? cloneInternal(v, clones) : v;
-				try{
-				Array.set(newInstance, i, clone);
-				}
-				catch(Exception ex)
-				{
-					Array.set(newInstance, i, v);
-				}
-			}
-			return newInstance;
-		}
-
-		final T newInstance = newInstance(clz);
-		if (clones != null)
-		{
-			clones.put(o, newInstance);
-		}
-		final List<Field> fields = allFields(clz);
-		for (final Field field : fields)
-		{
-			final int modifiers = field.getModifiers();
-			if (!Modifier.isStatic(modifiers))
-			{
-				if (nullTransient && Modifier.isTransient(modifiers))
-				{
-					// request by Jonathan : transient fields can be null-ed
-					final Class<?> type = field.getType();
-					if (!type.isPrimitive())
-					{
-						field.set(newInstance, null);
-					}
-				} else
-				{
-					final Object fieldObject = field.get(o);
-					final boolean shouldClone = (cloneSynthetics || (!cloneSynthetics && !field.isSynthetic())) && (cloneAnonymousParent || ((!cloneAnonymousParent && !isAnonymousParent(field))));
-					final Object fieldObjectClone = clones != null ? (shouldClone ? cloneInternal(fieldObject, clones) : fieldObject) : fieldObject;
-					try
-					{
-						field.set(newInstance, fieldObjectClone);
-					}
-					catch(Exception ex)
-					{
-//						ex.printStackTrace();
-//						System.exit(-1);
-					}
-					if (dumpClonedClasses && fieldObjectClone != fieldObject)
-					{
-						System.out.println("cloned field>" + field + "  -- of class " + o.getClass());
-					}
-				}
-			}
-		}
-		return newInstance;
-	}
-
-	private boolean isAnonymousParent(final Field field)
-	{
-		return "this$0".equals(field.getName());
-	}
-
-	/**
-	 * copies all properties from src to dest. Src and dest can be of different class, provided they contain same field names/types
-	 *
-	 * @param src		the source object
-	 * @param dest		the destination object which must contain as minimum all the fields of src
-	 */
-	public <T, E extends T> void copyPropertiesOfInheritedClass(final T src, final E dest)
-	{
-		if (src == null) throw new IllegalArgumentException("src can't be null");
-		if (dest == null) throw new IllegalArgumentException("dest can't be null");
-		final Class<? extends Object> srcClz = src.getClass();
-		final Class<? extends Object> destClz = dest.getClass();
-		if (srcClz.isArray())
-		{
-			if (!destClz.isArray()) throw new IllegalArgumentException("can't copy from array to non-array class " + destClz);
-			final int length = Array.getLength(src);
-			for (int i = 0; i < length; i++)
-			{
-				final Object v = Array.get(src, i);
-				Array.set(dest, i, v);
-			}
-			return;
-		}
-		final List<Field> fields = allFields(srcClz);
-		final List<Field> destFields = allFields(dest.getClass());
-		for (final Field field : fields)
-		{
-			if (!Modifier.isStatic(field.getModifiers()))
-			{
-				try
-				{
-					final Object fieldObject = field.get(src);
-					field.setAccessible(true);
-					if (destFields.contains(field))
-					{
-						field.set(dest, fieldObject);
-					}
-				} catch (final IllegalArgumentException e)
-				{
-					throw new RuntimeException(e);
-				} catch (final IllegalAccessException e)
-				{
-					throw new RuntimeException(e);
-				}
-			}
-		}
-	}
-
-	/**
-	 * reflection utils
-	 */
-	private void addAll(final List<Field> l, final Field[] fields)
-	{
-		for (final Field field : fields)
-		{
-			if (!field.isAccessible())
-			{
-				field.setAccessible(true);
-			}
-			l.add(field);
-		}
-	}
-
-	/**
-	 * reflection utils, override this to choose which fields to clone
-	 */
-	protected List<Field> allFields(final Class<?> c)
-	{
-		List<Field> l = fieldsCache.get(c);
-		if (l == null)
-		{
-			l = new LinkedList<Field>();
-			final Field[] fields = c.getDeclaredFields();
-			addAll(l, fields);
-			Class<?> sc = c;
-			while ((sc = sc.getSuperclass()) != Object.class && sc != null)
-			{
-				addAll(l, sc.getDeclaredFields());
-			}
-			fieldsCache.putIfAbsent(c, l);
-		}
-		return l;
-	}
-
-	public boolean isDumpClonedClasses()
-	{
-		return dumpClonedClasses;
-	}
-
-	/**
-	 * will println() all cloned classes. Useful for debugging only.
-	 *
-	 * @param dumpClonedClasses			true to enable printing all cloned classes
-	 */
-	public void setDumpClonedClasses(final boolean dumpClonedClasses)
-	{
-		this.dumpClonedClasses = dumpClonedClasses;
-	}
-
-	public boolean isCloningEnabled()
-	{
-		return cloningEnabled;
-	}
-
-	public void setCloningEnabled(final boolean cloningEnabled)
-	{
-		this.cloningEnabled = cloningEnabled;
-	}
-
-	/**
-	 * if false, anonymous classes parent class won't be cloned. Default is true
-	 */
-	public void setCloneAnonymousParent(final boolean cloneAnonymousParent)
-	{
-		this.cloneAnonymousParent = cloneAnonymousParent;
-	}
-
-	public boolean isCloneAnonymousParent()
-	{
-		return cloneAnonymousParent;
-	}
+public class Cloner {
+    private final IInstantiationStrategy instantiationStrategy;
+
+    private final Set<Class<?>> ignored = new HashSet<Class<?>>();
+
+    private final Set<Class<?>> ignoredInstanceOf = new HashSet<Class<?>>();
+
+    private final Set<Class<?>> nullInstead = new HashSet<Class<?>>();
+
+    private final Map<Class<?>, IFastCloner> fastCloners = new HashMap<Class<?>, IFastCloner>();
+
+    private final Map<Object, Boolean> ignoredInstances = new IdentityHashMap<Object, Boolean>();
+
+    private final ConcurrentHashMap<Class<?>, List<Field>> fieldsCache = new ConcurrentHashMap<Class<?>, List<Field>>();
+
+    private boolean dumpClonedClasses = false;
+
+    private boolean cloningEnabled = true;
+
+    private boolean nullTransient = false;
+
+    private boolean cloneSynthetics = true;
+
+    private boolean dumpCloneStatistics = true;
+
+    private final static HashMap<Class<?>, Long> timePerClass = new HashMap<>();
+
+    public Cloner() {
+        this.instantiationStrategy = ObjenesisInstantiationStrategy.getInstance();
+        init();
+    }
+
+    public Cloner(final IInstantiationStrategy instantiationStrategy) {
+        this.instantiationStrategy = instantiationStrategy;
+        init();
+    }
+
+    public boolean isNullTransient() {
+        return nullTransient;
+    }
+
+    /**
+     * this makes the cloner to set a transient field to null upon cloning.
+     * NOTE: primitive types can't be nulled. Their value will be set to
+     * default, i.e. 0 for int
+     *
+     * @param nullTransient true for transient fields to be nulled
+     */
+    public void setNullTransient(final boolean nullTransient) {
+        this.nullTransient = nullTransient;
+    }
+
+    public void setCloneSynthetics(final boolean cloneSynthetics) {
+        this.cloneSynthetics = cloneSynthetics;
+    }
+
+    private void init() {
+        registerKnownJdkImmutableClasses();
+        registerKnownConstants();
+        registerFastCloners();
+    }
+
+    /**
+     * registers a std set of fast cloners.
+     */
+    protected void registerFastCloners() {
+        fastCloners.put(GregorianCalendar.class, new FastClonerCalendar());
+        fastCloners.put(ArrayList.class, new FastClonerArrayList());
+        fastCloners.put(LinkedList.class, new FastClonerLinkedList());
+        fastCloners.put(HashSet.class, new FastClonerHashSet());
+        fastCloners.put(HashMap.class, new FastClonerHashMap());
+        fastCloners.put(TreeMap.class, new FastClonerTreeMap());
+        fastCloners.put(ConcurrentHashMap.class, new FastClonerConcurrentHashMap());
+    }
+
+    protected Object fastClone(final Object o, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final Class<? extends Object> c = o.getClass();
+        final IFastCloner fastCloner = fastCloners.get(c);
+        if (fastCloner != null)
+            return fastCloner.clone(o, this, clones);
+        return null;
+    }
+
+    public void registerConstant(final Object o) {
+        ignoredInstances.put(o, true);
+    }
+
+    public void registerConstant(final Class<?> c, final String privateFieldName) {
+        try {
+            final Field field = c.getDeclaredField(privateFieldName);
+            field.setAccessible(true);
+            final Object v = field.get(null);
+            ignoredInstances.put(v, true);
+        } catch (final SecurityException e) {
+            throw new RuntimeException(e);
+        } catch (final NoSuchFieldException e) {
+            throw new RuntimeException(e);
+        } catch (final IllegalArgumentException e) {
+            throw new RuntimeException(e);
+        } catch (final IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * registers some known JDK immutable classes. Override this to register
+     * your own list of jdk's immutable classes
+     */
+    protected void registerKnownJdkImmutableClasses() {
+        registerImmutable(String.class);
+        registerImmutable(Integer.class);
+        registerImmutable(Long.class);
+        registerImmutable(Boolean.class);
+        registerImmutable(Class.class);
+        registerImmutable(Float.class);
+        registerImmutable(Double.class);
+        registerImmutable(Character.class);
+        registerImmutable(Byte.class);
+        registerImmutable(Short.class);
+        registerImmutable(Void.class);
+
+        registerImmutable(BigDecimal.class);
+        registerImmutable(BigInteger.class);
+        registerImmutable(URI.class);
+        registerImmutable(URL.class);
+        registerImmutable(UUID.class);
+        registerImmutable(Pattern.class);
+    }
+
+    protected void registerKnownConstants() {
+        // registering known constants of the jdk.
+        registerStaticFields(TreeSet.class, HashSet.class, HashMap.class, TreeMap.class);
+    }
+
+    /**
+     * registers all static fields of these classes. Those static fields won't
+     * be cloned when an instance of the class is cloned. This is useful i.e.
+     * when a static field object is added into maps or sets. At that point,
+     * there is no way for the cloner to know that it was static except if it is
+     * registered.
+     *
+     * @param classes array of classes
+     */
+    public void registerStaticFields(final Class<?>... classes) {
+        for (final Class<?> c : classes) {
+            final List<Field> fields = allFields(c);
+            for (final Field field : fields) {
+                final int mods = field.getModifiers();
+                if (Modifier.isStatic(mods) && !field.getType().isPrimitive()) {
+                    registerConstant(c, field.getName());
+                }
+            }
+        }
+    }
+
+    /**
+     * spring framework friendly version of registerStaticFields
+     *
+     * @param set a set of classes which will be scanned for static fields
+     */
+    public void setExtraStaticFields(final Set<Class<?>> set) {
+        registerStaticFields((Class<?>[]) set.toArray());
+    }
+
+    /**
+     * instances of classes that shouldn't be cloned can be registered using
+     * this method.
+     *
+     * @param c The class that shouldn't be cloned. That is, whenever a deep
+     *            clone for an object is created and c is encountered, the
+     *            object instance of c will be added to the clone.
+     */
+    public void dontClone(final Class<?>... c) {
+        for (final Class<?> cl : c) {
+            ignored.add(cl);
+        }
+    }
+
+    public boolean isIgnored(Class<?> clz) {
+        for (final Class<?> c : ignored) {
+            if (c.isAssignableFrom(clz))
+                return true;
+        }
+        return false;
+    }
+
+    public void dontCloneInstanceOf(final Class<?>... c) {
+        for (final Class<?> cl : c) {
+            ignoredInstanceOf.add(cl);
+        }
+    }
+
+    public void setDontCloneInstanceOf(final Class<?>... c) {
+        dontCloneInstanceOf(c);
+    }
+
+    /**
+     * instead of cloning these classes will set the field to null
+     *
+     * @param c the classes to nullify during cloning
+     */
+    public void nullInsteadOfClone(final Class<?>... c) {
+        for (final Class<?> cl : c) {
+            nullInstead.add(cl);
+        }
+    }
+
+    /**
+     * spring framework friendly version of nullInsteadOfClone
+     */
+    public void setExtraNullInsteadOfClone(final Set<Class<?>> set) {
+        nullInstead.addAll(set);
+    }
+
+    /**
+     * registers an immutable class. Immutable classes are not cloned.
+     *
+     * @param c the immutable class
+     */
+    public void registerImmutable(final Class<?>... c) {
+        for (final Class<?> cl : c) {
+            ignored.add(cl);
+        }
+    }
+
+    /**
+     * spring framework friendly version of registerImmutable
+     */
+    public void setExtraImmutables(final Set<Class<?>> set) {
+        ignored.addAll(set);
+    }
+
+    public void registerFastCloner(final Class<?> c, final IFastCloner fastCloner) {
+        if (fastCloners.containsKey(c))
+            throw new IllegalArgumentException(c + " already fast-cloned!");
+        fastCloners.put(c, fastCloner);
+    }
+
+    /**
+     * creates a new instance of c. Override to provide your own implementation
+     *
+     * @param <T> the type of c
+     * @param c the class
+     * @return a new instance of c
+     */
+    protected <T> T newInstance(final Class<T> c) {
+        return instantiationStrategy.newInstance(c);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T fastCloneOrNewInstance(final Class<T> c) {
+        try {
+            final T fastClone = (T) fastClone(c, null);
+            if (fastClone != null)
+                return fastClone;
+        } catch (final IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+        return newInstance(c);
+
+    }
+
+    /**
+     * deep clones "o".
+     *
+     * @param <T> the type of "o"
+     * @param o the object to be deep-cloned
+     * @return a deep-clone of "o".
+     */
+    public <T> T deepClone(final T o) {
+        if (o == null)
+            return null;
+        if (!cloningEnabled)
+            return o;
+        if (dumpClonedClasses) {
+            System.out.println("start>" + o.getClass());
+        }
+        final Map<Object, Object> clones = new IdentityHashMap<Object, Object>(16);
+        try {
+            return cloneInternal(o, clones);
+        } catch (final IllegalAccessException e) {
+            throw new CloningException("error during cloning of " + o, e);
+        }
+    }
+
+    public <T> T deepCloneDontCloneInstances(final T o, final Object... dontCloneThese) {
+        if (o == null)
+            return null;
+        if (!cloningEnabled)
+            return o;
+        if (dumpClonedClasses) {
+            System.out.println("start>" + o.getClass());
+        }
+        final Map<Object, Object> clones = new IdentityHashMap<Object, Object>(16);
+        for (final Object dc : dontCloneThese) {
+            clones.put(dc, dc);
+        }
+        try {
+            return cloneInternal(o, clones);
+        } catch (final IllegalAccessException e) {
+            throw new CloningException("error during cloning of " + o, e);
+        }
+    }
+
+    /**
+     * shallow clones "o". This means that if c=shallowClone(o) then c!=o. Any
+     * change to c won't affect o.
+     *
+     * @param <T> the type of o
+     * @param o the object to be shallow-cloned
+     * @return a shallow clone of "o"
+     */
+    public <T> T shallowClone(final T o) {
+        if (o == null)
+            return null;
+        if (!cloningEnabled)
+            return o;
+        try {
+            return cloneInternal(o, null);
+        } catch (final IllegalAccessException e) {
+            throw new CloningException("error during cloning of " + o, e);
+        }
+    }
+
+    // caches immutables for quick reference
+    private final ConcurrentHashMap<Class<?>, Boolean> immutables = new ConcurrentHashMap<Class<?>, Boolean>();
+
+    private boolean cloneAnonymousParent = true;
+
+    /**
+     * override this to decide if a class is immutable. Immutable classes are
+     * not cloned.
+     *
+     * @param clz the class under check
+     * @return true to mark clz as immutable and skip cloning it
+     */
+    protected boolean considerImmutable(final Class<?> clz) {
+        return false;
+    }
+
+    protected Class<?> getImmutableAnnotation() {
+        return Immutable.class;
+    }
+
+    /**
+     * decides if a class is to be considered immutable or not
+     *
+     * @param clz the class under check
+     * @return true if the clz is considered immutable
+     */
+    private boolean isImmutable(final Class<?> clz) {
+        if (clz.getName().equals("java.util.HashSet")
+        // clz.getName().startsWith("java.util")
+        // && !clz.getName().equals("java.util.HashMap")
+        // && !clz.getName().equals("java.util.LinkedHashMap")
+        // && !clz.getName().startsWith("java.util.Hashtable")
+        // && !clz.getName().equals("java.util.ArrayList")
+        // && !clz.getName().contains("Map")
+        // && ! clz.getName().startsWith("java.util.Collections")
+        // //&& !clz.getName().equals("java.util.HashSet") //bad
+        // && !clz.getName().startsWith("java.util.Linked")
+        // && !clz.getName().contains("Vector")
+        // && !clz.getName().equals("java.util.concurrent.CopyOnWriteArrayList")
+        // && !clz.getName().equals("java.util.Arrays$ArrayList")
+        ) {
+            // System.out.println(clz.getName());
+            return true;
+        }
+        final Boolean isIm = immutables.get(clz);
+        if (isIm != null)
+            return isIm;
+        if (considerImmutable(clz))
+            return true;
+
+        Class<?> c = clz.getSuperclass();
+        while (c != null && c != Object.class) {
+            final Boolean ret = immutables.get(c);
+            if (ret != null && ret != false) {
+                immutables.put(clz, Boolean.TRUE);
+                return true;
+            }
+            c = c.getSuperclass();
+        }
+        immutables.put(clz, Boolean.FALSE);
+        return false;
+    }
+
+    /**
+     * PLEASE DONT CALL THIS METHOD The only reason for been public is because
+     * custom IFastCloner's must invoke it
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T cloneInternal(final T o, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        if (o == null)
+            return null;
+        if (o == this)
+            return null;
+        if (ignoredInstances.containsKey(o))
+            return o;
+        final Class<T> clz = (Class<T>) o.getClass();
+        if (clz.isEnum())
+            return o;
+        // skip cloning ignored classes
+        if (nullInstead.contains(clz))
+            return null;
+        if (isIgnored(clz))
+            return o;
+        for (final Class<?> iClz : ignoredInstanceOf) {
+            if (iClz.isAssignableFrom(clz))
+                return o;
+        }
+        if (isImmutable(clz))
+            return o;
+        if (o instanceof IFreezable) {
+            final IFreezable f = (IFreezable) o;
+            if (f.isFrozen())
+                return o;
+        }
+        final Object clonedPreviously = clones != null ? clones.get(o) : null;
+        if (clonedPreviously != null)
+            return (T) clonedPreviously;
+
+        final Object fastClone = fastClone(o, clones);
+        if (fastClone != null) {
+            if (clones != null) {
+                clones.put(o, fastClone);
+            }
+            return (T) fastClone;
+        }
+        long start = 0L;
+        if (dumpCloneStatistics)
+            start = System.currentTimeMillis();
+        if (dumpClonedClasses) {
+            System.out.println("clone>" + clz);
+        }
+        if (clz.isArray()) {
+            final int length = Array.getLength(o);
+            final T newInstance = (T) Array.newInstance(clz.getComponentType(), length);
+            if (clones != null) {
+                clones.put(o, newInstance);
+            }
+            for (int i = 0; i < length; i++) {
+                final Object v = Array.get(o, i);
+                final Object clone = clones != null ? cloneInternal(v, clones) : v;
+                try {
+                    Array.set(newInstance, i, clone);
+                } catch (Exception ex) {
+                    Array.set(newInstance, i, v);
+                }
+            }
+            return newInstance;
+        }
+
+        final T newInstance = newInstance(clz);
+        if (clones != null) {
+            clones.put(o, newInstance);
+        }
+        final List<Field> fields = allFields(clz);
+        for (final Field field : fields) {
+            final int modifiers = field.getModifiers();
+            if (!Modifier.isStatic(modifiers)) {
+                if (nullTransient && Modifier.isTransient(modifiers)) {
+                    // request by Jonathan : transient fields can be null-ed
+                    final Class<?> type = field.getType();
+                    if (!type.isPrimitive()) {
+                        field.set(newInstance, null);
+                    }
+                } else {
+                    final Object fieldObject = field.get(o);
+                    final boolean shouldClone = (cloneSynthetics || (!cloneSynthetics && !field
+                            .isSynthetic()))
+                            && (cloneAnonymousParent || ((!cloneAnonymousParent && !isAnonymousParent(field))));
+                    final Object fieldObjectClone = clones != null ? (shouldClone ? cloneInternal(
+                            fieldObject, clones) : fieldObject) : fieldObject;
+                    try {
+                        field.set(newInstance, fieldObjectClone);
+                    } catch (Exception ex) {
+                        // ex.printStackTrace();
+                        // System.exit(-1);
+                    }
+                    if (dumpClonedClasses && fieldObjectClone != fieldObject) {
+                        System.out.println("cloned field>" + field + "  -- of class "
+                                + o.getClass());
+                    }
+                }
+            }
+        }
+        if (dumpCloneStatistics) {
+            long end = System.currentTimeMillis();
+
+            if (!timePerClass.containsKey(clz))
+                timePerClass.put(clz, 0L);
+            timePerClass.put(clz, timePerClass.get(clz) + (end - start));
+        }
+        return newInstance;
+    }
+
+    public static void printStatistics() {
+        for (Class<?> c : timePerClass.keySet()) {
+            System.out.println(((timePerClass.get(c) / 1000) + "\t" + c.getName()));
+        }
+    }
+
+    private boolean isAnonymousParent(final Field field) {
+        return "this$0".equals(field.getName());
+    }
+
+    /**
+     * copies all properties from src to dest. Src and dest can be of different
+     * class, provided they contain same field names/types
+     *
+     * @param src the source object
+     * @param dest the destination object which must contain as minimum all the
+     *            fields of src
+     */
+    public <T, E extends T> void copyPropertiesOfInheritedClass(final T src, final E dest) {
+        if (src == null)
+            throw new IllegalArgumentException("src can't be null");
+        if (dest == null)
+            throw new IllegalArgumentException("dest can't be null");
+        final Class<? extends Object> srcClz = src.getClass();
+        final Class<? extends Object> destClz = dest.getClass();
+        if (srcClz.isArray()) {
+            if (!destClz.isArray())
+                throw new IllegalArgumentException("can't copy from array to non-array class "
+                        + destClz);
+            final int length = Array.getLength(src);
+            for (int i = 0; i < length; i++) {
+                final Object v = Array.get(src, i);
+                Array.set(dest, i, v);
+            }
+            return;
+        }
+        final List<Field> fields = allFields(srcClz);
+        final List<Field> destFields = allFields(dest.getClass());
+        for (final Field field : fields) {
+            if (!Modifier.isStatic(field.getModifiers())) {
+                try {
+                    final Object fieldObject = field.get(src);
+                    field.setAccessible(true);
+                    if (destFields.contains(field)) {
+                        field.set(dest, fieldObject);
+                    }
+                } catch (final IllegalArgumentException e) {
+                    throw new RuntimeException(e);
+                } catch (final IllegalAccessException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * reflection utils
+     */
+    private void addAll(final List<Field> l, final Field[] fields) {
+        for (final Field field : fields) {
+            if (!field.isAccessible()) {
+                field.setAccessible(true);
+            }
+            l.add(field);
+        }
+    }
+
+    /**
+     * reflection utils, override this to choose which fields to clone
+     */
+    protected List<Field> allFields(final Class<?> c) {
+        List<Field> l = fieldsCache.get(c);
+        if (l == null) {
+            l = new LinkedList<Field>();
+            final Field[] fields = c.getDeclaredFields();
+            addAll(l, fields);
+            Class<?> sc = c;
+            while ((sc = sc.getSuperclass()) != Object.class && sc != null) {
+                addAll(l, sc.getDeclaredFields());
+            }
+            fieldsCache.putIfAbsent(c, l);
+        }
+        return l;
+    }
+
+    public boolean isDumpClonedClasses() {
+        return dumpClonedClasses;
+    }
+
+    /**
+     * will println() all cloned classes. Useful for debugging only.
+     *
+     * @param dumpClonedClasses true to enable printing all cloned classes
+     */
+    public void setDumpClonedClasses(final boolean dumpClonedClasses) {
+        this.dumpClonedClasses = dumpClonedClasses;
+    }
+
+    public boolean isCloningEnabled() {
+        return cloningEnabled;
+    }
+
+    public void setCloningEnabled(final boolean cloningEnabled) {
+        this.cloningEnabled = cloningEnabled;
+    }
+
+    /**
+     * if false, anonymous classes parent class won't be cloned. Default is true
+     */
+    public void setCloneAnonymousParent(final boolean cloneAnonymousParent) {
+        this.cloneAnonymousParent = cloneAnonymousParent;
+    }
+
+    public boolean isCloneAnonymousParent() {
+        return cloneAnonymousParent;
+    }
+
+    public void setDumpCloneStatistics(boolean dumpCloneStatistics) {
+        this.dumpCloneStatistics = dumpCloneStatistics;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        if (dumpCloneStatistics)
+            Cloner.printStatistics();
+        super.finalize();
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/CloningException.java b/Code/ChroniclerJ/src/com/rits/cloning/CloningException.java
index 09b2678..2e03bbd 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/CloningException.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/CloningException.java
@@ -1,20 +1,17 @@
+
 package com.rits.cloning;

 /**
  * thrown if cloning fails
  *
- * @author kostantinos.kougios
- *
- * 18 Jan 2009
+ * @author kostantinos.kougios 18 Jan 2009
  */
-public class CloningException extends RuntimeException
-{
-	private static final long	serialVersionUID	= 3815175312001146867L;
+public class CloningException extends RuntimeException {
+    private static final long serialVersionUID = 3815175312001146867L;

-	public CloningException(final String message, final Throwable cause)
-	{
-		super(message, cause);
+    public CloningException(final String message, final Throwable cause) {
+        super(message, cause);

-	}
+    }

 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerArrayList.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerArrayList.java
index b9dc489..177a092 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerArrayList.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerArrayList.java
@@ -1,26 +1,25 @@
+
 package com.rits.cloning;

 import java.util.ArrayList;
 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public class FastClonerArrayList implements IFastCloner
-{
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final ArrayList al = (ArrayList) t;
-		final ArrayList l = new ArrayList();
-		for (final Object o : al)
-		{
-			final Object cloneInternal = cloner.cloneInternal(o, clones);
-			l.add(cloneInternal);
-		}
-		return l;
-	}
+public class FastClonerArrayList implements IFastCloner {
+    @SuppressWarnings({
+            "unchecked", "rawtypes"
+    })
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final ArrayList al = (ArrayList) t;
+        final ArrayList l = new ArrayList();
+        for (final Object o : al) {
+            final Object cloneInternal = cloner.cloneInternal(o, clones);
+            l.add(cloneInternal);
+        }
+        return l;
+    }

 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCalendar.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCalendar.java
index 9870fd9..7d337c3 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCalendar.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCalendar.java
@@ -1,19 +1,16 @@
+
 package com.rits.cloning;

 import java.util.GregorianCalendar;
 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public class FastClonerCalendar implements IFastCloner
-{
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
-	{
-		final GregorianCalendar gc = new GregorianCalendar();
-		gc.setTimeInMillis(((GregorianCalendar) t).getTimeInMillis());
-		return gc;
-	}
+public class FastClonerCalendar implements IFastCloner {
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) {
+        final GregorianCalendar gc = new GregorianCalendar();
+        gc.setTimeInMillis(((GregorianCalendar) t).getTimeInMillis());
+        return gc;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerConcurrentHashMap.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerConcurrentHashMap.java
index e49a907..e68533e 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerConcurrentHashMap.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerConcurrentHashMap.java
@@ -1,27 +1,26 @@
+
 package com.rits.cloning;

 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;

 /**
- * @author kostantinos.kougios
- *
- * 18 Oct 2011
+ * @author kostantinos.kougios 18 Oct 2011
  */
-public class FastClonerConcurrentHashMap implements IFastCloner
-{
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final ConcurrentHashMap<Object, Object> m = (ConcurrentHashMap) t;
-		final ConcurrentHashMap result = new ConcurrentHashMap();
-		for (final Map.Entry e : m.entrySet())
-		{
-			final Object key = cloner.cloneInternal(e.getKey(), clones);
-			final Object value = cloner.cloneInternal(e.getValue(), clones);
-			if (key != null && value != null)
-				result.put(key, value);
-		}
-		return result;
-	}
+public class FastClonerConcurrentHashMap implements IFastCloner {
+    @SuppressWarnings({
+            "unchecked", "rawtypes"
+    })
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final ConcurrentHashMap<Object, Object> m = (ConcurrentHashMap) t;
+        final ConcurrentHashMap result = new ConcurrentHashMap();
+        for (final Map.Entry e : m.entrySet()) {
+            final Object key = cloner.cloneInternal(e.getKey(), clones);
+            final Object value = cloner.cloneInternal(e.getValue(), clones);
+            if (key != null && value != null)
+                result.put(key, value);
+        }
+        return result;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomCollection.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomCollection.java
index 393c01e..ecd3fc0 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomCollection.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomCollection.java
@@ -1,27 +1,26 @@
+
 package com.rits.cloning;

 import java.util.Collection;
 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-@SuppressWarnings({ "unchecked", "rawtypes" })
-public abstract class FastClonerCustomCollection<T extends Collection> implements IFastCloner
-{
-	public abstract T getInstance(T o);
+@SuppressWarnings({
+        "unchecked", "rawtypes"
+})
+public abstract class FastClonerCustomCollection<T extends Collection> implements IFastCloner {
+    public abstract T getInstance(T o);

-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final T c = getInstance((T) t);
-		final T l = (T) t;
-		for (final Object o : l)
-		{
-			final Object clone = cloner.cloneInternal(o, clones);
-			c.add(clone);
-		}
-		return c;
-	}
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final T c = getInstance((T) t);
+        final T l = (T) t;
+        for (final Object o : l) {
+            final Object clone = cloner.cloneInternal(o, clones);
+            c.add(clone);
+        }
+        return c;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomMap.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomMap.java
index f42b8fe..3ff0725 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomMap.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerCustomMap.java
@@ -1,29 +1,28 @@
+
 package com.rits.cloning;

 import java.util.Map;
 import java.util.Set;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-@SuppressWarnings({ "unchecked", "rawtypes" })
-public abstract class FastClonerCustomMap<T extends Map> implements IFastCloner
-{
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final T m = (T) t;
-		final T result = getInstance((T) t);
-		final Set<Map.Entry<Object, Object>> entrySet = m.entrySet();
-		for (final Map.Entry e : entrySet)
-		{
-			final Object key = cloner.cloneInternal(e.getKey(), clones);
-			final Object value = cloner.cloneInternal(e.getValue(), clones);
-			result.put(key, value);
-		}
-		return result;
-	}
+@SuppressWarnings({
+        "unchecked", "rawtypes"
+})
+public abstract class FastClonerCustomMap<T extends Map> implements IFastCloner {
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final T m = (T) t;
+        final T result = getInstance((T) t);
+        final Set<Map.Entry<Object, Object>> entrySet = m.entrySet();
+        for (final Map.Entry e : entrySet) {
+            final Object key = cloner.cloneInternal(e.getKey(), clones);
+            final Object value = cloner.cloneInternal(e.getValue(), clones);
+            result.put(key, value);
+        }
+        return result;
+    }

-	protected abstract T getInstance(T t);
+    protected abstract T getInstance(T t);
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashMap.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashMap.java
index 3fa059c..4cd8de9 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashMap.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashMap.java
@@ -1,35 +1,31 @@
+
 package com.rits.cloning;

 import java.util.HashMap;
 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public class FastClonerHashMap implements IFastCloner
-{
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		try {
-
+public class FastClonerHashMap implements IFastCloner {
+    @SuppressWarnings({
+            "unchecked", "rawtypes"
+    })
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        try {

-		final HashMap<Object, Object> m = (HashMap) t;
-		final HashMap result = new HashMap();
-		for (final Map.Entry e : m.entrySet())
-		{
-			final Object key = cloner.cloneInternal(e.getKey(), clones);
-			final Object value = cloner.cloneInternal(e.getValue(), clones);
+            final HashMap<Object, Object> m = (HashMap) t;
+            final HashMap result = new HashMap();
+            for (final Map.Entry e : m.entrySet()) {
+                final Object key = cloner.cloneInternal(e.getKey(), clones);
+                final Object value = cloner.cloneInternal(e.getValue(), clones);

-			result.put(key, value);
-		}
-		return result;
-		}
-		catch(Exception ex)
-		{
-			return null;
-		}
-	}
+                result.put(key, value);
+            }
+            return result;
+        } catch (Exception ex) {
+            return null;
+        }
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashSet.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashSet.java
index 519d71a..c234e93 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashSet.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerHashSet.java
@@ -1,26 +1,25 @@
+
 package com.rits.cloning;

 import java.util.HashSet;
 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public class FastClonerHashSet implements IFastCloner
-{
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final HashSet al = (HashSet) t;
-		final HashSet l = new HashSet();
-		for (final Object o : al)
-		{
-			final Object cloneInternal = cloner.cloneInternal(o, clones);
-			if(cloneInternal != null)
-				l.add(cloneInternal);
-		}
-		return l;
-	}
+public class FastClonerHashSet implements IFastCloner {
+    @SuppressWarnings({
+            "unchecked", "rawtypes"
+    })
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final HashSet al = (HashSet) t;
+        final HashSet l = new HashSet();
+        for (final Object o : al) {
+            final Object cloneInternal = cloner.cloneInternal(o, clones);
+            if (cloneInternal != null)
+                l.add(cloneInternal);
+        }
+        return l;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerLinkedList.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerLinkedList.java
index b9dfbcf..2c6696b 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerLinkedList.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerLinkedList.java
@@ -1,25 +1,24 @@
+
 package com.rits.cloning;

 import java.util.LinkedList;
 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public class FastClonerLinkedList implements IFastCloner
-{
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final LinkedList al = (LinkedList) t;
-		final LinkedList l = new LinkedList();
-		for (final Object o : al)
-		{
-			final Object cloneInternal = cloner.cloneInternal(o, clones);
-			l.add(cloneInternal);
-		}
-		return l;
-	}
+public class FastClonerLinkedList implements IFastCloner {
+    @SuppressWarnings({
+            "unchecked", "rawtypes"
+    })
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final LinkedList al = (LinkedList) t;
+        final LinkedList l = new LinkedList();
+        for (final Object o : al) {
+            final Object cloneInternal = cloner.cloneInternal(o, clones);
+            l.add(cloneInternal);
+        }
+        return l;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerTreeMap.java b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerTreeMap.java
index 6ba46cf..571cf5d 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/FastClonerTreeMap.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/FastClonerTreeMap.java
@@ -1,26 +1,25 @@
+
 package com.rits.cloning;

 import java.util.Map;
 import java.util.TreeMap;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public class FastClonerTreeMap implements IFastCloner
-{
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones) throws IllegalAccessException
-	{
-		final TreeMap<Object, Object> m = (TreeMap) t;
-		final TreeMap result = new TreeMap(m.comparator());
-		for (final Map.Entry e : m.entrySet())
-		{
-			final Object key = cloner.cloneInternal(e.getKey(), clones);
-			final Object value = cloner.cloneInternal(e.getValue(), clones);
-			result.put(key, value);
-		}
-		return result;
-	}
+public class FastClonerTreeMap implements IFastCloner {
+    @SuppressWarnings({
+            "unchecked", "rawtypes"
+    })
+    public Object clone(final Object t, final Cloner cloner, final Map<Object, Object> clones)
+            throws IllegalAccessException {
+        final TreeMap<Object, Object> m = (TreeMap) t;
+        final TreeMap result = new TreeMap(m.comparator());
+        for (final Map.Entry e : m.entrySet()) {
+            final Object key = cloner.cloneInternal(e.getKey(), clones);
+            final Object value = cloner.cloneInternal(e.getValue(), clones);
+            result.put(key, value);
+        }
+        return result;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/IFastCloner.java b/Code/ChroniclerJ/src/com/rits/cloning/IFastCloner.java
index aca7c87..f56b1b8 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/IFastCloner.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/IFastCloner.java
@@ -1,13 +1,12 @@
+
 package com.rits.cloning;

 import java.util.Map;

 /**
- * @author kostantinos.kougios
- *
- * 21 May 2009
+ * @author kostantinos.kougios 21 May 2009
  */
-public interface IFastCloner
-{
-	public Object clone(Object t, Cloner cloner, Map<Object, Object> clones) throws IllegalAccessException;
+public interface IFastCloner {
+    public Object clone(Object t, Cloner cloner, Map<Object, Object> clones)
+            throws IllegalAccessException;
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/IFreezable.java b/Code/ChroniclerJ/src/com/rits/cloning/IFreezable.java
index 7308583..556610c 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/IFreezable.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/IFreezable.java
@@ -1,12 +1,10 @@
+
 package com.rits.cloning;

 /**
- * @author kostantinos.kougios
- *
- * 15 Nov 2010
+ * @author kostantinos.kougios 15 Nov 2010
  */
-public interface IFreezable
-{
-	public boolean isFrozen();
+public interface IFreezable {
+    public boolean isFrozen();

 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/IInstantiationStrategy.java b/Code/ChroniclerJ/src/com/rits/cloning/IInstantiationStrategy.java
index acafb73..b23edec 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/IInstantiationStrategy.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/IInstantiationStrategy.java
@@ -1,11 +1,9 @@
+
 package com.rits.cloning;

 /**
- * @author kostantinos.kougios
- *
- * 17 Jul 2012
+ * @author kostantinos.kougios 17 Jul 2012
  */
-public interface IInstantiationStrategy
-{
-	<T> T newInstance(final Class<T> c);
+public interface IInstantiationStrategy {
+    <T> T newInstance(final Class<T> c);
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/Immutable.java b/Code/ChroniclerJ/src/com/rits/cloning/Immutable.java
index 16347f0..7f68e4d 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/Immutable.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/Immutable.java
@@ -1,3 +1,4 @@
+
 package com.rits.cloning;

 import static java.lang.annotation.ElementType.TYPE;
@@ -9,17 +10,17 @@ import java.lang.annotation.Target;
 /**
  * marks the specific class as immutable and the cloner avoids cloning it
  *
- * @author kostantinos.kougios
- *
- * 24 Mar 2011
+ * @author kostantinos.kougios 24 Mar 2011
  */
 @Target(TYPE)
 @Retention(RUNTIME)
-public @interface Immutable
-{
-	/**
-	 * by default all subclasses of the @Immutable class are not immutable. This can override it.
-	 * @return		true for subclasses of @Immutable class to be regarded as immutable from the cloner
-	 */
-	boolean subClass() default false;
+public @interface Immutable {
+    /**
+     * by default all subclasses of the @Immutable class are not immutable. This
+     * can override it.
+     *
+     * @return true for subclasses of @Immutable class to be regarded as
+     *         immutable from the cloner
+     */
+    boolean subClass() default false;
 }
diff --git a/Code/ChroniclerJ/src/com/rits/cloning/ObjenesisInstantiationStrategy.java b/Code/ChroniclerJ/src/com/rits/cloning/ObjenesisInstantiationStrategy.java
index 742e21e..9b24358 100644
--- a/Code/ChroniclerJ/src/com/rits/cloning/ObjenesisInstantiationStrategy.java
+++ b/Code/ChroniclerJ/src/com/rits/cloning/ObjenesisInstantiationStrategy.java
@@ -1,27 +1,23 @@
+
 package com.rits.cloning;

 import org.objenesis.Objenesis;
 import org.objenesis.ObjenesisStd;

 /**
- * @author kostantinos.kougios
- *
- * 17 Jul 2012
+ * @author kostantinos.kougios 17 Jul 2012
  */
-public class ObjenesisInstantiationStrategy implements IInstantiationStrategy
-{
-	private final Objenesis	objenesis	= new ObjenesisStd();
+public class ObjenesisInstantiationStrategy implements IInstantiationStrategy {
+    private final Objenesis objenesis = new ObjenesisStd();

-	@SuppressWarnings("unchecked")
-	public <T> T newInstance(Class<T> c)
-	{
-		return (T) objenesis.newInstance(c);
-	}
+    @SuppressWarnings("unchecked")
+    public <T> T newInstance(Class<T> c) {
+        return (T) objenesis.newInstance(c);
+    }

-	private static ObjenesisInstantiationStrategy	instance	= new ObjenesisInstantiationStrategy();
+    private static ObjenesisInstantiationStrategy instance = new ObjenesisInstantiationStrategy();

-	public static ObjenesisInstantiationStrategy getInstance()
-	{
-		return instance;
-	}
+    public static ObjenesisInstantiationStrategy getInstance() {
+        return instance;
+    }
 }
diff --git a/Code/ChroniclerJ/src/com/rits/perspectives/Perspectives.java b/Code/ChroniclerJ/src/com/rits/perspectives/Perspectives.java
index 0338341..9b787ce 100644
--- a/Code/ChroniclerJ/src/com/rits/perspectives/Perspectives.java
+++ b/Code/ChroniclerJ/src/com/rits/perspectives/Perspectives.java
@@ -1,3 +1,4 @@
+
 package com.rits.perspectives;

 import java.util.Collection;
@@ -5,69 +6,71 @@ import java.util.Collection;
 import com.rits.cloning.Cloner;

 /**
- * Perspectives: an object instance of a class behaving differently according to the "view angle".
- *
- * @author kostantinos.kougios
- *
- * 30 Nov 2009
+ * Perspectives: an object instance of a class behaving differently according to
+ * the "view angle".
+ *
+ * @author kostantinos.kougios 30 Nov 2009
  */
-public class Perspectives
-{
-	private final Cloner	cloner;
+public class Perspectives {
+    private final Cloner cloner;

-	public Perspectives(final Cloner cloner)
-	{
-		this.cloner = cloner;
-	}
+    public Perspectives(final Cloner cloner) {
+        this.cloner = cloner;
+    }

-	/**
-	 * Sample: if o is an instance of Product and c is OrderedProduct.class then this returns
-	 * and instance of OrderedProduct.class which has equal field values to those of the instance of Product.
-	 * In other words, the returned instance of OrderedProduct.class is the Product instance from the perspective
-	 * of an OrderedProduct
-	 *
-	 * View an object o from the perspective of class c. (view o as an instance of c). c must be instanceof o.getClass()
-	 *
-	 * @param <T>		the object
-	 * @param <E>		this will be the returned type and it must be instanceof T. All properties of o will be copied to this instance.
-	 * @param c			the class of E. This is used to generate new instances of c
-	 * @param o			the object that must be viewed from a different perspective
-	 * @return			the E perspective of o
-	 */
-	public <T, E extends T> E viewAs(final Class<E> c, final T o)
-	{
-		if (o == null) return null;
-		if (o instanceof Collection<?>) throw new IllegalArgumentException("for collections please use viewCollectionAs() method. Invalid object " + o);
-		final E newInstance = cloner.fastCloneOrNewInstance(c);
-		cloner.copyPropertiesOfInheritedClass(o, newInstance);
-		return newInstance;
-	}
+    /**
+     * Sample: if o is an instance of Product and c is OrderedProduct.class then
+     * this returns and instance of OrderedProduct.class which has equal field
+     * values to those of the instance of Product. In other words, the returned
+     * instance of OrderedProduct.class is the Product instance from the
+     * perspective of an OrderedProduct View an object o from the perspective of
+     * class c. (view o as an instance of c). c must be instanceof o.getClass()
+     *
+     * @param <T> the object
+     * @param <E> this will be the returned type and it must be instanceof T.
+     *            All properties of o will be copied to this instance.
+     * @param c the class of E. This is used to generate new instances of c
+     * @param o the object that must be viewed from a different perspective
+     * @return the E perspective of o
+     */
+    public <T, E extends T> E viewAs(final Class<E> c, final T o) {
+        if (o == null)
+            return null;
+        if (o instanceof Collection<?>)
+            throw new IllegalArgumentException(
+                    "for collections please use viewCollectionAs() method. Invalid object " + o);
+        final E newInstance = cloner.fastCloneOrNewInstance(c);
+        cloner.copyPropertiesOfInheritedClass(o, newInstance);
+        return newInstance;
+    }

-	/**
-	 * Sample: if o is a [ Products extends LinkedList<Product> ] then the returned instance
-	 * is a [ OrderedProducts extends LinkedList<OrderedProduct> ].
-	 *
-	 * View a collection o from the perspective of collection E.
-	 *
-	 * NOTE: order of the items might not be preserved, depending on the collection type
-	 *
-	 * @param <T>								the type of the collection o
-	 * @param <I>								the type of the elements of the collection o
-	 * @param <E>								the type of the perspective collection
-	 * @param <NI>								the type of the perspective's elements
-	 * @param newCollection			the collection to which the adapted instances should be added
-	 * @param currentCollection			the collection with the instances to be adapted
-	 * @param perspectiveCollectionItemClass	the class of the NI
-	 * @return									E, the collection from a different perspective or null if currentCollection is null
-	 */
-	public <I, NI extends I, T extends Collection<I>, E extends Collection<NI>> E viewCollectionAs(final E newCollection, final Class<NI> perspectiveCollectionItemClass, final T currentCollection)
-	{
-		if (currentCollection == null) return null;
-		for (final I item : currentCollection)
-		{
-			final NI newItem = viewAs(perspectiveCollectionItemClass, item);
-			newCollection.add(newItem);
-		}
-		return newCollection;
-	}
+    /**
+     * Sample: if o is a [ Products extends LinkedList<Product> ] then the
+     * returned instance is a [ OrderedProducts extends
+     * LinkedList<OrderedProduct> ]. View a collection o from the perspective of
+     * collection E. NOTE: order of the items might not be preserved, depending
+     * on the collection type
+     *
+     * @param <T> the type of the collection o
+     * @param <I> the type of the elements of the collection o
+     * @param <E> the type of the perspective collection
+     * @param <NI> the type of the perspective's elements
+     * @param newCollection the collection to which the adapted instances should
+     *            be added
+     * @param currentCollection the collection with the instances to be adapted
+     * @param perspectiveCollectionItemClass the class of the NI
+     * @return E, the collection from a different perspective or null if
+     *         currentCollection is null
+     */
+    public <I, NI extends I, T extends Collection<I>, E extends Collection<NI>> E viewCollectionAs(
+            final E newCollection, final Class<NI> perspectiveCollectionItemClass,
+            final T currentCollection) {
+        if (currentCollection == null)
+            return null;
+        for (final I item : currentCollection) {
+            final NI newItem = viewAs(perspectiveCollectionItemClass, item);
+            newCollection.add(newItem);
+        }
+        return newCollection;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackInvocation.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackInvocation.java
index 347c8ab..242a8e6 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackInvocation.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackInvocation.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.awt.EventQueue;
@@ -7,123 +8,137 @@ import java.lang.reflect.Method;
 import org.objectweb.asm.Type;

 public class CallbackInvocation {
-	@Override
-	public String toString() {
-		return "CallbackInvocation [clazz=" + clazz + ", methodName=" + methodName + ", methodDesc=" + methodDesc + ", ownerID=" + ownerID + ", executed=" + executed + ", clock=" + clock + "]";
-	}
-
-	private String clazz;
-	private String methodName;
-	private String methodDesc;
-	private Object[] args;
-	private String ownerID;
-	private boolean executed;
-	private int clock;
-	private String threadName;
-
-	public CallbackInvocation(String clazz, String methodName, String methodDesc, Object[] args, Object owner) {
-		this.clazz = clazz;
-		this.methodName = methodName;
-		this.methodDesc = methodDesc;
-		this.args = args;
-		this.ownerID = CallbackRegistry.getId(owner);
-		this.clock = SerializableLog.aLog_fill + SerializableLog.bLog_fill + SerializableLog.cLog_fill + SerializableLog.dLog_fill + SerializableLog.fLog_fill + SerializableLog.jLog_fill
-				+ SerializableLog.sLog_fill + SerializableLog.zLog_fill + Log.aLog_fill;
-		this.threadName = Thread.currentThread().getName();
-	}
-
-	public String getThreadName() {
-		return threadName;
-	}
-
-	public int getClock() {
-		return clock;
-	}
-
-	public void resetExecuted() {
-		executed = false;
-	}
-
-	public boolean invoke() {
-		if (executed)
-			return false;
-		executed = true;
-		try {
-			if (CallbackRegistry.get(ownerID) == null) {
-				//				System.out.println("Queued");
-				CallbackRegistry.queueInvocation(ownerID, this);
-			} else {
-				if (!this.threadName.startsWith("AWT-EventQueue-")) {
-					try {
-						final Object owner = CallbackRegistry.get(ownerID);
-						final Method method = getMethod();
-						EventQueue.invokeAndWait(new Runnable() {
-
-							@Override
-							public void run() {
-								try {
-									//									System.out.println("Dispatching to AWT");
-									method.invoke(owner, args);
-									//									System.out.println("Executed");
-								} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-									// TODO Auto-generated catch block
-									e.getCause().printStackTrace();
-									System.exit(-1);
-								}
-							}
-						});
-					} catch (InterruptedException e) {
-						// TODO Auto-generated catch block
-						e.printStackTrace();
-					}
-				} else {
-					try {
-						getMethod().invoke(CallbackRegistry.get(ownerID), args);
-					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-						// TODO Auto-generated catch block
-						e.getCause().printStackTrace();
-						System.exit(-1);
-					}
-				}
-			}
-		} catch (IllegalArgumentException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (InvocationTargetException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		return true;
-	}
-
-	public Method getMethod() {
-		Type[] argDesc = Type.getMethodType(methodDesc).getArgumentTypes();
-		return getMethod(methodName, argDesc, CallbackRegistry.get(ownerID).getClass());
-	}
-
-	protected Method getMethod(String methodName, Type[] types, Class<?> clazz) {
-		try {
-			for (Method m : clazz.getDeclaredMethods()) {
-				boolean ok = true;
-				if (m.getName().equals(methodName)) {
-					Class<?>[] mArgs = m.getParameterTypes();
-					if (mArgs.length != types.length)
-						break;
-					for (int i = 0; i < mArgs.length; i++)
-						if (!mArgs[i].getName().equals(types[i].getClassName()))
-							ok = false;
-					if (ok) {
-						if (!m.isAccessible())
-							m.setAccessible(true);
-						return m;
-					}
-				}
-			}
-		} catch (SecurityException e) {
-			e.printStackTrace();
-		}
-		if (clazz.getSuperclass() != null)
-			return getMethod(methodName, types, clazz.getSuperclass());
-		return null;
-	}
+    @Override
+    public String toString() {
+        return "CallbackInvocation [clazz=" + clazz + ", methodName=" + methodName
+                + ", methodDesc=" + methodDesc + ", ownerID=" + ownerID + ", executed=" + executed
+                + ", clock=" + clock + "]";
+    }
+
+    private String clazz;
+
+    private String methodName;
+
+    private String methodDesc;
+
+    private Object[] args;
+
+    private String ownerID;
+
+    private boolean executed;
+
+    private int clock;
+
+    private String threadName;
+
+    public CallbackInvocation(String clazz, String methodName, String methodDesc, Object[] args,
+            Object owner) {
+        this.clazz = clazz;
+        this.methodName = methodName;
+        this.methodDesc = methodDesc;
+        this.args = args;
+        this.ownerID = CallbackRegistry.getId(owner);
+        this.clock = SerializableLog.aLog_fill + SerializableLog.bLog_fill
+                + SerializableLog.cLog_fill + SerializableLog.dLog_fill + SerializableLog.fLog_fill
+                + SerializableLog.jLog_fill + SerializableLog.sLog_fill + SerializableLog.zLog_fill
+                + Log.aLog_fill;
+        this.threadName = Thread.currentThread().getName();
+    }
+
+    public String getThreadName() {
+        return threadName;
+    }
+
+    public int getClock() {
+        return clock;
+    }
+
+    public void resetExecuted() {
+        executed = false;
+    }
+
+    public boolean invoke() {
+        if (executed)
+            return false;
+        executed = true;
+        try {
+            if (CallbackRegistry.get(ownerID) == null) {
+                // System.out.println("Queued");
+                CallbackRegistry.queueInvocation(ownerID, this);
+            } else {
+                if (!this.threadName.startsWith("AWT-EventQueue-")) {
+                    try {
+                        final Object owner = CallbackRegistry.get(ownerID);
+                        final Method method = getMethod();
+                        EventQueue.invokeAndWait(new Runnable() {
+
+                            @Override
+                            public void run() {
+                                try {
+                                    // System.out.println("Dispatching to AWT");
+                                    method.invoke(owner, args);
+                                    // System.out.println("Executed");
+                                } catch (IllegalAccessException | IllegalArgumentException
+                                        | InvocationTargetException e) {
+                                    // TODO Auto-generated catch block
+                                    e.getCause().printStackTrace();
+                                    System.exit(-1);
+                                }
+                            }
+                        });
+                    } catch (InterruptedException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    }
+                } else {
+                    try {
+                        getMethod().invoke(CallbackRegistry.get(ownerID), args);
+                    } catch (IllegalAccessException | IllegalArgumentException
+                            | InvocationTargetException e) {
+                        // TODO Auto-generated catch block
+                        e.getCause().printStackTrace();
+                        System.exit(-1);
+                    }
+                }
+            }
+        } catch (IllegalArgumentException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return true;
+    }
+
+    public Method getMethod() {
+        Type[] argDesc = Type.getMethodType(methodDesc).getArgumentTypes();
+        return getMethod(methodName, argDesc, CallbackRegistry.get(ownerID).getClass());
+    }
+
+    protected Method getMethod(String methodName, Type[] types, Class<?> clazz) {
+        try {
+            for (Method m : clazz.getDeclaredMethods()) {
+                boolean ok = true;
+                if (m.getName().equals(methodName)) {
+                    Class<?>[] mArgs = m.getParameterTypes();
+                    if (mArgs.length != types.length)
+                        break;
+                    for (int i = 0; i < mArgs.length; i++)
+                        if (!mArgs[i].getName().equals(types[i].getClassName()))
+                            ok = false;
+                    if (ok) {
+                        if (!m.isAccessible())
+                            m.setAccessible(true);
+                        return m;
+                    }
+                }
+            }
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        if (clazz.getSuperclass() != null)
+            return getMethod(methodName, types, clazz.getSuperclass());
+        return null;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackRegistry.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackRegistry.java
index ef13dd2..1612177 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackRegistry.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CallbackRegistry.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.util.HashMap;
@@ -5,48 +6,49 @@ import java.util.LinkedList;
 import java.util.WeakHashMap;

 public class CallbackRegistry {
-	private static HashMap<String, Object> registry = new HashMap<String, Object>();
-	private static WeakHashMap<Object, String> reverseRegistry = new WeakHashMap<Object, String>();
-	private static ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
-		protected Integer initialValue() {
-			return 0;
-		};
-	};
-	public static void queueInvocation(String o, CallbackInvocation i)
-	{
-//		System.out.println("QUeue" + i);
-		if(!queuedInvocations.containsKey(o))
-			queuedInvocations.put(o, new LinkedList<CallbackInvocation>());
-		queuedInvocations.get(o).add(i);
-	}
-	private static HashMap<String, LinkedList<CallbackInvocation>> queuedInvocations = new HashMap<String, LinkedList<CallbackInvocation>>();
-	public static synchronized void register(Object o)
-	{
-//		System.out.println("Register callback");
-		String key = Thread.currentThread().getName()+count.get();
-//		System.out.println(key + " registered");
-		registry.put(key, o);
-		reverseRegistry.put(o, key);
-		count.set(count.get() + 1);
-
-		if(queuedInvocations.containsKey(key))
-		{
-			for(CallbackInvocation i : queuedInvocations.get(key))
-			{
-//				System.out.println("Invoke " + i);
-				i.resetExecuted();
-				i.invoke();
-			}
-			queuedInvocations.remove(key);
-		}
-	}
-	public static String getId(Object o)
-	{
-		return reverseRegistry.get(o);
-	}
-	public static synchronized Object get(String id)
-	{
-//		System.out.println("Get callback");
-		return registry.get(id);
-	}
+    private static HashMap<String, Object> registry = new HashMap<String, Object>();
+
+    private static WeakHashMap<Object, String> reverseRegistry = new WeakHashMap<Object, String>();
+
+    private static ThreadLocal<Integer> count = new ThreadLocal<Integer>() {
+        protected Integer initialValue() {
+            return 0;
+        };
+    };
+
+    public static void queueInvocation(String o, CallbackInvocation i) {
+        // System.out.println("QUeue" + i);
+        if (!queuedInvocations.containsKey(o))
+            queuedInvocations.put(o, new LinkedList<CallbackInvocation>());
+        queuedInvocations.get(o).add(i);
+    }
+
+    private static HashMap<String, LinkedList<CallbackInvocation>> queuedInvocations = new HashMap<String, LinkedList<CallbackInvocation>>();
+
+    public static synchronized void register(Object o) {
+        // System.out.println("Register callback");
+        String key = Thread.currentThread().getName() + count.get();
+        // System.out.println(key + " registered");
+        registry.put(key, o);
+        reverseRegistry.put(o, key);
+        count.set(count.get() + 1);
+
+        if (queuedInvocations.containsKey(key)) {
+            for (CallbackInvocation i : queuedInvocations.get(key)) {
+                // System.out.println("Invoke " + i);
+                i.resetExecuted();
+                i.invoke();
+            }
+            queuedInvocations.remove(key);
+        }
+    }
+
+    public static String getId(Object o) {
+        return reverseRegistry.get(o);
+    }
+
+    public static synchronized Object get(String id) {
+        // System.out.println("Get callback");
+        return registry.get(id);
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJExportRunner.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJExportRunner.java
index 11867f3..e535634 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJExportRunner.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJExportRunner.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.io.File;
@@ -17,266 +18,261 @@ import com.thoughtworks.xstream.XStream;
 import edu.columbia.cs.psl.chroniclerj.xstream.StaticReflectionProvider;
 import java.util.jar.Manifest;

-
 public class ChroniclerJExportRunner extends Thread {

-	private static String mainClass;
-	private static String[] mainArgs;
-
-	private static ArrayList<String> serializableLogs = new ArrayList<>();
-	private static ArrayList<String> otherLogs = new ArrayList<>();
-
-	public static void logMain(String main, String[] args)
-	{
-		CloningUtils.init();
-		mainClass = main;
-		mainArgs = new String[args.length];
-		System.arraycopy(args, 0, mainArgs, 0, args.length);
-	}
-
-	public static void genTestCase()
-	{
-		export();
-		exportSerializable();
-		try {
-
-			File logFile = new File("chroniclerj-crash-"+System.currentTimeMillis()+".test");
-
-			Manifest manifest = new Manifest();
-			  manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
-			  manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "edu.columbia.cs.psl.wallace.replay.ReplayRunner");
-
-			JarOutputStream zos = new JarOutputStream(new FileOutputStream(logFile));
-
-			JarEntry mainEntry = new JarEntry("main-info");
-			zos.putNextEntry(mainEntry);
-			zos.write(mainClass.getBytes());
-			zos.write("\n".getBytes());
-			zos.write((""+mainArgs.length+"\n").getBytes());
-			for(String s : mainArgs)
-			{
-				zos.write((s+"\n").getBytes());
-			}
-			for(String s : serializableLogs)
-			{
-				zos.write((s+"\n").getBytes());
-			}
-			for(String s : otherLogs)
-			{
-				zos.write((s+"\n").getBytes());
-			}
-			zos.closeEntry();
-			for(String s : serializableLogs)
-			{
-				JarEntry e = new JarEntry(s);
-				zos.putNextEntry(e);
-				InputStream is = new FileInputStream(s);
-				byte[] buffer = new byte[1024];
-				while (true) {
-					int count = is.read(buffer);
-					if (count == -1)
-						break;
-					zos.write(buffer, 0, count);
-				}
-				is.close();
-				zos.closeEntry();
-				File f = new File(s);
-				f.delete();
-			}
-			for(String s : otherLogs)
-			{
-				JarEntry e = new JarEntry(s);
-				zos.putNextEntry(e);
-				InputStream is = new FileInputStream(s);
-				byte[] buffer = new byte[1024];
-				while (true) {
-					int count = is.read(buffer);
-					if (count == -1)
-						break;
-					zos.write(buffer, 0, count);
-				}
-				is.close();
-				zos.closeEntry();
-				File f = new File(s);
-				f.delete();
-			}
-			zos.flush();
-			zos.close();
-			System.out.println("Chroniclerj exported a test case");
-
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-
-	}
-
-
-	@Override
-	public void run() {
-		while (1 == 1) {
-			try {
-				Thread.sleep(10000); // 10 seconds
-				if (shouldExport == 1)
-					export();
-				if (shouldExportSerializable == 1)
-					exportSerializable();
-				if (shouldExport == 1)
-					export();
-
-			} catch (InterruptedException e) {
-				if (shouldExport == 1)
-					export();
-				if (shouldExportSerializable == 1)
-					exportSerializable();
-				if (shouldExport == 1)
-					export();
-			}
-		}
-	}
-
-	static ChroniclerJExportRunner inst = new ChroniclerJExportRunner();
-
-	public ChroniclerJExportRunner() {
-		setDaemon(true);
-		setPriority(Thread.MAX_PRIORITY);
-	}
-
-	private static ExportedLog log = new ExportedLog();
-
-	public static void export() {
-		shouldExport = 0;
-		try {
-
-			XStream xstream = new XStream(new StaticReflectionProvider());
-			String xml = "";
-			Log.logLock.lock();
-			ExportedLog.aLog = Log.aLog;
-			ExportedLog.aLog_owners = Log.aLog_owners;
-			ExportedLog.aLog_fill = Log.aLog_fill;
-			Log.logsize = 0;
-			Log.aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-			Log.aLog_fill = 0;
-			Log.logLock.unlock();
-
-			try {
-				xml = xstream.toXML(log);
-			} catch (Exception ex) {
-				System.err.println("NPE" + ex.getMessage());
-			}
-
-			ExportedLog.clearLog();
-			String name = "chroniclerj_" + System.currentTimeMillis() + ".log";
-			otherLogs.add(name);
-			File output = new File(name);
-			FileWriter fw = new FileWriter(output);
-			fw.write(xml);
-			fw.close();
-		} catch (Exception exi) {
-
-		}
-		shouldExport = -1;
-	}
-
-	private static ExportedSerializableLog logS = new ExportedSerializableLog();
-
-	public static void exportSerializable() {
-		shouldExportSerializable = 0;
-		try {
-
-			Log.logLock.lock();
-			{
-				ExportedSerializableLog.aLog = SerializableLog.aLog;
-				ExportedSerializableLog.aLog_fill = SerializableLog.aLog_fill;
-				ExportedSerializableLog.bLog = SerializableLog.bLog;
-				ExportedSerializableLog.cLog = SerializableLog.cLog;
-				ExportedSerializableLog.dLog = SerializableLog.dLog;
-				ExportedSerializableLog.iLog = SerializableLog.iLog;
-				ExportedSerializableLog.fLog = SerializableLog.fLog;
-				ExportedSerializableLog.jLog = SerializableLog.jLog;
-				ExportedSerializableLog.zLog = SerializableLog.zLog;
-				ExportedSerializableLog.sLog = SerializableLog.sLog;
-
-				ExportedSerializableLog.bLog_fill = SerializableLog.bLog_fill;
-				ExportedSerializableLog.cLog_fill = SerializableLog.cLog_fill;
-				ExportedSerializableLog.dLog_fill = SerializableLog.dLog_fill;
-				ExportedSerializableLog.iLog_fill = SerializableLog.iLog_fill;
-				ExportedSerializableLog.fLog_fill = SerializableLog.fLog_fill;
-				ExportedSerializableLog.jLog_fill = SerializableLog.jLog_fill;
-				ExportedSerializableLog.zLog_fill = SerializableLog.zLog_fill;
-				ExportedSerializableLog.sLog_fill = SerializableLog.sLog_fill;
-
-				ExportedSerializableLog.aLog_owners = SerializableLog.aLog_owners;
-				ExportedSerializableLog.iLog_owners = SerializableLog.iLog_owners;
-				ExportedSerializableLog.jLog_owners = SerializableLog.jLog_owners;
-				ExportedSerializableLog.fLog_owners = SerializableLog.fLog_owners;
-				ExportedSerializableLog.dLog_owners = SerializableLog.dLog_owners;
-				ExportedSerializableLog.bLog_owners = SerializableLog.bLog_owners;
-				ExportedSerializableLog.zLog_owners = SerializableLog.zLog_owners;
-				ExportedSerializableLog.cLog_owners = SerializableLog.cLog_owners;
-				ExportedSerializableLog.sLog_owners = SerializableLog.sLog_owners;
-
-				SerializableLog.aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.iLog = new int[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.jLog = new long[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.fLog = new float[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.dLog = new double[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.bLog = new byte[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.zLog = new boolean[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.cLog = new char[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.sLog = new short[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.iLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.jLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.fLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.dLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.bLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.zLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.cLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.sLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-				SerializableLog.logsize = 0;
-				SerializableLog.iLog_fill = 0;
-				SerializableLog.jLog_fill = 0;
-				SerializableLog.fLog_fill = 0;
-				SerializableLog.dLog_fill = 0;
-				SerializableLog.bLog_fill = 0;
-				SerializableLog.zLog_fill = 0;
-				SerializableLog.cLog_fill = 0;
-				SerializableLog.sLog_fill = 0;
-				SerializableLog.aLog_fill = 0;
-			}
-			Log.logLock.unlock();
-			String name = "chroniclerj_serializable_" + System.currentTimeMillis() + ".log";
-			File output = new File(name);
-			serializableLogs.add(name);
-			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(output));
-			oos.writeObject(logS);
-			oos.flush();
-			oos.close();
-			ExportedLog.clearLog();
-		} catch (Exception exi) {
-
-		}
-		shouldExportSerializable = -1;
-	}
-
-	private static int shouldExport = -1;
-	private static int shouldExportSerializable = -1;
-
-	public static void _exportSerializable() {
-		if (shouldExportSerializable == -1) {
-			Thread.yield();
-			shouldExportSerializable = 1;
-			inst.interrupt();
-		}
-	}
-
-	public static void _export() {
-		if (shouldExport == -1) {
-			Thread.yield();
-			shouldExport = 1;
-			inst.interrupt();
-		}
-	}
+    private static String mainClass;
+
+    private static String[] mainArgs;
+
+    private static ArrayList<String> serializableLogs = new ArrayList<>();
+
+    private static ArrayList<String> otherLogs = new ArrayList<>();
+
+    public static void logMain(String main, String[] args) {
+        CloningUtils.init();
+        mainClass = main;
+        mainArgs = new String[args.length];
+        System.arraycopy(args, 0, mainArgs, 0, args.length);
+    }
+
+    public static void genTestCase() {
+        export();
+        exportSerializable();
+        try {
+
+            File logFile = new File("chroniclerj-crash-" + System.currentTimeMillis() + ".test");
+
+            Manifest manifest = new Manifest();
+            manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+            manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS,
+                    "edu.columbia.cs.psl.wallace.replay.ReplayRunner");
+
+            JarOutputStream zos = new JarOutputStream(new FileOutputStream(logFile));
+
+            JarEntry mainEntry = new JarEntry("main-info");
+            zos.putNextEntry(mainEntry);
+            zos.write(mainClass.getBytes());
+            zos.write("\n".getBytes());
+            zos.write(("" + mainArgs.length + "\n").getBytes());
+            for (String s : mainArgs) {
+                zos.write((s + "\n").getBytes());
+            }
+            for (String s : serializableLogs) {
+                zos.write((s + "\n").getBytes());
+            }
+            for (String s : otherLogs) {
+                zos.write((s + "\n").getBytes());
+            }
+            zos.closeEntry();
+            for (String s : serializableLogs) {
+                JarEntry e = new JarEntry(s);
+                zos.putNextEntry(e);
+                InputStream is = new FileInputStream(s);
+                byte[] buffer = new byte[1024];
+                while (true) {
+                    int count = is.read(buffer);
+                    if (count == -1)
+                        break;
+                    zos.write(buffer, 0, count);
+                }
+                is.close();
+                zos.closeEntry();
+                File f = new File(s);
+                f.delete();
+            }
+            for (String s : otherLogs) {
+                JarEntry e = new JarEntry(s);
+                zos.putNextEntry(e);
+                InputStream is = new FileInputStream(s);
+                byte[] buffer = new byte[1024];
+                while (true) {
+                    int count = is.read(buffer);
+                    if (count == -1)
+                        break;
+                    zos.write(buffer, 0, count);
+                }
+                is.close();
+                zos.closeEntry();
+                File f = new File(s);
+                f.delete();
+            }
+            zos.flush();
+            zos.close();
+            System.out.println("Chroniclerj exported a test case");
+
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+    }
+
+    @Override
+    public void run() {
+        while (1 == 1) {
+            try {
+                Thread.sleep(10000); // 10 seconds
+                if (shouldExport == 1)
+                    export();
+                if (shouldExportSerializable == 1)
+                    exportSerializable();
+                if (shouldExport == 1)
+                    export();
+
+            } catch (InterruptedException e) {
+                if (shouldExport == 1)
+                    export();
+                if (shouldExportSerializable == 1)
+                    exportSerializable();
+                if (shouldExport == 1)
+                    export();
+            }
+        }
+    }
+
+    static ChroniclerJExportRunner inst = new ChroniclerJExportRunner();
+
+    public ChroniclerJExportRunner() {
+        setDaemon(true);
+        setPriority(Thread.MAX_PRIORITY);
+    }
+
+    private static ExportedLog log = new ExportedLog();
+
+    public static void export() {
+        shouldExport = 0;
+        try {
+
+            XStream xstream = new XStream(new StaticReflectionProvider());
+            String xml = "";
+            Log.logLock.lock();
+            ExportedLog.aLog = Log.aLog;
+            ExportedLog.aLog_owners = Log.aLog_owners;
+            ExportedLog.aLog_fill = Log.aLog_fill;
+            Log.logsize = 0;
+            Log.aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+            Log.aLog_fill = 0;
+            Log.logLock.unlock();
+
+            try {
+                xml = xstream.toXML(log);
+            } catch (Exception ex) {
+                System.err.println("NPE" + ex.getMessage());
+            }
+
+            ExportedLog.clearLog();
+            String name = "chroniclerj_" + System.currentTimeMillis() + ".log";
+            otherLogs.add(name);
+            File output = new File(name);
+            FileWriter fw = new FileWriter(output);
+            fw.write(xml);
+            fw.close();
+        } catch (Exception exi) {
+
+        }
+        shouldExport = -1;
+    }
+
+    private static ExportedSerializableLog logS = new ExportedSerializableLog();
+
+    public static void exportSerializable() {
+        shouldExportSerializable = 0;
+        try {
+
+            Log.logLock.lock();
+            {
+                ExportedSerializableLog.aLog = SerializableLog.aLog;
+                ExportedSerializableLog.aLog_fill = SerializableLog.aLog_fill;
+                ExportedSerializableLog.bLog = SerializableLog.bLog;
+                ExportedSerializableLog.cLog = SerializableLog.cLog;
+                ExportedSerializableLog.dLog = SerializableLog.dLog;
+                ExportedSerializableLog.iLog = SerializableLog.iLog;
+                ExportedSerializableLog.fLog = SerializableLog.fLog;
+                ExportedSerializableLog.jLog = SerializableLog.jLog;
+                ExportedSerializableLog.zLog = SerializableLog.zLog;
+                ExportedSerializableLog.sLog = SerializableLog.sLog;
+
+                ExportedSerializableLog.bLog_fill = SerializableLog.bLog_fill;
+                ExportedSerializableLog.cLog_fill = SerializableLog.cLog_fill;
+                ExportedSerializableLog.dLog_fill = SerializableLog.dLog_fill;
+                ExportedSerializableLog.iLog_fill = SerializableLog.iLog_fill;
+                ExportedSerializableLog.fLog_fill = SerializableLog.fLog_fill;
+                ExportedSerializableLog.jLog_fill = SerializableLog.jLog_fill;
+                ExportedSerializableLog.zLog_fill = SerializableLog.zLog_fill;
+                ExportedSerializableLog.sLog_fill = SerializableLog.sLog_fill;
+
+                ExportedSerializableLog.aLog_owners = SerializableLog.aLog_owners;
+                ExportedSerializableLog.iLog_owners = SerializableLog.iLog_owners;
+                ExportedSerializableLog.jLog_owners = SerializableLog.jLog_owners;
+                ExportedSerializableLog.fLog_owners = SerializableLog.fLog_owners;
+                ExportedSerializableLog.dLog_owners = SerializableLog.dLog_owners;
+                ExportedSerializableLog.bLog_owners = SerializableLog.bLog_owners;
+                ExportedSerializableLog.zLog_owners = SerializableLog.zLog_owners;
+                ExportedSerializableLog.cLog_owners = SerializableLog.cLog_owners;
+                ExportedSerializableLog.sLog_owners = SerializableLog.sLog_owners;
+
+                SerializableLog.aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.iLog = new int[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.jLog = new long[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.fLog = new float[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.dLog = new double[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.bLog = new byte[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.zLog = new boolean[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.cLog = new char[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.sLog = new short[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.iLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.jLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.fLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.dLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.bLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.zLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.cLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.sLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+                SerializableLog.logsize = 0;
+                SerializableLog.iLog_fill = 0;
+                SerializableLog.jLog_fill = 0;
+                SerializableLog.fLog_fill = 0;
+                SerializableLog.dLog_fill = 0;
+                SerializableLog.bLog_fill = 0;
+                SerializableLog.zLog_fill = 0;
+                SerializableLog.cLog_fill = 0;
+                SerializableLog.sLog_fill = 0;
+                SerializableLog.aLog_fill = 0;
+            }
+            Log.logLock.unlock();
+            String name = "chroniclerj_serializable_" + System.currentTimeMillis() + ".log";
+            File output = new File(name);
+            serializableLogs.add(name);
+            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(output));
+            oos.writeObject(logS);
+            oos.flush();
+            oos.close();
+            ExportedLog.clearLog();
+        } catch (Exception exi) {
+
+        }
+        shouldExportSerializable = -1;
+    }
+
+    private static int shouldExport = -1;
+
+    private static int shouldExportSerializable = -1;
+
+    public static void _exportSerializable() {
+        if (shouldExportSerializable == -1) {
+            Thread.yield();
+            shouldExportSerializable = 1;
+            inst.interrupt();
+        }
+    }
+
+    public static void _export() {
+        if (shouldExport == -1) {
+            Thread.yield();
+            shouldExport = 1;
+            inst.interrupt();
+        }
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJUncaughtExceptionHandler.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJUncaughtExceptionHandler.java
index a3cd7fa..42c9ba1 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJUncaughtExceptionHandler.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ChroniclerJUncaughtExceptionHandler.java
@@ -1,20 +1,18 @@
-package edu.columbia.cs.psl.chroniclerj;

+package edu.columbia.cs.psl.chroniclerj;

-public class ChroniclerJUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
+public class ChroniclerJUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

-	@Override
-	public void uncaughtException(Thread t, Throwable e) {
-		try{
-			System.err.println("ChroniclerJ caught an exception");
-			e.printStackTrace();
-			System.err.println("Writing log");
-			ChroniclerJExportRunner.genTestCase();
-			}
-		catch(Exception exi)
-		{
-			exi.printStackTrace();
-		}
-	}
+    @Override
+    public void uncaughtException(Thread t, Throwable e) {
+        try {
+            System.err.println("ChroniclerJ caught an exception");
+            e.printStackTrace();
+            System.err.println("Writing log");
+            ChroniclerJExportRunner.genTestCase();
+        } catch (Exception exi) {
+            exi.printStackTrace();
+        }
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CloningUtils.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CloningUtils.java
index 893d9c7..e469b96 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CloningUtils.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/CloningUtils.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.io.Closeable;
@@ -12,11 +13,13 @@ import java.net.URI;
 import java.net.URL;
 import java.net.URLConnection;
 import java.nio.channels.Channel;
+import java.nio.channels.SelectableChannel;
 import java.nio.channels.Selector;
 import java.security.Permissions;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Properties;
+import java.util.TimeZone;
 import java.util.Timer;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.locks.Lock;
@@ -38,111 +41,124 @@ import sun.nio.ch.DirectBuffer;
 import com.rits.cloning.Cloner;

 public class CloningUtils {
-	public static boolean				CATCH_ALL_ERRORS	= true;
-	private static Cloner				cloner				= new Cloner();
-	public static ReadWriteLock		exportLock			= new ReentrantReadWriteLock();
-	private static HashSet<Class<?>>	moreIgnoredImmutables;
-	private static HashSet<Class<?>>	nullInsteads;
-	private static HashSet<String> specificIgnored = new HashSet<>();
-	private static boolean inited= false;
-	public static void init()
-	{
-		if(inited)
-			return;
-		inited=true;
-		ChroniclerJExportRunner.inst.start();
-		if (CATCH_ALL_ERRORS) {
-			Thread.setDefaultUncaughtExceptionHandler(new ChroniclerJUncaughtExceptionHandler());
-		}
-
-	}
-//	private static BufferedWriter		log;
-	static {
-		moreIgnoredImmutables = new HashSet<Class<?>>();
-		moreIgnoredImmutables.add(ClassLoader.class);
-		moreIgnoredImmutables.add(Thread.class);
-		moreIgnoredImmutables.add(URI.class);
-		moreIgnoredImmutables.add(File.class);
-		moreIgnoredImmutables.add(ZipFile.class);
-		moreIgnoredImmutables.add(ZipEntry.class);
-		moreIgnoredImmutables.add(JarFile.class);
-		moreIgnoredImmutables.add(Inflater.class);
-		moreIgnoredImmutables.add(InputStream.class);
-		moreIgnoredImmutables.add(OutputStream.class);
-		moreIgnoredImmutables.add(Deflater.class);
-		moreIgnoredImmutables.add(Socket.class);
-		moreIgnoredImmutables.add(ServerSocket.class);
-		moreIgnoredImmutables.add(Channel.class);
-		moreIgnoredImmutables.add(Closeable.class);
-		moreIgnoredImmutables.add(Class.class);
-		moreIgnoredImmutables.add(CallbackInvocation.class);
-		moreIgnoredImmutables.add(Method.class);
-		moreIgnoredImmutables.add(Logger.class);
-		moreIgnoredImmutables.add(URLConnection.class);
-		moreIgnoredImmutables.add(MBeanServer.class);
-		moreIgnoredImmutables.add(DirectBuffer.class);
-		moreIgnoredImmutables.add(Semaphore.class);
-		moreIgnoredImmutables.add(Lock.class);
-		moreIgnoredImmutables.add(ReadWriteLock.class);
-		moreIgnoredImmutables.add(Writer.class);
-		moreIgnoredImmutables.add(Properties.class);
-		moreIgnoredImmutables.add(Timer.class);
-		moreIgnoredImmutables.add(ObjectName.class);
-		moreIgnoredImmutables.add(ObjectInstance.class);
-		moreIgnoredImmutables.add(Selector.class);
-		moreIgnoredImmutables.add(URI.class);
-		moreIgnoredImmutables.add(URL.class);
-
-		cloner.setExtraNullInsteadOfClone(moreIgnoredImmutables);
-		cloner.setExtraImmutables(moreIgnoredImmutables);
-
-		specificIgnored.add("org.apache.geronimo.security.jaas.LoginModuleControlFlag");
-		specificIgnored.add("org.apache.openejb.core.ivm.naming.IvmContext");
-		specificIgnored.add("org.apache.geronimo.openejb.GeronimoSecurityService");
-		specificIgnored.add("org.apache.geronimo.kernel.config.ConfigurationData");
-		specificIgnored.add("sun.net.www.protocol.jar.URLJarFile");
-		specificIgnored.add("sun.net.www.protocol.jar.JarURLConnection");
-//		cloner.dontClone("org.apache.geronimo.gbean.GBeanInfo");
-//		cloner.dontClone("org.apache.geronimo.gbean.AbstractName");
-//		cloner.dontClone("org.apache.geronimo.security.jaas.LoginModuleControlFlag");
-//		cloner.dontClone("org.apache.geronimo.kernel.config.ConfigurationData");
-//		cloner.dontClone("org.apache.geronimo.kernel.repository.Artifact");
-
-		nullInsteads = new HashSet<Class<?>>();
-		nullInsteads.add(Permissions.class);
-		cloner.setExtraNullInsteadOfClone(nullInsteads);
-		init();
-//		cloner.setDumpClonedClasses(true);
-		//		try {
-//			File f = new File("cloneLog");
-//			if (f.exists())
-//				f.delete();
-//			log = new BufferedWriter(new FileWriter("cloneLog"));
-//		} catch (IOException e) {
-//			// TODO Auto-generated catch block
-//			e.printStackTrace();
-//		}
-	}
-
-	public static final <T> T clone(T obj, String debug) {
-		if(obj != null)
-		{
-//			System.out.println(debug);
-//			if(specificIgnored.contains(obj.getClass().getName()))
-//				return obj;
-//			System.out.println(obj.getClass().getName());
-//	 		System.out.println("source>"+obj.getClass().getName() +"..."+Thread.currentThread().getName());
-				T ret = cloner.deepClone(obj);
-//			T ret = obj;
-				return ret;
-//				return obj;
-		}
-
-//			System.out.println("Done");
-			return null;
-	}
-
-	public static IdentityHashMap<Object, Object>	cloneCache	= new IdentityHashMap<Object, Object>();	;
-
+    public static boolean CATCH_ALL_ERRORS = true;
+
+    private static Cloner cloner = new Cloner();
+
+    public static ReadWriteLock exportLock = new ReentrantReadWriteLock();
+
+    public static HashSet<Class<?>> moreIgnoredImmutables;
+
+    public static HashSet<Class<?>> nullInsteads;
+
+    private static HashSet<String> specificIgnored = new HashSet<>();
+
+    private static boolean inited = false;
+
+    public static void init() {
+        if (inited)
+            return;
+        inited = true;
+        ChroniclerJExportRunner.inst.start();
+        if (CATCH_ALL_ERRORS) {
+            Thread.setDefaultUncaughtExceptionHandler(new ChroniclerJUncaughtExceptionHandler());
+        }
+
+    }
+
+    // private static BufferedWriter log;
+    static {
+        moreIgnoredImmutables = new HashSet<Class<?>>();
+        moreIgnoredImmutables.add(ClassLoader.class);
+        moreIgnoredImmutables.add(Thread.class);
+        moreIgnoredImmutables.add(URI.class);
+        moreIgnoredImmutables.add(Inflater.class);
+        moreIgnoredImmutables.add(InputStream.class);
+        moreIgnoredImmutables.add(OutputStream.class);
+        moreIgnoredImmutables.add(Deflater.class);
+        moreIgnoredImmutables.add(Class.class);
+        moreIgnoredImmutables.add(CallbackInvocation.class);
+        moreIgnoredImmutables.add(Method.class);
+        moreIgnoredImmutables.add(Logger.class);
+        moreIgnoredImmutables.add(URLConnection.class);
+        moreIgnoredImmutables.add(MBeanServer.class);
+        moreIgnoredImmutables.add(DirectBuffer.class);
+        moreIgnoredImmutables.add(Semaphore.class);
+        moreIgnoredImmutables.add(Lock.class);
+        moreIgnoredImmutables.add(ReadWriteLock.class);
+        moreIgnoredImmutables.add(Writer.class);
+        moreIgnoredImmutables.add(Properties.class);
+        moreIgnoredImmutables.add(Timer.class);
+        moreIgnoredImmutables.add(ObjectName.class);
+        moreIgnoredImmutables.add(ObjectInstance.class);
+        moreIgnoredImmutables.add(Selector.class);
+        moreIgnoredImmutables.add(URI.class);
+        moreIgnoredImmutables.add(URL.class);
+        moreIgnoredImmutables.add(ZipEntry.class);
+        moreIgnoredImmutables.add(TimeZone.class);
+        moreIgnoredImmutables.add(SelectableChannel.class);
+        moreIgnoredImmutables.add(File.class);
+        moreIgnoredImmutables.add(Selector.class);
+
+        cloner.setExtraNullInsteadOfClone(moreIgnoredImmutables);
+        cloner.setExtraImmutables(moreIgnoredImmutables);
+
+        specificIgnored.add("org.apache.geronimo.security.jaas.LoginModuleControlFlag");
+        specificIgnored.add("org.apache.openejb.core.ivm.naming.IvmContext");
+        specificIgnored.add("org.apache.geronimo.openejb.GeronimoSecurityService");
+        specificIgnored.add("org.apache.geronimo.kernel.config.ConfigurationData");
+        specificIgnored.add("sun.net.www.protocol.jar.URLJarFile");
+        specificIgnored.add("sun.net.www.protocol.jar.JarURLConnection");
+        // cloner.dontClone("org.apache.geronimo.gbean.GBeanInfo");
+        // cloner.dontClone("org.apache.geronimo.gbean.AbstractName");
+        // cloner.dontClone("org.apache.geronimo.security.jaas.LoginModuleControlFlag");
+        // cloner.dontClone("org.apache.geronimo.kernel.config.ConfigurationData");
+        // cloner.dontClone("org.apache.geronimo.kernel.repository.Artifact");
+
+        nullInsteads = new HashSet<Class<?>>();
+        nullInsteads.add(Permissions.class);
+
+        nullInsteads.add(File.class);
+        nullInsteads.add(ZipFile.class);
+        nullInsteads.add(ZipEntry.class);
+        nullInsteads.add(JarFile.class);
+        nullInsteads.add(Socket.class);
+        nullInsteads.add(ServerSocket.class);
+        nullInsteads.add(Channel.class);
+        nullInsteads.add(Closeable.class);
+        cloner.setExtraNullInsteadOfClone(nullInsteads);
+        init();
+        // cloner.setDumpClonedClasses(true);
+        // cloner.setDumpCloneStatistics(true);
+        // try {
+        // File f = new File("cloneLog");
+        // if (f.exists())
+        // f.delete();
+        // log = new BufferedWriter(new FileWriter("cloneLog"));
+        // } catch (IOException e) {
+        // // TODO Auto-generated catch block
+        // e.printStackTrace();
+        // }
+    }
+
+    public static final <T> T clone(T obj, String debug) {
+        if (obj != null) {
+            // System.out.println(debug);
+            // if(specificIgnored.contains(obj.getClass().getName()))
+            // return obj;
+            // System.out.println(obj.getClass().getName());
+            // System.out.println("source>"+obj.getClass().getName()
+            // +"..."+Thread.currentThread().getName());
+            T ret = cloner.deepClone(obj);
+            // T ret = obj;
+            return ret;
+            // return obj;
+        }
+
+        // System.out.println("Done");
+        return null;
+    }
+
+    public static IdentityHashMap<Object, Object> cloneCache = new IdentityHashMap<Object, Object>();;

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Constants.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Constants.java
index 9f22bda..57f3b68 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Constants.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Constants.java
@@ -1,13 +1,19 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 public class Constants {

-	public static int DEFAULT_LOG_SIZE = 2000;
-	public static int MAX_LOG_SIZE = 40000000;
+    public static int DEFAULT_LOG_SIZE = 2000;
+
+    public static int MAX_LOG_SIZE = 40000000;
+
+    public static double LOG_GROWTH_RATE = 2.5;
+
+    public static String REPLAY_CLASS_SUFFIX = "InvivoReplay";
+
+    public static String INNER_COPY_METHOD_NAME = "_Invivo___copy";
+
+    public static String OUTER_COPY_METHOD_NAME = "_Invivo_copy";

-	public static double LOG_GROWTH_RATE = 2.5;
-	public static String REPLAY_CLASS_SUFFIX = "InvivoReplay";
-	public static String INNER_COPY_METHOD_NAME = "_Invivo___copy";
-	public static String OUTER_COPY_METHOD_NAME = "_Invivo_copy";
-	public static String SET_FIELDS_METHOD_NAME = "_Invivo_set_fields";
+    public static String SET_FIELDS_METHOD_NAME = "_Invivo_set_fields";
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedLog.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedLog.java
index e991344..5cbee8e 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedLog.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedLog.java
@@ -1,18 +1,23 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.util.HashMap;

 public class ExportedLog {
-	public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-	public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-
-	public static int aLog_fill;
-	public static int globalReplayIndex = 0;
-	public static HashMap<String, Integer> aLog_replayIndex = new HashMap<String, Integer>();
-	public static void clearLog() {
-		aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-		aLog_owners =  new String[Constants.DEFAULT_LOG_SIZE];
-		aLog_fill = 0;
-		globalReplayIndex = 0;
-	}
+    public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static int aLog_fill;
+
+    public static int globalReplayIndex = 0;
+
+    public static HashMap<String, Integer> aLog_replayIndex = new HashMap<String, Integer>();
+
+    public static void clearLog() {
+        aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+        aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+        aLog_fill = 0;
+        globalReplayIndex = 0;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedSerializableLog.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedSerializableLog.java
index 8915e78..4444b99 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedSerializableLog.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/ExportedSerializableLog.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.io.IOException;
@@ -7,119 +8,147 @@ import java.io.Serializable;
 import java.util.HashMap;

 public class ExportedSerializableLog implements Serializable {
-	/**
+    /**
 	 *
 	 */
-	private static final long serialVersionUID = 1166783255069514273L;
-	public static Object[]	aLog	= new Object[Constants.DEFAULT_LOG_SIZE];
-	public static int[] iLog = new int[Constants.DEFAULT_LOG_SIZE];
-	public static long[] jLog = new long[Constants.DEFAULT_LOG_SIZE];
-	public static float[] fLog = new float[Constants.DEFAULT_LOG_SIZE];
-	public static double[] dLog = new double[Constants.DEFAULT_LOG_SIZE];
-	public static byte[] bLog = new byte[Constants.DEFAULT_LOG_SIZE];
-	public static boolean[] zLog = new boolean[Constants.DEFAULT_LOG_SIZE];
-	public static char[] cLog = new char[Constants.DEFAULT_LOG_SIZE];
-	public static short[] sLog = new short[Constants.DEFAULT_LOG_SIZE];
-	public static Object lock = new Object();
-	public static int aLog_fill, iLog_fill, jLog_fill, fLog_fill, dLog_fill, bLog_fill, zLog_fill, cLog_fill, sLog_fill;
-
-	public static HashMap<String,Integer> aLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> iLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> jLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> fLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> dLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> bLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> zLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> cLog_replayIndex = new HashMap<String,Integer>();
-	public static HashMap<String,Integer> sLog_replayIndex = new HashMap<String,Integer>();
-
-	public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] iLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] jLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] fLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] dLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] bLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] zLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] cLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] sLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-
-	public static void clearLog() {
-		aLog = new Serializable[Constants.DEFAULT_LOG_SIZE];
-		aLog_fill = 0;
-	}
-
-	private void writeObject(ObjectOutputStream oos) throws IOException {
-		oos.defaultWriteObject();
-		oos.writeInt(aLog_fill);
-		oos.writeObject(aLog);
-		oos.writeInt(iLog_fill);
-		oos.writeObject(iLog);
-		oos.writeInt(jLog_fill);
-		oos.writeObject(jLog);
-		oos.writeInt(fLog_fill);
-		oos.writeObject(fLog);
-		oos.writeInt(dLog_fill);
-		oos.writeObject(dLog);
-		oos.writeInt(bLog_fill);
-		oos.writeObject(bLog);
-		oos.writeInt(zLog_fill);
-		oos.writeObject(zLog);
-		oos.writeInt(cLog_fill);
-		oos.writeObject(cLog);
-		oos.writeInt(sLog_fill);
-		oos.writeObject(sLog);
-
-		oos.writeObject(aLog_owners);
-		oos.writeObject(iLog_owners);
-		oos.writeObject(jLog_owners);
-		oos.writeObject(fLog_owners);
-		oos.writeObject(dLog_owners);
-		oos.writeObject(bLog_owners);
-		oos.writeObject(zLog_owners);
-		oos.writeObject(cLog_owners);
-		oos.writeObject(sLog_owners);
-
-	}
-
-	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
-		ois.defaultReadObject();
-		aLog_fill = ois.readInt();
-		aLog = (Object[]) ois.readObject();
-		iLog_fill = ois.readInt();
-		iLog = (int[]) ois.readObject();
-		jLog_fill = ois.readInt();
-		jLog = (long[]) ois.readObject();
-		fLog_fill = ois.readInt();
-		fLog = (float[]) ois.readObject();
-		dLog_fill = ois.readInt();
-		dLog = (double[]) ois.readObject();
-		bLog_fill = ois.readInt();
-		bLog = (byte[]) ois.readObject();
-		zLog_fill = ois.readInt();
-		zLog = (boolean[]) ois.readObject();
-		cLog_fill = ois.readInt();
-		cLog = (char[]) ois.readObject();
-		sLog_fill = ois.readInt();
-		sLog = (short[]) ois.readObject();
-
-		aLog_owners = (String[]) ois.readObject();
-		iLog_owners = (String[]) ois.readObject();
-		jLog_owners = (String[]) ois.readObject();
-		fLog_owners = (String[]) ois.readObject();
-		dLog_owners = (String[]) ois.readObject();
-		bLog_owners = (String[]) ois.readObject();
-		zLog_owners = (String[]) ois.readObject();
-		cLog_owners = (String[]) ois.readObject();
-		sLog_owners = (String[]) ois.readObject();
-
-		ExportedSerializableLog.aLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.iLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.jLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.fLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.dLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.bLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.zLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.cLog_replayIndex = new HashMap<String,Integer>();
-		ExportedSerializableLog.sLog_replayIndex = new HashMap<String,Integer>();
-	}
-}
\ No newline at end of file
+    private static final long serialVersionUID = 1166783255069514273L;
+
+    public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+
+    public static int[] iLog = new int[Constants.DEFAULT_LOG_SIZE];
+
+    public static long[] jLog = new long[Constants.DEFAULT_LOG_SIZE];
+
+    public static float[] fLog = new float[Constants.DEFAULT_LOG_SIZE];
+
+    public static double[] dLog = new double[Constants.DEFAULT_LOG_SIZE];
+
+    public static byte[] bLog = new byte[Constants.DEFAULT_LOG_SIZE];
+
+    public static boolean[] zLog = new boolean[Constants.DEFAULT_LOG_SIZE];
+
+    public static char[] cLog = new char[Constants.DEFAULT_LOG_SIZE];
+
+    public static short[] sLog = new short[Constants.DEFAULT_LOG_SIZE];
+
+    public static Object lock = new Object();
+
+    public static int aLog_fill, iLog_fill, jLog_fill, fLog_fill, dLog_fill, bLog_fill, zLog_fill,
+            cLog_fill, sLog_fill;
+
+    public static HashMap<String, Integer> aLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> iLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> jLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> fLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> dLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> bLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> zLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> cLog_replayIndex = new HashMap<String, Integer>();
+
+    public static HashMap<String, Integer> sLog_replayIndex = new HashMap<String, Integer>();
+
+    public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] iLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] jLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] fLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] dLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] bLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] zLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] cLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] sLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static void clearLog() {
+        aLog = new Serializable[Constants.DEFAULT_LOG_SIZE];
+        aLog_fill = 0;
+    }
+
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(aLog_fill);
+        oos.writeObject(aLog);
+        oos.writeInt(iLog_fill);
+        oos.writeObject(iLog);
+        oos.writeInt(jLog_fill);
+        oos.writeObject(jLog);
+        oos.writeInt(fLog_fill);
+        oos.writeObject(fLog);
+        oos.writeInt(dLog_fill);
+        oos.writeObject(dLog);
+        oos.writeInt(bLog_fill);
+        oos.writeObject(bLog);
+        oos.writeInt(zLog_fill);
+        oos.writeObject(zLog);
+        oos.writeInt(cLog_fill);
+        oos.writeObject(cLog);
+        oos.writeInt(sLog_fill);
+        oos.writeObject(sLog);
+
+        oos.writeObject(aLog_owners);
+        oos.writeObject(iLog_owners);
+        oos.writeObject(jLog_owners);
+        oos.writeObject(fLog_owners);
+        oos.writeObject(dLog_owners);
+        oos.writeObject(bLog_owners);
+        oos.writeObject(zLog_owners);
+        oos.writeObject(cLog_owners);
+        oos.writeObject(sLog_owners);
+
+    }
+
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        aLog_fill = ois.readInt();
+        aLog = (Object[]) ois.readObject();
+        iLog_fill = ois.readInt();
+        iLog = (int[]) ois.readObject();
+        jLog_fill = ois.readInt();
+        jLog = (long[]) ois.readObject();
+        fLog_fill = ois.readInt();
+        fLog = (float[]) ois.readObject();
+        dLog_fill = ois.readInt();
+        dLog = (double[]) ois.readObject();
+        bLog_fill = ois.readInt();
+        bLog = (byte[]) ois.readObject();
+        zLog_fill = ois.readInt();
+        zLog = (boolean[]) ois.readObject();
+        cLog_fill = ois.readInt();
+        cLog = (char[]) ois.readObject();
+        sLog_fill = ois.readInt();
+        sLog = (short[]) ois.readObject();
+
+        aLog_owners = (String[]) ois.readObject();
+        iLog_owners = (String[]) ois.readObject();
+        jLog_owners = (String[]) ois.readObject();
+        fLog_owners = (String[]) ois.readObject();
+        dLog_owners = (String[]) ois.readObject();
+        bLog_owners = (String[]) ois.readObject();
+        zLog_owners = (String[]) ois.readObject();
+        cLog_owners = (String[]) ois.readObject();
+        sLog_owners = (String[]) ois.readObject();
+
+        ExportedSerializableLog.aLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.iLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.jLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.fLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.dLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.bLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.zLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.cLog_replayIndex = new HashMap<String, Integer>();
+        ExportedSerializableLog.sLog_replayIndex = new HashMap<String, Integer>();
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Instrumenter.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Instrumenter.java
index b0911c5..aa31cb0 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Instrumenter.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Instrumenter.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.io.ByteArrayOutputStream;
@@ -32,601 +33,620 @@ import org.objectweb.asm.util.CheckClassAdapter;

 import edu.columbia.cs.psl.chroniclerj.analysis.MutabilityAnalyzer;
 import edu.columbia.cs.psl.chroniclerj.struct.AnnotatedMethod;
+import edu.columbia.cs.psl.chroniclerj.visitor.CallbackDuplicatingClassVisitor;
 import edu.columbia.cs.psl.chroniclerj.visitor.NonDeterministicLoggingClassVisitor;

 public class Instrumenter {
-	public static URLClassLoader						loader;
-	private static Logger								logger				= Logger.getLogger(Instrumenter.class);
-	public static HashMap<String, AnnotatedMethod>		annotatedMethods	= new HashMap<String, AnnotatedMethod>();
-	public static HashMap<String, ClassNode>			instrumentedClasses	= new HashMap<String, ClassNode>();
-
-	private static MutabilityAnalyzer					ma					= new MutabilityAnalyzer(annotatedMethods);
-	public static HashMap<String, HashSet<MethodCall>>	methodCalls			= new HashMap<String, HashSet<MethodCall>>();
-	private static final int							NUM_PASSES			= 2;
-	private static final int							PASS_ANALYZE		= 0;
-	private static final int							PASS_OUTPUT			= 1;
-
-	private static int									pass_number			= 0;
-
-	private static File									rootOutputDir;
-	private static String								lastInstrumentedClass;
-
-	public static AnnotatedMethod getAnnotatedMethod(String owner, String name, String desc) {
-		String lookupKey = owner + "." + name + ":" + desc;
-		return annotatedMethods.get(lookupKey);
-	}
-
-	private static void analyzeClass(InputStream inputStream) {
-		try {
-			ClassNode analysisResult = ma.analyzeClass(new ClassReader(inputStream));
-			if(analysisResult == null)
-			{
-				logger.error("Null analysis result on this analysis");
-			}
-			instrumentedClasses.put(analysisResult.name, analysisResult);
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			logger.error("Error in analysis",e);
-		}
-	}
-
-	private static void finishedPass() {
-		switch (pass_number) {
-		case PASS_ANALYZE:
-			ma.doneSupplyingClasses();
-			break;
-		case PASS_OUTPUT:
-			break;
-		}
-	}
-
-
-	private static byte[] instrumentClass(InputStream is) {
-		try {
-			ClassReader cr = new ClassReader(is);
-			{
-				ClassWriter cw = new ClassWriter(cr, 0);
-				SerialVersionUIDAdder uidAdder = new SerialVersionUIDAdder(cw);
-				cr.accept(uidAdder, 0);
-				byte[] b = cw.toByteArray();
-				cr = new ClassReader(b);
-			}
-
-			ClassWriter cw = new InstrumenterClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES, loader);
-			NonDeterministicLoggingClassVisitor cv = new NonDeterministicLoggingClassVisitor(Opcodes.ASM4, cw);
-
-			cr.accept(cv, ClassReader.EXPAND_FRAMES);
-			if(methodCalls.containsKey(cv.getClassName()))
-				methodCalls.get(cv.getClassName()).addAll(cv.getLoggedMethodCalls());
-			else
-				methodCalls.put(cv.getClassName(), cv.getLoggedMethodCalls());
-			lastInstrumentedClass = cv.getClassName();
-			byte[] out = cw.toByteArray();
-			try{
-			 ClassReader cr2 = new ClassReader(out);
-			 cr2.accept(new CheckClassAdapter(new ClassWriter(0)), ClassReader.EXPAND_FRAMES);
-			}
-			catch(Exception ex)
-			{
-				System.err.println(lastInstrumentedClass);
-				ex.printStackTrace();
-			}
-			return out;
-		} catch (Exception ex) {
-			logger.error("Exception processing class: " + lastInstrumentedClass, ex);
-			ex.printStackTrace();
-			return null;
-		}
-	}
-
-	public static void _main(String[] args) {
-
-		String outputFolder = args[1];
-		rootOutputDir = new File(outputFolder);
-		if (!rootOutputDir.exists())
-			rootOutputDir.mkdir();
-		String inputFolder = args[0];
-		// Setup the class loader
-		URL[] urls = new URL[args.length - 2];
-		for (int i = 2; i < args.length; i++) {
-			File f = new File(args[i]);
-			if (!f.exists()) {
-				System.err.println("Unable to read path " + args[i]);
-				System.exit(-1);
-			}
-			if (f.isDirectory() && !f.getAbsolutePath().endsWith("/"))
-				f = new File(f.getAbsolutePath() + "/");
-			try {
-				urls[i - 2] = f.getCanonicalFile().toURI().toURL();
-			} catch (Exception ex) {
-				ex.printStackTrace();
-			}
-		}
-		loader = new URLClassLoader(urls, Instrumenter.class.getClassLoader());
-
-		for (pass_number = 0; pass_number < NUM_PASSES; pass_number++) // Do
-																		// each
-																		// pass.
-		{
-			File f = new File(inputFolder);
-			if (!f.exists()) {
-				System.err.println("Unable to read path " + inputFolder);
-				System.exit(-1);
-			}
-			if (f.isDirectory())
-				processDirectory(f, rootOutputDir, true);
-			else if (inputFolder.endsWith(".jar"))
-					processJar(f,rootOutputDir);
-			else if (inputFolder.endsWith(".zip"))
-				processZip(f,rootOutputDir);
-			else if (inputFolder.endsWith(".class"))
-				try {
-					processClass(f.getName(), new FileInputStream(f), rootOutputDir);
-				} catch (FileNotFoundException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			else {
-				System.err.println("Unknown type for path " + inputFolder);
-				System.exit(-1);
-			}
-			finishedPass();
-		}
-		// }
-
-	}
-
-	private static void processClass(String name, InputStream is, File outputDir) {
-		switch (pass_number) {
-		case PASS_ANALYZE:
-			analyzeClass(is);
-			break;
-		case PASS_OUTPUT:
-			try {
-					FileOutputStream fos = new FileOutputStream(outputDir.getPath() + File.separator + name);
-					ByteArrayOutputStream bos = new ByteArrayOutputStream();
-					lastInstrumentedClass = outputDir.getPath() + File.separator + name;
-					bos.write(instrumentClass(is));
-					bos.writeTo(fos);
-					fos.close();
-
-
-			} catch (Exception ex) {
-				ex.printStackTrace();
-			}
-		}
-	}
-
-
-
-	private static void processDirectory(File f, File parentOutputDir, boolean isFirstLevel) {
-		File thisOutputDir;
-		if (isFirstLevel) {
-			thisOutputDir = parentOutputDir;
-		} else {
-			thisOutputDir = new File(parentOutputDir.getAbsolutePath() + File.separator + f.getName());
-			if (pass_number == PASS_OUTPUT)
-				thisOutputDir.mkdir();
-		}
-		for (File fi : f.listFiles()) {
-			if (fi.isDirectory())
-				processDirectory(fi, thisOutputDir, false);
-			else if (fi.getName().endsWith(".class"))
-				try {
-					processClass(fi.getName(), new FileInputStream(fi), thisOutputDir);
-				} catch (FileNotFoundException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			else if (fi.getName().endsWith(".jar"))
-			{
-					if(!thisOutputDir.exists())
-						thisOutputDir.mkdir();
-					processJar(fi, thisOutputDir);
-			}
-			else if(fi.getName().endsWith(".zip"))
-			{
-				processZip(fi, thisOutputDir);
-			}
-			else if (pass_number == PASS_OUTPUT) {
-				File dest = new File(thisOutputDir.getPath() + File.separator + fi.getName());
-				FileChannel source = null;
-				FileChannel destination = null;
-
-				try {
-					source = new FileInputStream(fi).getChannel();
-					destination = new FileOutputStream(dest).getChannel();
-					destination.transferFrom(source, 0, source.size());
-				} catch (Exception ex) {
-					logger.error("Unable to copy file " + fi, ex);
-					System.exit(-1);
-				} finally {
-					if (source != null) {
-						try {
-							source.close();
-						} catch (IOException e) {
-							// TODO Auto-generated catch block
-							e.printStackTrace();
-						}
-					}
-					if (destination != null) {
-						try {
-							destination.close();
-						} catch (IOException e) {
-							// TODO Auto-generated catch block
-							e.printStackTrace();
-						}
-					}
-				}
-
-			}
-		}
-
-	}
-
-//	@Deprecated
-//	private static void processJar(InputStream inputStream, OutputStream os) {
-//		try {
-//
-//			File f = new File("/tmp/classfile");
-//			if(f.exists())
-//				f.delete();
-//			FileOutputStream fos = new FileOutputStream(f);
-//			byte buf[] = new byte[1024];
-//			int len;
-//			while((len=inputStream.read(buf)) > 0)
-//			{
-//				fos.write(buf,0,len);
-//			}
-//			fos.close();
-//			inputStream.close();
-//
-//			@SuppressWarnings("resource")
-//			JarFile jar = new JarFile(f);
-//			JarOutputStream jos = null;
-//			if (pass_number == PASS_OUTPUT)
-//				jos = new JarOutputStream(os);
-////				jos = new JarOutputStream(new FileOutputStream(outputDir.getPath() + File.separator + f.getName()));
-//			Enumeration<JarEntry> entries = jar.entries();
-//			while (entries.hasMoreElements()) {
-//				JarEntry e = entries.nextElement();
-//				switch (pass_number) {
-//				case PASS_ANALYZE:
-//					if (e.getName().endsWith(".class")) {
-//						analyzeClass(jar.getInputStream(e));
-//					}
-//					break;
-//				case PASS_OUTPUT:
-//					if (e.getName().endsWith(".class") && !e.getName().startsWith("java") && !e.getName().startsWith("org/objenesis")
-//							&& !e.getName().startsWith("com/thoughtworks/xstream/") && !e.getName().startsWith("com/rits/cloning")
-//							&& !e.getName().startsWith("com/apple/java/Application")) {
-//						{
-//							JarEntry outEntry = new JarEntry(e.getName());
-//							jos.putNextEntry(outEntry);
-//							byte[] clazz = instrumentClass(jar.getInputStream(e));
-//							if(clazz == null)
-//							{
-//								System.out.println("Unable to transform " + e.getName());
-//								InputStream is = jar.getInputStream(e);
-//								byte[] buffer = new byte[1024];
-//								while (true) {
-//									int count = is.read(buffer);
-//									if (count == -1)
-//										break;
-//									jos.write(buffer, 0, count);
-//								}
-//							}
-//							else
-//									jos.write(clazz);
-//							jos.closeEntry();
-//						}
-//
-//
-//					} else {
-//						JarEntry outEntry = new JarEntry(e.getName());
-//						if (e.isDirectory()) {
-//							jos.putNextEntry(outEntry);
-//							jos.closeEntry();
-//						} else if (e.getName().startsWith("META-INF") && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
-//							// don't copy this
-//						} else if (e.getName().equals("META-INF/MANIFEST.MF")) {
-//							Scanner s = new Scanner(jar.getInputStream(e));
-//							jos.putNextEntry(outEntry);
-//
-//							String curPair = "";
-//							while (s.hasNextLine()) {
-//								String line = s.nextLine();
-//								if (line.equals("")) {
-//									curPair += "\n";
-//									if (!curPair.contains("SHA1-Digest:"))
-//										jos.write(curPair.getBytes());
-//									curPair = "";
-//								} else {
-//									curPair += line + "\n";
-//								}
-//							}
-//							s.close();
-//							jos.write("\n".getBytes());
-//							jos.closeEntry();
-//						} else {
-//							jos.putNextEntry(outEntry);
-//							InputStream is = jar.getInputStream(e);
-//							byte[] buffer = new byte[1024];
-//							while (true) {
-//								int count = is.read(buffer);
-//								if (count == -1)
-//									break;
-//								jos.write(buffer, 0, count);
-//							}
-//							jos.closeEntry();
-//						}
-//					}
-//				}
-//
-//			}
-//			if(jos != null)
-//			{
-//				jos.flush();
-////				jos.finish();
-//			}
-//		} catch (Exception e) {
-//			// TODO Auto-generated catch block
-//			logger.error("Unable to process jar" , e);
-//			System.exit(-1);
-//		}
-//
-//	}
-	private static void processJar(File f, File outputDir) {
-		try {
-
-//			@SuppressWarnings("resource")
-			JarFile jar = new JarFile(f);
-			JarOutputStream jos = null;
-			if (pass_number == PASS_OUTPUT)
-//				jos = new JarOutputStream(os);
-				jos = new JarOutputStream(new FileOutputStream(outputDir.getPath() + File.separator + f.getName()));
-			Enumeration<JarEntry> entries = jar.entries();
-			while (entries.hasMoreElements()) {
-				JarEntry e = entries.nextElement();
-				switch (pass_number) {
-				case PASS_ANALYZE:
-					if (e.getName().endsWith(".class")) {
-						analyzeClass(jar.getInputStream(e));
-					}
-					break;
-				case PASS_OUTPUT:
-					if (e.getName().endsWith(".class") && !e.getName().startsWith("java") && !e.getName().startsWith("org/objenesis")
-							&& !e.getName().startsWith("com/thoughtworks/xstream/") && !e.getName().startsWith("com/rits/cloning")
-							&& !e.getName().startsWith("com/apple/java/Application") && !e.getName().startsWith("net/sf/cglib/")) {
-						{
-							JarEntry outEntry = new JarEntry(e.getName());
-							jos.putNextEntry(outEntry);
-							byte[] clazz = instrumentClass(jar.getInputStream(e));
-							if(clazz == null)
-							{
-								System.out.println("Failed to instrument " + e.getName());
-								InputStream is = jar.getInputStream(e);
-								byte[] buffer = new byte[1024];
-								while (true) {
-									int count = is.read(buffer);
-									if (count == -1)
-										break;
-									jos.write(buffer, 0, count);
-								}
-							}
-							else
-									jos.write(clazz);
-							jos.closeEntry();
-						}
-
-
-					} else {
-						JarEntry outEntry = new JarEntry(e.getName());
-						if (e.isDirectory()) {
-							jos.putNextEntry(outEntry);
-							jos.closeEntry();
-						} else if (e.getName().startsWith("META-INF") && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
-							// don't copy this
-						} else if (e.getName().equals("META-INF/MANIFEST.MF")) {
-							Scanner s = new Scanner(jar.getInputStream(e));
-							jos.putNextEntry(outEntry);
-
-							String curPair = "";
-							while (s.hasNextLine()) {
-								String line = s.nextLine();
-								if (line.equals("")) {
-									curPair += "\n";
-									if (!curPair.contains("SHA1-Digest:"))
-										jos.write(curPair.getBytes());
-									curPair = "";
-								} else {
-									curPair += line + "\n";
-								}
-							}
-							s.close();
-							jos.write("\n".getBytes());
-							jos.closeEntry();
-						} else {
-							jos.putNextEntry(outEntry);
-							InputStream is = jar.getInputStream(e);
-							byte[] buffer = new byte[1024];
-							while (true) {
-								int count = is.read(buffer);
-								if (count == -1)
-									break;
-								jos.write(buffer, 0, count);
-							}
-							jos.closeEntry();
-						}
-					}
-				}
-
-			}
-			if(jos != null)
-			{
-			jos.close();
-
-			}
-			jar.close();
-		} catch (Exception e) {
-			// TODO Auto-generated catch block
-			logger.error("Unable to process jar" , e);
-			System.exit(-1);
-		}
-
-	}
-	private static void processZip(File f, File outputDir) {
-		try {
-//			@SuppressWarnings("resource")
-			ZipFile zip = new ZipFile(f);
-			ZipOutputStream zos = null;
-			if (pass_number == PASS_OUTPUT)
-				zos = new ZipOutputStream(new FileOutputStream(outputDir.getPath() + File.separator + f.getName()));
-			Enumeration<? extends ZipEntry> entries = zip.entries();
-			while (entries.hasMoreElements()) {
-				ZipEntry e = entries.nextElement();
-				switch (pass_number) {
-				case PASS_ANALYZE:
-					if (e.getName().endsWith(".class")) {
-						analyzeClass((zip.getInputStream(e)));
-					}
-					else if(e.getName().endsWith(".jar"))
-					{
-						File tmp = new File("/tmp/classfile");
-						if(tmp.exists())
-							tmp.delete();
-						FileOutputStream fos = new FileOutputStream(tmp);
-						byte buf[] = new byte[1024];
-						int len;
-						InputStream is =zip.getInputStream(e);
-						while((len=is.read(buf)) > 0)
-						{
-							fos.write(buf,0,len);
-						}
-						is.close();
-						fos.close();
-
-						processJar(tmp, new File("/tmp"));
-//						processJar(jar.getInputStream(e), jos);
-					}
-					break;
-				case PASS_OUTPUT:
-					if (e.getName().endsWith(".class") && !e.getName().startsWith("java") && !e.getName().startsWith("org/objenesis")
-							&& !e.getName().startsWith("com/thoughtworks/xstream/") && !e.getName().startsWith("com/rits/cloning")
-							&& !e.getName().startsWith("com/apple/java/Application")) {
-						{
-							ZipEntry outEntry = new ZipEntry(e.getName());
-							zos.putNextEntry(outEntry);
-							byte[] clazz = instrumentClass(zip.getInputStream(e));
-							if(clazz == null)
-							{
-								InputStream is = zip.getInputStream(e);
-								byte[] buffer = new byte[1024];
-								while (true) {
-									int count = is.read(buffer);
-									if (count == -1)
-										break;
-									zos.write(buffer, 0, count);
-								}
-							}
-							else
-									zos.write(clazz);
-							zos.closeEntry();
-						}
-
-					}
-					else if(e.getName().endsWith(".jar"))
-					{
-						ZipEntry outEntry  =new ZipEntry(e.getName());
-//						jos.putNextEntry(outEntry);
-//						try {
-//							processJar(jar.getInputStream(e), jos);
-//							jos.closeEntry();
-//						} catch (FileNotFoundException e1) {
-//							// TODO Auto-generated catch block
-//							e1.printStackTrace();
-//						}
-
-						File tmp = new File("/tmp/classfile");
-						if(tmp.exists())
-							tmp.delete();
-						FileOutputStream fos = new FileOutputStream(tmp);
-						byte buf[] = new byte[1024];
-						int len;
-						InputStream is =zip.getInputStream(e);
-						while((len=is.read(buf)) > 0)
-						{
-							fos.write(buf,0,len);
-						}
-						is.close();
-						fos.close();
-//						System.out.println("Done reading");
-						processJar(tmp, new File("tmp2"));
-
-						zos.putNextEntry(outEntry);
-						is = new FileInputStream("tmp2/classfile");
-						byte[] buffer = new byte[1024];
-						while (true) {
-							int count = is.read(buffer);
-							if (count == -1)
-								break;
-							zos.write(buffer, 0, count);
-						}
-						is.close();
-						zos.closeEntry();
-//						jos.closeEntry();
-					}
-					else {
-						ZipEntry outEntry = new ZipEntry(e.getName());
-						if (e.isDirectory()) {
-							zos.putNextEntry(outEntry);
-							zos.closeEntry();
-						} else if (e.getName().startsWith("META-INF") && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
-							// don't copy this
-						} else if (e.getName().equals("META-INF/MANIFEST.MF")) {
-							Scanner s = new Scanner(zip.getInputStream(e));
-							zos.putNextEntry(outEntry);
-
-							String curPair = "";
-							while (s.hasNextLine()) {
-								String line = s.nextLine();
-								if (line.equals("")) {
-									curPair += "\n";
-									if (!curPair.contains("SHA1-Digest:"))
-										zos.write(curPair.getBytes());
-									curPair = "";
-								} else {
-									curPair += line + "\n";
-								}
-							}
-							s.close();
-							zos.write("\n".getBytes());
-							zos.closeEntry();
-						} else {
-							zos.putNextEntry(outEntry);
-							InputStream is = zip.getInputStream(e);
-							byte[] buffer = new byte[1024];
-							while (true) {
-								int count = is.read(buffer);
-								if (count == -1)
-									break;
-								zos.write(buffer, 0, count);
-							}
-							zos.closeEntry();
-						}
-					}
-				}
-
-			}
-			if (pass_number == PASS_OUTPUT) {
-				zos.close();
-				zip.close();
-			}
-		} catch (Exception e) {
-			// TODO Auto-generated catch block
-			logger.error("Unable to process zip" + f, e);
-			System.exit(-1);
-		}
-
-	}
+    public static URLClassLoader loader;
+
+    private static Logger logger = Logger.getLogger(Instrumenter.class);
+
+    public static HashMap<String, AnnotatedMethod> annotatedMethods = new HashMap<String, AnnotatedMethod>();
+
+    public static HashMap<String, ClassNode> instrumentedClasses = new HashMap<String, ClassNode>();
+
+    private static MutabilityAnalyzer ma = new MutabilityAnalyzer(annotatedMethods);
+
+    public static HashMap<String, HashSet<MethodCall>> methodCalls = new HashMap<String, HashSet<MethodCall>>();
+
+    private static final int NUM_PASSES = 2;
+
+    private static final int PASS_ANALYZE = 0;
+
+    private static final int PASS_OUTPUT = 1;
+
+    public static final boolean IS_DACAPO = true;
+
+    private static int pass_number = 0;
+
+    public static final boolean FINALIZERS_ENABLED = true;
+
+    public static final String FIELD_LOGICAL_CLOCK = "_chronicler_clock";
+
+    private static File rootOutputDir;
+
+    private static String lastInstrumentedClass;
+
+    public static String getParentType(String type) {
+        final ClassNode cn = instrumentedClasses.get(type);
+        if (cn == null)
+            return null;
+        return cn.superName;
+    }
+
+    public static AnnotatedMethod getAnnotatedMethod(String owner, String name, String desc) {
+        String lookupKey = owner + "." + name + ":" + desc;
+        return annotatedMethods.get(lookupKey);
+    }
+
+    private static void analyzeClass(InputStream inputStream) {
+        try {
+            ClassNode analysisResult = ma.analyzeClass(new ClassReader(inputStream));
+            if (analysisResult == null) {
+                logger.error("Null analysis result on this analysis");
+            }
+            instrumentedClasses.put(analysisResult.name, analysisResult);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            logger.error("Error in analysis", e);
+        }
+    }
+
+    private static void finishedPass() {
+        switch (pass_number) {
+            case PASS_ANALYZE:
+                ma.doneSupplyingClasses();
+                break;
+            case PASS_OUTPUT:
+                break;
+        }
+    }
+
+    private static byte[] instrumentClass(InputStream is) {
+        try {
+            ClassReader cr = new ClassReader(is);
+            {
+                ClassWriter cw = new ClassWriter(cr, 0);
+                SerialVersionUIDAdder uidAdder = new SerialVersionUIDAdder(cw);
+                cr.accept(uidAdder, 0);
+                byte[] b = cw.toByteArray();
+                cr = new ClassReader(b);
+            }
+
+            ClassWriter cw = new InstrumenterClassWriter(cr, ClassWriter.COMPUTE_MAXS
+                    | ClassWriter.COMPUTE_FRAMES, loader);
+            NonDeterministicLoggingClassVisitor cv = new NonDeterministicLoggingClassVisitor(
+                    Opcodes.ASM4, cw);
+            CallbackDuplicatingClassVisitor callbackDuplicator = new CallbackDuplicatingClassVisitor(
+                    Opcodes.ASM4, cv);
+
+            cr.accept(callbackDuplicator, ClassReader.EXPAND_FRAMES);
+            if (methodCalls.containsKey(cv.getClassName()))
+                methodCalls.get(cv.getClassName()).addAll(cv.getLoggedMethodCalls());
+            else
+                methodCalls.put(cv.getClassName(), cv.getLoggedMethodCalls());
+            lastInstrumentedClass = cv.getClassName();
+            byte[] out = cw.toByteArray();
+            try {
+                ClassReader cr2 = new ClassReader(out);
+                cr2.accept(new CheckClassAdapter(new ClassWriter(0)), ClassReader.EXPAND_FRAMES);
+            } catch (Exception ex) {
+                System.err.println(lastInstrumentedClass);
+                ex.printStackTrace();
+            }
+            return out;
+        } catch (Exception ex) {
+            logger.error("Exception processing class: " + lastInstrumentedClass, ex);
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    public static void _main(String[] args) {
+
+        String outputFolder = args[1];
+        rootOutputDir = new File(outputFolder);
+        if (!rootOutputDir.exists())
+            rootOutputDir.mkdir();
+        String inputFolder = args[0];
+        // Setup the class loader
+        URL[] urls = new URL[args.length - 2];
+        for (int i = 2; i < args.length; i++) {
+            File f = new File(args[i]);
+            if (!f.exists()) {
+                System.err.println("Unable to read path " + args[i]);
+                System.exit(-1);
+            }
+            if (f.isDirectory() && !f.getAbsolutePath().endsWith("/"))
+                f = new File(f.getAbsolutePath() + "/");
+            try {
+                urls[i - 2] = f.getCanonicalFile().toURI().toURL();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+        }
+        loader = new URLClassLoader(urls, Instrumenter.class.getClassLoader());
+
+        for (pass_number = 0; pass_number < NUM_PASSES; pass_number++) // Do
+                                                                       // each
+                                                                       // pass.
+        {
+            File f = new File(inputFolder);
+            if (!f.exists()) {
+                System.err.println("Unable to read path " + inputFolder);
+                System.exit(-1);
+            }
+            if (f.isDirectory())
+                processDirectory(f, rootOutputDir, true);
+            else if (inputFolder.endsWith(".jar"))
+                processJar(f, rootOutputDir);
+            else if (inputFolder.endsWith(".zip"))
+                processZip(f, rootOutputDir);
+            else if (inputFolder.endsWith(".class"))
+                try {
+                    processClass(f.getName(), new FileInputStream(f), rootOutputDir);
+                } catch (FileNotFoundException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            else {
+                System.err.println("Unknown type for path " + inputFolder);
+                System.exit(-1);
+            }
+            finishedPass();
+        }
+        // }
+
+    }
+
+    private static void processClass(String name, InputStream is, File outputDir) {
+        switch (pass_number) {
+            case PASS_ANALYZE:
+                analyzeClass(is);
+                break;
+            case PASS_OUTPUT:
+                try {
+                    FileOutputStream fos = new FileOutputStream(outputDir.getPath()
+                            + File.separator + name);
+                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                    lastInstrumentedClass = outputDir.getPath() + File.separator + name;
+                    bos.write(instrumentClass(is));
+                    bos.writeTo(fos);
+                    fos.close();
+
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+        }
+    }
+
+    private static void processDirectory(File f, File parentOutputDir, boolean isFirstLevel) {
+        File thisOutputDir;
+        if (isFirstLevel) {
+            thisOutputDir = parentOutputDir;
+        } else {
+            thisOutputDir = new File(parentOutputDir.getAbsolutePath() + File.separator
+                    + f.getName());
+            if (pass_number == PASS_OUTPUT)
+                thisOutputDir.mkdir();
+        }
+        for (File fi : f.listFiles()) {
+            if (fi.isDirectory())
+                processDirectory(fi, thisOutputDir, false);
+            else if (fi.getName().endsWith(".class"))
+                try {
+                    processClass(fi.getName(), new FileInputStream(fi), thisOutputDir);
+                } catch (FileNotFoundException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            else if (fi.getName().endsWith(".jar")) {
+                if (!thisOutputDir.exists())
+                    thisOutputDir.mkdir();
+                processJar(fi, thisOutputDir);
+            } else if (fi.getName().endsWith(".zip")) {
+                processZip(fi, thisOutputDir);
+            } else if (pass_number == PASS_OUTPUT) {
+                File dest = new File(thisOutputDir.getPath() + File.separator + fi.getName());
+                FileChannel source = null;
+                FileChannel destination = null;
+
+                try {
+                    source = new FileInputStream(fi).getChannel();
+                    destination = new FileOutputStream(dest).getChannel();
+                    destination.transferFrom(source, 0, source.size());
+                } catch (Exception ex) {
+                    logger.error("Unable to copy file " + fi, ex);
+                    System.exit(-1);
+                } finally {
+                    if (source != null) {
+                        try {
+                            source.close();
+                        } catch (IOException e) {
+                            // TODO Auto-generated catch block
+                            e.printStackTrace();
+                        }
+                    }
+                    if (destination != null) {
+                        try {
+                            destination.close();
+                        } catch (IOException e) {
+                            // TODO Auto-generated catch block
+                            e.printStackTrace();
+                        }
+                    }
+                }
+
+            }
+        }
+
+    }
+
+    // @Deprecated
+    // private static void processJar(InputStream inputStream, OutputStream os)
+    // {
+    // try {
+    //
+    // File f = new File("/tmp/classfile");
+    // if(f.exists())
+    // f.delete();
+    // FileOutputStream fos = new FileOutputStream(f);
+    // byte buf[] = new byte[1024];
+    // int len;
+    // while((len=inputStream.read(buf)) > 0)
+    // {
+    // fos.write(buf,0,len);
+    // }
+    // fos.close();
+    // inputStream.close();
+    //
+    // @SuppressWarnings("resource")
+    // JarFile jar = new JarFile(f);
+    // JarOutputStream jos = null;
+    // if (pass_number == PASS_OUTPUT)
+    // jos = new JarOutputStream(os);
+    // // jos = new JarOutputStream(new FileOutputStream(outputDir.getPath() +
+    // File.separator + f.getName()));
+    // Enumeration<JarEntry> entries = jar.entries();
+    // while (entries.hasMoreElements()) {
+    // JarEntry e = entries.nextElement();
+    // switch (pass_number) {
+    // case PASS_ANALYZE:
+    // if (e.getName().endsWith(".class")) {
+    // analyzeClass(jar.getInputStream(e));
+    // }
+    // break;
+    // case PASS_OUTPUT:
+    // if (e.getName().endsWith(".class") && !e.getName().startsWith("java") &&
+    // !e.getName().startsWith("org/objenesis")
+    // && !e.getName().startsWith("com/thoughtworks/xstream/") &&
+    // !e.getName().startsWith("com/rits/cloning")
+    // && !e.getName().startsWith("com/apple/java/Application")) {
+    // {
+    // JarEntry outEntry = new JarEntry(e.getName());
+    // jos.putNextEntry(outEntry);
+    // byte[] clazz = instrumentClass(jar.getInputStream(e));
+    // if(clazz == null)
+    // {
+    // System.out.println("Unable to transform " + e.getName());
+    // InputStream is = jar.getInputStream(e);
+    // byte[] buffer = new byte[1024];
+    // while (true) {
+    // int count = is.read(buffer);
+    // if (count == -1)
+    // break;
+    // jos.write(buffer, 0, count);
+    // }
+    // }
+    // else
+    // jos.write(clazz);
+    // jos.closeEntry();
+    // }
+    //
+    //
+    // } else {
+    // JarEntry outEntry = new JarEntry(e.getName());
+    // if (e.isDirectory()) {
+    // jos.putNextEntry(outEntry);
+    // jos.closeEntry();
+    // } else if (e.getName().startsWith("META-INF") &&
+    // (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
+    // // don't copy this
+    // } else if (e.getName().equals("META-INF/MANIFEST.MF")) {
+    // Scanner s = new Scanner(jar.getInputStream(e));
+    // jos.putNextEntry(outEntry);
+    //
+    // String curPair = "";
+    // while (s.hasNextLine()) {
+    // String line = s.nextLine();
+    // if (line.equals("")) {
+    // curPair += "\n";
+    // if (!curPair.contains("SHA1-Digest:"))
+    // jos.write(curPair.getBytes());
+    // curPair = "";
+    // } else {
+    // curPair += line + "\n";
+    // }
+    // }
+    // s.close();
+    // jos.write("\n".getBytes());
+    // jos.closeEntry();
+    // } else {
+    // jos.putNextEntry(outEntry);
+    // InputStream is = jar.getInputStream(e);
+    // byte[] buffer = new byte[1024];
+    // while (true) {
+    // int count = is.read(buffer);
+    // if (count == -1)
+    // break;
+    // jos.write(buffer, 0, count);
+    // }
+    // jos.closeEntry();
+    // }
+    // }
+    // }
+    //
+    // }
+    // if(jos != null)
+    // {
+    // jos.flush();
+    // // jos.finish();
+    // }
+    // } catch (Exception e) {
+    // // TODO Auto-generated catch block
+    // logger.error("Unable to process jar" , e);
+    // System.exit(-1);
+    // }
+    //
+    // }
+    private static void processJar(File f, File outputDir) {
+        try {
+
+            // @SuppressWarnings("resource")
+            JarFile jar = new JarFile(f);
+            JarOutputStream jos = null;
+            if (pass_number == PASS_OUTPUT)
+                // jos = new JarOutputStream(os);
+                jos = new JarOutputStream(new FileOutputStream(outputDir.getPath() + File.separator
+                        + f.getName()));
+            Enumeration<JarEntry> entries = jar.entries();
+            while (entries.hasMoreElements()) {
+                JarEntry e = entries.nextElement();
+                switch (pass_number) {
+                    case PASS_ANALYZE:
+                        if (e.getName().endsWith(".class")) {
+                            analyzeClass(jar.getInputStream(e));
+                        }
+                        break;
+                    case PASS_OUTPUT:
+                        if (e.getName().endsWith(".class") && !e.getName().startsWith("java")
+                                && !e.getName().startsWith("org/objenesis")
+                                && !e.getName().startsWith("com/thoughtworks/xstream/")
+                                && !e.getName().startsWith("com/rits/cloning")
+                                && !e.getName().startsWith("com/apple/java/Application")
+                                && !e.getName().startsWith("net/sf/cglib/")) {
+                            {
+                                JarEntry outEntry = new JarEntry(e.getName());
+                                jos.putNextEntry(outEntry);
+                                byte[] clazz = instrumentClass(jar.getInputStream(e));
+                                if (clazz == null) {
+                                    System.out.println("Failed to instrument " + e.getName());
+                                    InputStream is = jar.getInputStream(e);
+                                    byte[] buffer = new byte[1024];
+                                    while (true) {
+                                        int count = is.read(buffer);
+                                        if (count == -1)
+                                            break;
+                                        jos.write(buffer, 0, count);
+                                    }
+                                } else
+                                    jos.write(clazz);
+                                jos.closeEntry();
+                            }
+
+                        } else {
+                            JarEntry outEntry = new JarEntry(e.getName());
+                            if (e.isDirectory()) {
+                                jos.putNextEntry(outEntry);
+                                jos.closeEntry();
+                            } else if (e.getName().startsWith("META-INF")
+                                    && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
+                                // don't copy this
+                            } else if (e.getName().equals("META-INF/MANIFEST.MF")) {
+                                Scanner s = new Scanner(jar.getInputStream(e));
+                                jos.putNextEntry(outEntry);
+
+                                String curPair = "";
+                                while (s.hasNextLine()) {
+                                    String line = s.nextLine();
+                                    if (line.equals("")) {
+                                        curPair += "\n";
+                                        if (!curPair.contains("SHA1-Digest:"))
+                                            jos.write(curPair.getBytes());
+                                        curPair = "";
+                                    } else {
+                                        curPair += line + "\n";
+                                    }
+                                }
+                                s.close();
+                                jos.write("\n".getBytes());
+                                jos.closeEntry();
+                            } else {
+                                jos.putNextEntry(outEntry);
+                                InputStream is = jar.getInputStream(e);
+                                byte[] buffer = new byte[1024];
+                                while (true) {
+                                    int count = is.read(buffer);
+                                    if (count == -1)
+                                        break;
+                                    jos.write(buffer, 0, count);
+                                }
+                                jos.closeEntry();
+                            }
+                        }
+                }
+
+            }
+            if (jos != null) {
+                jos.close();
+
+            }
+            jar.close();
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            logger.error("Unable to process jar", e);
+            System.exit(-1);
+        }
+
+    }
+
+    private static void processZip(File f, File outputDir) {
+        try {
+            // @SuppressWarnings("resource")
+            ZipFile zip = new ZipFile(f);
+            ZipOutputStream zos = null;
+            if (pass_number == PASS_OUTPUT)
+                zos = new ZipOutputStream(new FileOutputStream(outputDir.getPath() + File.separator
+                        + f.getName()));
+            Enumeration<? extends ZipEntry> entries = zip.entries();
+            while (entries.hasMoreElements()) {
+                ZipEntry e = entries.nextElement();
+                switch (pass_number) {
+                    case PASS_ANALYZE:
+                        if (e.getName().endsWith(".class")) {
+                            analyzeClass((zip.getInputStream(e)));
+                        } else if (e.getName().endsWith(".jar")) {
+                            File tmp = new File("/tmp/classfile");
+                            if (tmp.exists())
+                                tmp.delete();
+                            FileOutputStream fos = new FileOutputStream(tmp);
+                            byte buf[] = new byte[1024];
+                            int len;
+                            InputStream is = zip.getInputStream(e);
+                            while ((len = is.read(buf)) > 0) {
+                                fos.write(buf, 0, len);
+                            }
+                            is.close();
+                            fos.close();
+
+                            processJar(tmp, new File("/tmp"));
+                            // processJar(jar.getInputStream(e), jos);
+                        }
+                        break;
+                    case PASS_OUTPUT:
+                        if (e.getName().endsWith(".class") && !e.getName().startsWith("java")
+                                && !e.getName().startsWith("org/objenesis")
+                                && !e.getName().startsWith("com/thoughtworks/xstream/")
+                                && !e.getName().startsWith("com/rits/cloning")
+                                && !e.getName().startsWith("com/apple/java/Application")) {
+                            {
+                                ZipEntry outEntry = new ZipEntry(e.getName());
+                                zos.putNextEntry(outEntry);
+                                byte[] clazz = instrumentClass(zip.getInputStream(e));
+                                if (clazz == null) {
+                                    InputStream is = zip.getInputStream(e);
+                                    byte[] buffer = new byte[1024];
+                                    while (true) {
+                                        int count = is.read(buffer);
+                                        if (count == -1)
+                                            break;
+                                        zos.write(buffer, 0, count);
+                                    }
+                                } else
+                                    zos.write(clazz);
+                                zos.closeEntry();
+                            }
+
+                        } else if (e.getName().endsWith(".jar")) {
+                            ZipEntry outEntry = new ZipEntry(e.getName());
+                            // jos.putNextEntry(outEntry);
+                            // try {
+                            // processJar(jar.getInputStream(e), jos);
+                            // jos.closeEntry();
+                            // } catch (FileNotFoundException e1) {
+                            // // TODO Auto-generated catch block
+                            // e1.printStackTrace();
+                            // }
+
+                            File tmp = new File("/tmp/classfile");
+                            if (tmp.exists())
+                                tmp.delete();
+                            FileOutputStream fos = new FileOutputStream(tmp);
+                            byte buf[] = new byte[1024];
+                            int len;
+                            InputStream is = zip.getInputStream(e);
+                            while ((len = is.read(buf)) > 0) {
+                                fos.write(buf, 0, len);
+                            }
+                            is.close();
+                            fos.close();
+                            // System.out.println("Done reading");
+                            processJar(tmp, new File("tmp2"));
+
+                            zos.putNextEntry(outEntry);
+                            is = new FileInputStream("tmp2/classfile");
+                            byte[] buffer = new byte[1024];
+                            while (true) {
+                                int count = is.read(buffer);
+                                if (count == -1)
+                                    break;
+                                zos.write(buffer, 0, count);
+                            }
+                            is.close();
+                            zos.closeEntry();
+                            // jos.closeEntry();
+                        } else {
+                            ZipEntry outEntry = new ZipEntry(e.getName());
+                            if (e.isDirectory()) {
+                                zos.putNextEntry(outEntry);
+                                zos.closeEntry();
+                            } else if (e.getName().startsWith("META-INF")
+                                    && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
+                                // don't copy this
+                            } else if (e.getName().equals("META-INF/MANIFEST.MF")) {
+                                Scanner s = new Scanner(zip.getInputStream(e));
+                                zos.putNextEntry(outEntry);
+
+                                String curPair = "";
+                                while (s.hasNextLine()) {
+                                    String line = s.nextLine();
+                                    if (line.equals("")) {
+                                        curPair += "\n";
+                                        if (!curPair.contains("SHA1-Digest:"))
+                                            zos.write(curPair.getBytes());
+                                        curPair = "";
+                                    } else {
+                                        curPair += line + "\n";
+                                    }
+                                }
+                                s.close();
+                                zos.write("\n".getBytes());
+                                zos.closeEntry();
+                            } else {
+                                zos.putNextEntry(outEntry);
+                                InputStream is = zip.getInputStream(e);
+                                byte[] buffer = new byte[1024];
+                                while (true) {
+                                    int count = is.read(buffer);
+                                    if (count == -1)
+                                        break;
+                                    zos.write(buffer, 0, count);
+                                }
+                                zos.closeEntry();
+                            }
+                        }
+                }
+
+            }
+            if (pass_number == PASS_OUTPUT) {
+                zos.close();
+                zip.close();
+            }
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            logger.error("Unable to process zip" + f, e);
+            System.exit(-1);
+        }
+
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/InstrumenterClassWriter.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/InstrumenterClassWriter.java
index 15034f2..069386e 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/InstrumenterClassWriter.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/InstrumenterClassWriter.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.net.URLClassLoader;
@@ -7,28 +8,30 @@ import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassWriter;

 public class InstrumenterClassWriter extends ClassWriter {
-	private static Logger logger = Logger.getLogger(InstrumenterClassWriter.class);
-	private ClassLoader loader;
-	public InstrumenterClassWriter(ClassReader classReader, int flags, ClassLoader loader) {
-		super(classReader, flags);
-		this.loader = loader;
-	}
-
-	public InstrumenterClassWriter(int flags, URLClassLoader loader) {
-		super(flags);
-		this.loader=loader;
-	}
-
-	@Override
-	protected String getCommonSuperClass(String type1, String type2) {
-		Class<?> c, d;
+    private static Logger logger = Logger.getLogger(InstrumenterClassWriter.class);
+
+    private ClassLoader loader;
+
+    public InstrumenterClassWriter(ClassReader classReader, int flags, ClassLoader loader) {
+        super(classReader, flags);
+        this.loader = loader;
+    }
+
+    public InstrumenterClassWriter(int flags, URLClassLoader loader) {
+        super(flags);
+        this.loader = loader;
+    }
+
+    @Override
+    protected String getCommonSuperClass(String type1, String type2) {
+        Class<?> c, d;
         try {
             c = Class.forName(type1.replace('/', '.'), false, loader);
             d = Class.forName(type2.replace('/', '.'), false, loader);
         } catch (ClassNotFoundException e) {
-        	logger.debug("Error while finding common super class for " + type1 +"; " + type2,e);
-        	return "java/lang/Object";
-//        	throw new RuntimeException(e);
+            logger.debug("Error while finding common super class for " + type1 + "; " + type2, e);
+            return "java/lang/Object";
+            // throw new RuntimeException(e);
         }
         if (c.isAssignableFrom(d)) {
             return type1;
@@ -44,5 +47,5 @@ public class InstrumenterClassWriter extends ClassWriter {
             } while (!c.isAssignableFrom(d));
             return c.getName().replace('.', '/');
         }
-	}
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Log.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Log.java
index a40f6d0..d1bc33d 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Log.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Log.java
@@ -1,22 +1,28 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;

 public class Log {
-	public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-	public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static Lock logLock = new ReentrantLock();
-	public static int logsize = 0;
-	public static int aLog_fill;
-
-
-	public static void clearLog() {
-		logsize = 0;
-		aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-		aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-
-		aLog_fill = 0;
-
-	}
+    public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static Lock logLock = new ReentrantLock();
+
+    public static int logsize = 0;
+
+    public static int aLog_fill;
+
+    public static long _chronicler_clock = 0;
+
+    public static void clearLog() {
+        logsize = 0;
+        aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+        aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+        aLog_fill = 0;
+
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Main.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Main.java
index 20e149c..06927ed 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Main.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/Main.java
@@ -1,53 +1,55 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import edu.columbia.cs.psl.chroniclerj.replay.ReplayRunner;
 import edu.columbia.cs.psl.chroniclerj.replay.Replayer;

 public class Main {
-	public static void main(String[] args) {
-		if (args.length < 1) {
-			System.err.println("Usage: java -jar chroniclerj.jar -instrument [source] [dest-deploy] [dest-replay] {additional-classpath-entries}");
-			System.err.println("or");
-			System.err.println("Usage: java -jar chroniclerj.jar -replay [testcase]");
-			System.exit(-1);
-		}
-		if (args[0].equals("-instrument")) {
-			if (args.length < 4) {
-				System.err.println("Usage: java -jar chroniclerj.jar -instrument [source] [dest-deploy] [dest-replay] {additional-classpath-entries}");
-				System.exit(-1);
-			}
-			String[] instrumenterArgs = new String[args.length-1];
-			instrumenterArgs[0] = args[1];
-			instrumenterArgs[1] = args[2];
-			instrumenterArgs[2] = args[1];
-			for (int i = 4; i < args.length; i++) {
-				instrumenterArgs[i-1] = args[i];
-			}
-			Instrumenter._main(instrumenterArgs);
-			Replayer._main(new String[] { args[1], args[3] });
-		}
-		else if(args[0].equals("-replay"))
-		{
-			if(args.length < 2)
-			{
-				System.err.println("Usage: java -jar chroniclerj.jar -replay [testcase] {classpath}");
-				System.exit(-1);
-			}
-			String[] classpath = new String[args.length];
-			classpath[0] = System.getProperty("user.dir");
-			classpath[1] = args[1];
-			for(int i = 2; i < args.length; i++)
-			{
-				classpath[i] = args[i];
-			}
-			ReplayRunner._main(classpath);
-		}
-		else
-		{
-			System.err.println("Usage: java -jar chroniclerj.jar -instrument [source] [dest-deploy] [dest-replay] {additional-classpath-entries}");
-			System.err.println("or");
-			System.err.println("Usage: java -jar chroniclerj.jar -replay [testcase]");
-			System.exit(-1);
-		}
-	}
+    public static void main(String[] args) {
+        if (args.length < 1) {
+            System.err
+                    .println("Usage: java -jar chroniclerj.jar -instrument [source] [dest-deploy] [dest-replay] {additional-classpath-entries}");
+            System.err.println("or");
+            System.err.println("Usage: java -jar chroniclerj.jar -replay [testcase]");
+            System.exit(-1);
+        }
+        if (args[0].equals("-instrument")) {
+            if (args.length < 4) {
+                System.err
+                        .println("Usage: java -jar chroniclerj.jar -instrument [source] [dest-deploy] [dest-replay] {additional-classpath-entries}");
+                System.exit(-1);
+            }
+            String[] instrumenterArgs = new String[args.length - 1];
+            instrumenterArgs[0] = args[1];
+            instrumenterArgs[1] = args[2];
+            instrumenterArgs[2] = args[1];
+            for (int i = 4; i < args.length; i++) {
+                instrumenterArgs[i] = args[i];
+            }
+            Instrumenter._main(instrumenterArgs);
+            // TODO uncomment for release
+            Replayer._main(new String[] {
+                    args[1], args[3]
+            });
+        } else if (args[0].equals("-replay")) {
+            if (args.length < 2) {
+                System.err
+                        .println("Usage: java -jar chroniclerj.jar -replay [testcase] {classpath}");
+                System.exit(-1);
+            }
+            String[] classpath = new String[args.length];
+            classpath[0] = System.getProperty("user.dir");
+            classpath[1] = args[1];
+            for (int i = 2; i < args.length; i++) {
+                classpath[i] = args[i];
+            }
+            ReplayRunner._main(classpath);
+        } else {
+            System.err
+                    .println("Usage: java -jar chroniclerj.jar -instrument [source] [dest-deploy] [dest-replay] {additional-classpath-entries}");
+            System.err.println("or");
+            System.err.println("Usage: java -jar chroniclerj.jar -replay [testcase]");
+            System.exit(-1);
+        }
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodCall.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodCall.java
index 1a84364..fbcf365 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodCall.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodCall.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.util.HashSet;
@@ -7,161 +8,197 @@ import javax.swing.JFrame;
 import org.objectweb.asm.Type;

 public class MethodCall {
-	private String sourceMethodName;
-	private String sourceMethodDesc;
-	private String sourceClass;
-	private int pc;
-	private int lineNumber;
-	private String methodOwner;
-	private String methodName;
-	private String methodDesc;
-	private boolean isStatic;
-
-	private static HashSet<String> serializableClasses = new HashSet<String>();
-	static{
-		serializableClasses.add(Type.getType(String.class).getInternalName());
-		serializableClasses.add(Type.getType(JFrame.class).getInternalName());
-
-	}
-	public MethodCall(String sourceMethodName, String sourceMethodDesc, String sourceClass, int pc, int lineNumber, String methodOwner, String methodName, String methodDesc, boolean isStatic) {
-		this.sourceMethodName = sourceMethodName;
-		this.sourceMethodDesc = sourceMethodDesc;
-		this.sourceClass = sourceClass;
-		this.pc = pc;
-		this.lineNumber = lineNumber;
-		this.methodOwner = methodOwner;
-		this.methodName = methodName;
-		this.methodDesc = methodDesc;
-		this.isStatic = isStatic;
-	}
-	public boolean isStatic() {
-		return isStatic;
-	}
-	public String getSourceMethodName() {
-		return sourceMethodName;
-	}
-	public String getSourceMethodDesc() {
-		return sourceMethodDesc;
-	}
-	public String getSourceClass() {
-		return sourceClass;
-	}
-	public int getPc() {
-		return pc;
-	}
-	public int getLineNumber() {
-		return lineNumber;
-	}
-	public String getMethodOwner() {
-		return methodOwner;
-	}
-	public String getMethodName() {
-		return methodName;
-	}
-	public String getMethodDesc() {
-		return methodDesc;
-	}
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result + lineNumber;
-		result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
-		result = prime * result + pc;
-		result = prime * result + ((sourceClass == null) ? 0 : sourceClass.hashCode());
-		result = prime * result + ((sourceMethodName == null) ? 0 : sourceMethodName.hashCode());
-		return result;
-	}
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		MethodCall other = (MethodCall) obj;
-		if(other.getLogFieldName().equals(this.getLogFieldName()) && other.sourceClass.equals(this.sourceClass))
-			return true;
-		return false;
-	}
-	public static String getLogClassName(Type t)
-	{
-		if((t.getSort() != Type.OBJECT  && t.getSort() != Type.ARRAY)|| //primitives
-				(t.getSort() == Type.OBJECT && serializableClasses.contains(t.getInternalName())) || //serializble
-				(t.getSort() == Type.ARRAY && ((t.getElementType().getSort() != Type.OBJECT && t.getElementType().getSort() != Type.ARRAY)|| serializableClasses.contains(t.getElementType().getInternalName())))) // array of prims or array of serializable
-			return Type.getInternalName(SerializableLog.class);
-		else
-			return Type.getInternalName(Log.class);
-	}
-	public static String getReplayClassName(Type t)
-	{
-		if(getLogClassName(t).equals(Type.getInternalName(SerializableLog.class)))
-			return Type.getInternalName(ExportedSerializableLog.class);
-		else
-			return Type.getInternalName(ExportedLog.class);
-	}
-	public String getReplayClassName()
-	{
-		return getReplayClassName(Type.getReturnType(methodDesc));
-	}
-	public String getLogClassName()
-	{
-		return getLogClassName(Type.getReturnType(methodDesc));
-	}
-	public String getCapturePrefix()
-	{
-		String r = sourceMethodName.replace("<", "___").replace(">", "___")+"$$$$"+methodName.replace("<", "___").replace(">", "___")+"$$$$";
-		r += lineNumber+ "$"+pc;
-		return r;
-	}
-	public String getLogFieldName()
-	{
-//		Type[] args = Type.getArgumentTypes(methodDesc);
-//		String r = sourceMethodName.replace("<", "___").replace(">", "___")+"$$$$"+methodName+"$$$$";
-//		for(Type t : args)
-//		{
-//			r+=t.getInternalName().replace("/", "$")+"$$";
-//		}
-//		r += lineNumber+ "$"+pc;
-		Type t= Type.getReturnType(methodDesc);
-		if(t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY || methodName.equals("<init>"))
-			return "aLog";
-		else if(t.getSort() == Type.VOID)
-			return "bLog";
-		else
-			return t.getDescriptor().toLowerCase()+"Log";
-	}
-	public Type getReturnType()
-	{
-		return Type.getMethodType(methodDesc).getReturnType();
-	}
-	public Type getLogFieldType() {
-		Type t = Type.getMethodType(methodDesc).getReturnType();
-		if(t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)
-			return Type.getType("[Ljava/lang/Object;");
-		else if(t.getSort() == Type.VOID)
-			return Type.getType("["+Type.BYTE);
-		else
-			return Type.getType("["+t.getDescriptor());
-//		return Type.getType("["+Type.getMethodType(methodDesc).getReturnType().getDescriptor());
-	}
-	public static String getLogFieldName(Type t)
-	{
-		if(t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)
-			return "aLog";
-		else if(t.getSort() == Type.VOID)
-			return "bLog";
-		else
-			return t.getDescriptor().toLowerCase()+"Log";
-	}
-	public static Type getLogFieldType(Type t)
-	{
-		if(t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)
-			return Type.getType("[Ljava/lang/Object;");
-		else if(t.getSort() == Type.VOID)
-			return Type.getType("["+Type.BYTE);
-		else
-			return Type.getType("["+t.getDescriptor());
-	}
+    private String sourceMethodName;
+
+    private String sourceMethodDesc;
+
+    private String sourceClass;
+
+    private int pc;
+
+    private int lineNumber;
+
+    private String methodOwner;
+
+    private String methodName;
+
+    private String methodDesc;
+
+    private boolean isStatic;
+
+    private static HashSet<String> serializableClasses = new HashSet<String>();
+    static {
+        serializableClasses.add(Type.getType(String.class).getInternalName());
+        serializableClasses.add(Type.getType(JFrame.class).getInternalName());
+
+    }
+
+    public MethodCall(String sourceMethodName, String sourceMethodDesc, String sourceClass, int pc,
+            int lineNumber, String methodOwner, String methodName, String methodDesc,
+            boolean isStatic) {
+        this.sourceMethodName = sourceMethodName;
+        this.sourceMethodDesc = sourceMethodDesc;
+        this.sourceClass = sourceClass;
+        this.pc = pc;
+        this.lineNumber = lineNumber;
+        this.methodOwner = methodOwner;
+        this.methodName = methodName;
+        this.methodDesc = methodDesc;
+        this.isStatic = isStatic;
+    }
+
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    public String getSourceMethodName() {
+        return sourceMethodName;
+    }
+
+    public String getSourceMethodDesc() {
+        return sourceMethodDesc;
+    }
+
+    public String getSourceClass() {
+        return sourceClass;
+    }
+
+    public int getPc() {
+        return pc;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public String getMethodOwner() {
+        return methodOwner;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public String getMethodDesc() {
+        return methodDesc;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + lineNumber;
+        result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
+        result = prime * result + pc;
+        result = prime * result + ((sourceClass == null) ? 0 : sourceClass.hashCode());
+        result = prime * result + ((sourceMethodName == null) ? 0 : sourceMethodName.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        MethodCall other = (MethodCall) obj;
+        if (other.getLogFieldName().equals(this.getLogFieldName())
+                && other.sourceClass.equals(this.sourceClass))
+            return true;
+        return false;
+    }
+
+    public static String getLogClassName(Type t) {
+        if ((t.getSort() != Type.OBJECT && t.getSort() != Type.ARRAY) || // primitives
+                (t.getSort() == Type.OBJECT && serializableClasses.contains(t.getInternalName()))
+                || // serializble
+                (t.getSort() == Type.ARRAY && ((t.getElementType().getSort() != Type.OBJECT && t
+                        .getElementType().getSort() != Type.ARRAY) || serializableClasses
+                        .contains(t.getElementType().getInternalName())))) // array
+                                                                           // of
+                                                                           // prims
+                                                                           // or
+                                                                           // array
+                                                                           // of
+                                                                           // serializable
+            return Type.getInternalName(SerializableLog.class);
+        else
+            return Type.getInternalName(Log.class);
+    }
+
+    public static String getReplayClassName(Type t) {
+        if (getLogClassName(t).equals(Type.getInternalName(SerializableLog.class)))
+            return Type.getInternalName(ExportedSerializableLog.class);
+        else
+            return Type.getInternalName(ExportedLog.class);
+    }
+
+    public String getReplayClassName() {
+        return getReplayClassName(Type.getReturnType(methodDesc));
+    }
+
+    public String getLogClassName() {
+        return getLogClassName(Type.getReturnType(methodDesc));
+    }
+
+    public String getCapturePrefix() {
+        String r = sourceMethodName.replace("<", "___").replace(">", "___") + "$$$$"
+                + methodName.replace("<", "___").replace(">", "___") + "$$$$";
+        r += lineNumber + "$" + pc;
+        return r;
+    }
+
+    public String getLogFieldName() {
+        // Type[] args = Type.getArgumentTypes(methodDesc);
+        // String r = sourceMethodName.replace("<", "___").replace(">",
+        // "___")+"$$$$"+methodName+"$$$$";
+        // for(Type t : args)
+        // {
+        // r+=t.getInternalName().replace("/", "$")+"$$";
+        // }
+        // r += lineNumber+ "$"+pc;
+        Type t = Type.getReturnType(methodDesc);
+        if (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY || methodName.equals("<init>"))
+            return "aLog";
+        else if (t.getSort() == Type.VOID)
+            return "bLog";
+        else
+            return t.getDescriptor().toLowerCase() + "Log";
+    }
+
+    public Type getReturnType() {
+        return Type.getMethodType(methodDesc).getReturnType();
+    }
+
+    public Type getLogFieldType() {
+        Type t = Type.getMethodType(methodDesc).getReturnType();
+        if (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)
+            return Type.getType("[Ljava/lang/Object;");
+        else if (t.getSort() == Type.VOID)
+            return Type.getType("[" + Type.BYTE);
+        else
+            return Type.getType("[" + t.getDescriptor());
+        // return
+        // Type.getType("["+Type.getMethodType(methodDesc).getReturnType().getDescriptor());
+    }
+
+    public static String getLogFieldName(Type t) {
+        if (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)
+            return "aLog";
+        else if (t.getSort() == Type.VOID)
+            return "bLog";
+        else
+            return t.getDescriptor().toLowerCase() + "Log";
+    }
+
+    public static Type getLogFieldType(Type t) {
+        if (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)
+            return Type.getType("[Ljava/lang/Object;");
+        else if (t.getSort() == Type.VOID)
+            return Type.getType("[" + Type.BYTE);
+        else
+            return Type.getType("[" + t.getDescriptor());
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodInterceptor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodInterceptor.java
new file mode 100644
index 0000000..fcfd2f1
--- /dev/null
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/MethodInterceptor.java
@@ -0,0 +1,86 @@
+
+package edu.columbia.cs.psl.chroniclerj;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.objectweb.asm.Type;
+
+import edu.columbia.cs.psl.chroniclerj.replay.ReplayRunner;
+import edu.columbia.cs.psl.chroniclerj.replay.ReplayUtils;
+import edu.columbia.cs.psl.chroniclerj.visitor.NonDeterministicLoggingMethodVisitor;
+
+public class MethodInterceptor {
+    public static Object invoke(Method method, Object obj, Object... args)
+            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        if (NonDeterministicLoggingMethodVisitor.isND(
+                method.getDeclaringClass().getName().replace(".", "/"), method.getName(),
+                Type.getMethodDescriptor(method))) {
+            Object ret = method.invoke(obj, args);
+            if (args != null)
+                for (Object arg : args) {
+                    if (arg != null && arg.getClass().isArray())
+                        log(arg);
+                }
+            log(ret);
+            return ret;
+        } else
+            return method.invoke(obj, args);
+    }
+
+    public static Object invokeReplay(Method method, Object obj, Object... args)
+            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        if (NonDeterministicLoggingMethodVisitor.isND(
+                method.getDeclaringClass().getName().replace(".", "/"), method.getName(),
+                Type.getMethodDescriptor(method))) {
+            if (args != null)
+                for (int i = 0; i < args.length; i++) {
+                    if (args[i] != null && args[i].getClass().isArray())
+                        args[i] = replay();
+                }
+            Object ret = replay();
+            return ret;
+        } else
+            return method.invoke(obj, args);
+    }
+
+    private static Object replay() {
+        Log.logLock.lock();
+
+        int i = ReplayUtils.getNextIndexO(ExportedLog.aLog_replayIndex, ExportedLog.aLog_owners,
+                ExportedLog.aLog_fill, "edu/columbia/cs/psl/chroniclerj/ExportedLog",
+                ExportedLog.aLog);
+        if (i < 0) {
+            ReplayRunner.loadNextLog("edu/columbia/cs/psl/chroniclerj/ExportedLog");
+            return replay();
+        }
+        Object ret = ExportedLog.aLog[i];
+
+        ReplayUtils.getNextIndexO(ExportedLog.aLog_replayIndex, ExportedLog.aLog_owners,
+                ExportedLog.aLog_fill, "edu/columbia/cs/psl/chroniclerj/ExportedLog",
+                ExportedLog.aLog);
+        ExportedLog.aLog_replayIndex.put(Thread.currentThread().getName(), i + 1);
+        ExportedLog.globalReplayIndex++;
+        Log.logLock.unlock();
+        return ret;
+    }
+
+    private static void log(Object obj) {
+        Log.logLock.lock();
+
+        if (Log.aLog_fill == Log.aLog.length) {
+            Object[] temp = new Object[(int) (Log.aLog.length * 2.5)];
+            System.arraycopy(Log.aLog, 0, temp, 0, Log.aLog.length);
+            Log.aLog = temp;
+
+            String[] tempOwners = new String[(int) (Log.aLog.length * 2.5)];
+            System.arraycopy(Log.aLog_owners, 0, tempOwners, 0, Log.aLog_owners.length);
+            Log.aLog_owners = tempOwners;
+        }
+        Log.aLog[Log.aLog_fill] = CloningUtils.clone(obj, "reflection");
+        Log.aLog_owners[Log.aLog_fill] = Thread.currentThread().getName();
+        Log.aLog_fill++;
+        Log.logsize++;
+        Log.logLock.unlock();
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/SerializableLog.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/SerializableLog.java
index b496218..27c503a 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/SerializableLog.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/SerializableLog.java
@@ -1,33 +1,51 @@
+
 package edu.columbia.cs.psl.chroniclerj;

 import java.io.Serializable;

-public class SerializableLog implements Serializable{
-
-	private static final long	serialVersionUID	= 4627796984904522647L;
-	public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
-
-	public static int[] iLog = new int[Constants.DEFAULT_LOG_SIZE];
-	public static long[] jLog = new long[Constants.DEFAULT_LOG_SIZE];
-	public static float[] fLog = new float[Constants.DEFAULT_LOG_SIZE];
-	public static double[] dLog = new double[Constants.DEFAULT_LOG_SIZE];
-	public static byte[] bLog = new byte[Constants.DEFAULT_LOG_SIZE];
-	public static boolean[] zLog = new boolean[Constants.DEFAULT_LOG_SIZE];
-	public static char[] cLog = new char[Constants.DEFAULT_LOG_SIZE];
-	public static short[] sLog = new short[Constants.DEFAULT_LOG_SIZE];
-
-	public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] iLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] jLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] fLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] dLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] bLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] zLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] cLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-	public static String[] sLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
-
-	public static int logsize = 0;
-	public static int aLog_fill, iLog_fill, jLog_fill, fLog_fill, dLog_fill, bLog_fill, zLog_fill, cLog_fill, sLog_fill;
-
-
+public class SerializableLog implements Serializable {
+
+    private static final long serialVersionUID = 4627796984904522647L;
+
+    public static Object[] aLog = new Object[Constants.DEFAULT_LOG_SIZE];
+
+    public static int[] iLog = new int[Constants.DEFAULT_LOG_SIZE];
+
+    public static long[] jLog = new long[Constants.DEFAULT_LOG_SIZE];
+
+    public static float[] fLog = new float[Constants.DEFAULT_LOG_SIZE];
+
+    public static double[] dLog = new double[Constants.DEFAULT_LOG_SIZE];
+
+    public static byte[] bLog = new byte[Constants.DEFAULT_LOG_SIZE];
+
+    public static boolean[] zLog = new boolean[Constants.DEFAULT_LOG_SIZE];
+
+    public static char[] cLog = new char[Constants.DEFAULT_LOG_SIZE];
+
+    public static short[] sLog = new short[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] aLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] iLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] jLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] fLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] dLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] bLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] zLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] cLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static String[] sLog_owners = new String[Constants.DEFAULT_LOG_SIZE];
+
+    public static int logsize = 0;
+
+    public static int aLog_fill, iLog_fill, jLog_fill, fLog_fill, dLog_fill, bLog_fill, zLog_fill,
+            cLog_fill, sLog_fill;
+
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/analysis/MutabilityAnalyzer.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/analysis/MutabilityAnalyzer.java
index 7bce31d..5006da7 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/analysis/MutabilityAnalyzer.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/analysis/MutabilityAnalyzer.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.analysis;

 import java.util.ArrayList;
@@ -23,677 +24,710 @@ import edu.columbia.cs.psl.chroniclerj.visitor.NonDeterministicLoggingMethodVisi

 public class MutabilityAnalyzer implements Opcodes {

-	private static Logger logger = Logger.getLogger(MutabilityAnalyzer.class);
-	public MutabilityAnalyzer(HashMap<String, AnnotatedMethod> lookupCache) {
-		this.lookupCache = lookupCache;
-	}
-	private HashMap<String, AnnotatedMethod> lookupCache;
-	private static boolean enabled = false;
-	/**
-	 * Call when done calling analyzeClass
-	 */
-	public void doneSupplyingClasses()
-	{
-		if(!enabled)
-			return;
-		for (String s : lookupCache.keySet()) {
-			AnnotatedMethod method = lookupCache.get(s);
-			if (method.isMutatesFieldsDirectly()) {
-				for (AnnotatedMethod caller : method.functionsThatCallMe)
-				{
-					method.setMutatesFields();
-					addAllRecursively(caller);
-				}
-			}
-		}
-	}
-
-	private void addAllRecursively(AnnotatedMethod method) {
-		if (method.isMutatesFields())
-			return;
-		method.setMutatesFields();
-		for (AnnotatedMethod caller : method.functionsThatCallMe)
-			addAllRecursively(caller);
-	}
-
-	/**
-	 *
-	 * Approach:
-	 * Find all methods that can change fields
-	 * Recurse that out to find all methods that might call methods that can change fields
-	 *
-	 * At the start of each methods that might change fields, keep track in a field:
-	 * 		The starting count values for each storage array *recursively* this can be in local variables though
-	 * When a field is changed OR a "not safe" local variable (not safe if it might point to a field):
-	 * 		Store a reference to the field/local variable and a copy of the value
-	 * When a method is invoked that might change fields, track:
-	 * 		A reference to the callee
-	 *
-	 *
-	 * When we need to reset the system to a pre-crash state:
-	 * 		Go through the starting count for each field and compare with each current count. If count changed, reset and note
-	 * 		To find each field, may need to (recursively) descend through the holder points-to fields
-	 *
-	 * Take 2:
-	 * At the start of each method, make a reference copy to a local variable of every backup pt that we will subsequently read but might change
-	 *
-	 * If this method directly changes fields, store a local variable with the original value at time of change
-	 * If this method indirectly changes fields, store a local variable with the original value before the method is called
-	 * @param cr
-	 */
-	public ClassNode analyzeClass(ClassReader cr) {
-		ClassNode cn = new ClassNode();
-		cr.accept(cn, ClassReader.SKIP_DEBUG);
-
-		for (Object o : cn.methods) {
-			MethodNode thisMethodNode = (MethodNode) o;
-			AnnotatedMethod thisMethod = findOrAddMethod(cn.name, thisMethodNode);
-			thisMethod.setFullyDiscovered(true);
-			thisMethod.setAccess(thisMethodNode.access);
-
-			if((thisMethodNode.access & ACC_NATIVE) != 0) // is native
-					NonDeterministicLoggingMethodVisitor.registerNDMethod(cn.name, thisMethodNode.name, thisMethodNode.desc);
-
-			ListIterator<?> i = thisMethodNode.instructions.iterator();
-			boolean isFirstInsn = true;
-			while (i.hasNext()) {
-				AbstractInsnNode n = (AbstractInsnNode) i.next();
-				if (n.getType() == AbstractInsnNode.FIELD_INSN) // Field
-																// Instruction
-				{
-					FieldInsnNode fn = (FieldInsnNode) n;
-					if (n.getOpcode() == Opcodes.PUTSTATIC) {
-						// This instruction is changing a static field. Previous
-						// instruction is the value to set to
-						FieldExpression pi = new FieldExpression(fn.name, fn.owner, fn.desc, n.getOpcode());
-						thisMethod.getPutFieldInsns().add(pi);
-						thisMethod.setMutatesFieldsDirectly();
-					} else if (n.getOpcode() == Opcodes.PUTFIELD) {
-
-						// This instruction is changing a field.
-						// Previous instruction will have the value that we are
-						// setting to
-						FieldExpression pi = new FieldExpression(fn.name, fn.owner, fn.desc, n.getOpcode());
-						pi.setParent(parentInstructionOf(thisMethodNode, pi, thisMethodNode.instructions.iterator(i.previousIndex())));
-						thisMethod.getPutFieldInsns().add(pi);
-						thisMethod.setMutatesFieldsDirectly();
-					}
-				} else if (n.getType() == AbstractInsnNode.METHOD_INSN) // Method
-																		// invocation
-				{
-					MethodInsnNode whatWeCall = (MethodInsnNode) n;
-					AnnotatedMethod otherMethod = findOrAddMethod(whatWeCall.owner, whatWeCall.name, whatWeCall.desc,0);
-					otherMethod.functionsThatCallMe.add(thisMethod);
-					MethodExpression otherMethodExp = new MethodExpression(otherMethod, whatWeCall.getOpcode());
-					otherMethodExp.getParams().addAll(paramsOf(thisMethodNode, otherMethodExp, thisMethodNode.instructions.iterator(i.previousIndex())));
-
-					if(whatWeCall.getOpcode() != Opcodes.INVOKESTATIC)
-						otherMethodExp.setParent(parentInstructionOf(thisMethodNode, otherMethodExp, thisMethodNode.instructions.iterator(i.previousIndex())));
-
-					if(NonDeterministicLoggingMethodVisitor.isND(whatWeCall.owner, whatWeCall.name, whatWeCall.desc) &&
-							whatWeCall.name.equals("<init>") && whatWeCall.owner.equals(cn.superName) && thisMethodNode.name.equals("<init>") && isFirstInsn)
-					{
-						NonDeterministicLoggingMethodVisitor.registerNDMethod(cn.name, thisMethodNode.name, thisMethodNode.desc);
-					}
-
-					thisMethod.functionsThatICall.add(otherMethodExp);
-
-					isFirstInsn = false;
-				} else if (n.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN) // Invoke
-																				// dynamic
-				{
-
-				}
-			}
-		}
-		ClassNode ret = new ClassNode();
-		ret.name = cn.name;
-		ret.fields = cn.fields;
-		ret.superName = cn.superName;
-		ret.interfaces = cn.interfaces;
-		return ret;
-	}
-
-
-
-	private List<Expression> paramsOf(MethodNode sourceMethod, MethodExpression methodInsnToFindParamsOf, ListIterator<?> i) {
-		ArrayList<Expression> ret = new ArrayList<Expression>();
-		int nParams = methodInsnToFindParamsOf.getNumParamsNeeded();
-		int nToSkip = 0;
-		logger.debug("Finding " + nParams + " params for " + methodInsnToFindParamsOf);
-		while (i.hasPrevious() && nParams > 0) {
-			AbstractInsnNode n = (AbstractInsnNode) i.previous();
-			switch (n.getType()) {
-			case AbstractInsnNode.METHOD_INSN:
-				MethodInsnNode min = (MethodInsnNode) n;
-				MethodExpression mi = new MethodExpression(findOrAddMethod(min.owner, min.name, min.desc, min.getOpcode() == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0), min.getOpcode());
-				logger.debug("Encountered " + mi + ", skipping " + mi.getStackElementsToSkip());
-
-				if (nToSkip == 0) {
-					mi.setParent(parentInstructionOf(sourceMethod, mi, sourceMethod.instructions.iterator(i.previousIndex() + 1)));
-					mi.getParams().addAll(paramsOf(sourceMethod, mi, sourceMethod.instructions.iterator(i.previousIndex() + 1)));
-
-					ret.add(mi);
-					nParams--;
-				}
-				nToSkip--;
-				nToSkip += mi.getStackElementsToSkip() + (mi.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1);
-				logger.debug("NTOS" + nToSkip);
-				if (nToSkip < 0)
-					nToSkip = 0;
-				break;
-			case AbstractInsnNode.INVOKE_DYNAMIC_INSN:
-				// TODO
-				break;
-			case AbstractInsnNode.TYPE_INSN:
-				switch (n.getOpcode()) {
-				case NEW:
-					if (nToSkip == 0) {
-						ret.add(new SimpleExpression(n));
-						nParams--;
-					} else
-						nToSkip--;
-					break;
-				case ANEWARRAY:
-				case CHECKCAST:
-				case INSTANCEOF:
-				}
-				break;
-			case AbstractInsnNode.FIELD_INSN:
-				FieldInsnNode fn = (FieldInsnNode) n;
-				if (n.getOpcode() == Opcodes.GETFIELD) {
-					FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc, n.getOpcode());
-					logger.debug("Encoutnered" + fi);
-					if (nToSkip == 0) {
-						fi.setParent(parentInstructionOf(sourceMethod, fi, sourceMethod.instructions.iterator(i.previousIndex() + 1)));
-						ret.add(fi);
-						nParams--;
-					}
-					nToSkip--;
-					nToSkip += 1;
-				} else if (n.getOpcode() == Opcodes.GETSTATIC) {
-					FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc, n.getOpcode());
-					if (nToSkip == 0) {
-						ret.add(fi);
-						nParams--;
-					}
-					nToSkip--;
-				}
-				break;
-			case AbstractInsnNode.INT_INSN:
-			case AbstractInsnNode.LDC_INSN:
-			case AbstractInsnNode.VAR_INSN:
-				switch (n.getOpcode()) {
-				case Opcodes.ILOAD:
-				case Opcodes.LLOAD:
-				case Opcodes.FLOAD:
-				case Opcodes.DLOAD:
-				case Opcodes.ALOAD:
-				case BIPUSH:
-				case SIPUSH:
-				case Opcodes.LDC:
-					if (nToSkip == 0) {
-						ret.add(new SimpleExpression(n));
-						nParams--;
-					} else
-						nToSkip--;
-					break;
-				case ISTORE:
-				case LSTORE:
-				case FSTORE:
-				case DSTORE:
-				case ASTORE:
-					nToSkip--;
-					nToSkip++;
-					break;
-				case LALOAD:
-				case FALOAD:
-				case AALOAD:
-				case BALOAD:
-				case CALOAD:
-				case SALOAD:
-					nToSkip--;
-					nToSkip += 2;
-					break;
-				case AASTORE:
-				case IASTORE:
-				case FASTORE:
-				case DASTORE:
-				case BASTORE:
-				case CASTORE:
-				case SASTORE:
-					nToSkip += 3;
-					break;
-				case NEWARRAY:
-					nToSkip--;
-					nToSkip++;
-				default:
-					logger.debug("Unknown opcode " + n.getOpcode());
-					break;
-				}
-				break;
-			case AbstractInsnNode.INSN:
-				switch (n.getOpcode()) {
-				// case ATHROW: // 1 before n/a after
-				// popValue();
-				// onMethodExit(opcode);
-				// break;
-				//
-				// case LRETURN: // 2 before n/a after
-				// case DRETURN: // 2 before n/a after
-				// popValue();
-				// popValue();
-				// onMethodExit(opcode);
-				// break;
-
-				case NOP:
-				case LNEG:
-				case DNEG:
-				case FNEG:
-				case INEG:
-				case L2D:
-				case D2L:
-				case F2I:
-				case I2B:
-				case I2C:
-				case I2S:
-				case I2F:
-				case F2L: // 1 before 2 after
-				case F2D:
-				case I2L:
-				case I2D:
-
-				case L2I: // 2 before 1 after
-				case L2F: // 2 before 1 after
-				case D2I: // 2 before 1 after
-				case D2F: // 2 before 1 after
-				case ARRAYLENGTH:
-				case SWAP:
-					nToSkip--;
-					nToSkip++;
-					break;
-
-				case IADD:
-				case FADD:
-				case ISUB:
-				case LSHL: // 3 before 2 after
-				case LSHR: // 3 before 2 after
-				case LUSHR: // 3 before 2 after
-				case LSUB:
-				case LMUL:
-				case LDIV:
-				case LREM:
-				case LADD:
-				case LAND:
-				case LOR:
-				case LXOR:
-				case DADD:
-				case DMUL:
-				case DSUB:
-				case DDIV:
-				case DREM:
-
-				case FSUB:
-				case FMUL:
-				case FDIV:
-				case FREM:
-				case FCMPL: // 2 before 1 after
-				case FCMPG: // 2 before 1 after
-				case IMUL:
-				case IDIV:
-				case IREM:
-				case ISHL:
-				case ISHR:
-				case IUSHR:
-				case IAND:
-				case IOR:
-				case IXOR:
-
-				case IALOAD: // remove 2 add 1
-				case FALOAD: // remove 2 add 1
-				case AALOAD: // remove 2 add 1
-				case BALOAD: // remove 2 add 1
-				case CALOAD: // remove 2 add 1
-				case SALOAD: // remove 2 add 1
-				case LALOAD: // remove 2 add 2
-				case DALOAD: // remove 2 add 2
-
-				case LCMP: // 4 before 1 after
-				case DCMPL:
-				case DCMPG:
-					nToSkip--;
-					nToSkip += 2;
-					break;
-
-				case ACONST_NULL:
-				case ICONST_M1:
-				case ICONST_0:
-				case ICONST_1:
-				case ICONST_2:
-				case ICONST_3:
-				case ICONST_4:
-				case ICONST_5:
-				case FCONST_0:
-				case FCONST_1:
-				case FCONST_2:
-				case LCONST_0:
-				case LCONST_1:
-				case DCONST_0:
-				case DCONST_1:
-
-				case DUP:
-				case DUP_X1:
-				case DUP_X2:
-
-				case DUP2: // is this wrong to assume that dup2 is only used on
-							// longs and not 2 shorts?
-				case DUP2_X1:
-				case DUP2_X2:
-					// case POP:
-					// case MONITORENTER:
-					// case MONITOREXIT:
-					// case POP2:
-					if (nToSkip == 0) {
-						ret.add(new SimpleExpression(n));
-						nParams--;
-					} else
-						nToSkip--;
-					break;
-
-				case LASTORE:
-				case DASTORE:
-				case IASTORE:
-				case FASTORE:
-				case AASTORE:
-				case BASTORE:
-				case CASTORE:
-				case SASTORE:
-					nToSkip--;
-					nToSkip += 3;
-					break;
-				}
-				break;
-			}
-		}
-		return ret;
-	}
-
-	private Expression parentInstructionOf(MethodNode mn, Expression insnToFindParentOf, ListIterator<?> i) {
-		if (insnToFindParentOf.getType() == Expression.METHOD_TYPE && ((MethodExpression) insnToFindParentOf).getMethod().getName().equals("<init>"))
-			return null;
-		int nToSkip = insnToFindParentOf.getStackElementsToSkip();
-		logger.debug("Examining " + insnToFindParentOf.toString() + " for parent, skipping " + nToSkip);
-		while (i.hasPrevious()) {
-			AbstractInsnNode n = (AbstractInsnNode) i.previous();
-			switch (n.getType()) {
-			case AbstractInsnNode.METHOD_INSN:
-				MethodInsnNode min = (MethodInsnNode) n;
-				MethodExpression mi = new MethodExpression(findOrAddMethod(min.owner, min.name, min.desc, min.getOpcode() == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0), min.getOpcode());
-				logger.debug("Encountered " + mi + ", skipping " + mi.getStackElementsToSkip());
-
-				if (nToSkip == 0) {
-					mi.setParent(parentInstructionOf(mn, mi, mn.instructions.iterator(i.previousIndex() + 1)));
-					mi.getParams().addAll(paramsOf(mn, mi, mn.instructions.iterator(i.previousIndex() + 1)));
-					return mi;
-				}
-				nToSkip--;
-				nToSkip += mi.getStackElementsToSkip() + (mi.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1);
-				logger.debug("NTos" + nToSkip);
-				break;
-			case AbstractInsnNode.INVOKE_DYNAMIC_INSN:
-				// TODO
-				break;
-			case AbstractInsnNode.TYPE_INSN:
-				switch (n.getOpcode()) {
-				case NEW:
-					if (nToSkip == 0) {
-						return new SimpleExpression(n);
-					} else
-						nToSkip--;
-					break;
-				case ANEWARRAY:
-				case CHECKCAST:
-				case INSTANCEOF:
-				}
-				break;
-			case AbstractInsnNode.FIELD_INSN:
-				FieldInsnNode fn = (FieldInsnNode) n;
-				if (n.getOpcode() == Opcodes.GETFIELD) {
-					FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc, n.getOpcode());
-					logger.debug("Encoutnered field: " + fi);
-					if (nToSkip == 0) {
-						fi.setParent(parentInstructionOf(mn, fi, mn.instructions.iterator(i.previousIndex() + 1)));
-						return fi;
-					}
-					nToSkip--;
-					nToSkip += 1;
-					logger.debug("Ntos" + nToSkip);
-				} else if (n.getOpcode() == Opcodes.GETSTATIC) {
-					FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc, n.getOpcode());
-					if (nToSkip == 0) {
-						fi.setParent(parentInstructionOf(mn, fi, mn.instructions.iterator(i.previousIndex() + 1)));
-						return fi;
-					}
-					nToSkip--;
-					// nToSkip += 1;
-				}
-				break;
-			case AbstractInsnNode.INT_INSN:
-			case AbstractInsnNode.LDC_INSN:
-			case AbstractInsnNode.VAR_INSN:
-				switch (n.getOpcode()) {
-				case Opcodes.ILOAD:
-				case Opcodes.LLOAD:
-				case Opcodes.FLOAD:
-				case Opcodes.DLOAD:
-				case Opcodes.ALOAD:
-				case BIPUSH:
-				case SIPUSH:
-				case Opcodes.LDC:
-					if (nToSkip == 0) {
-						return new SimpleExpression(n);
-					}
-					nToSkip--;
-					break;
-				case ISTORE:
-				case LSTORE:
-				case FSTORE:
-				case DSTORE:
-				case ASTORE:
-					nToSkip--;
-					nToSkip++;
-					break;
-				case LALOAD:
-				case FALOAD:
-				case AALOAD:
-				case BALOAD:
-				case CALOAD:
-				case SALOAD:
-					nToSkip--;
-					nToSkip += 2;
-					break;
-				case AASTORE:
-				case IASTORE:
-				case FASTORE:
-				case DASTORE:
-				case BASTORE:
-				case CASTORE:
-				case SASTORE:
-					nToSkip += 3;
-					break;
-				case NEWARRAY:
-					nToSkip--;
-					nToSkip++;
-				default:
-					logger.debug("Unknown opcode " + n.getOpcode());
-					break;
-				}
-				break;
-			case AbstractInsnNode.INSN:
-				switch (n.getOpcode()) {
-				// case ATHROW: // 1 before n/a after
-				// popValue();
-				// onMethodExit(opcode);
-				// break;
-				//
-				// case LRETURN: // 2 before n/a after
-				// case DRETURN: // 2 before n/a after
-				// popValue();
-				// popValue();
-				// onMethodExit(opcode);
-				// break;
-
-				case NOP:
-				case LNEG:
-				case DNEG:
-				case FNEG:
-				case INEG:
-				case L2D:
-				case D2L:
-				case F2I:
-				case I2B:
-				case I2C:
-				case I2S:
-				case I2F:
-				case F2L: // 1 before 2 after
-				case F2D:
-				case I2L:
-				case I2D:
-
-				case L2I: // 2 before 1 after
-				case L2F: // 2 before 1 after
-				case D2I: // 2 before 1 after
-				case D2F: // 2 before 1 after
-				case ARRAYLENGTH:
-				case SWAP:
-					nToSkip--;
-					nToSkip++;
-					break;
-
-				case IADD:
-				case FADD:
-				case ISUB:
-				case LSHL: // 3 before 2 after
-				case LSHR: // 3 before 2 after
-				case LUSHR: // 3 before 2 after
-				case LSUB:
-				case LMUL:
-				case LDIV:
-				case LREM:
-				case LADD:
-				case LAND:
-				case LOR:
-				case LXOR:
-				case DADD:
-				case DMUL:
-				case DSUB:
-				case DDIV:
-				case DREM:
-
-				case FSUB:
-				case FMUL:
-				case FDIV:
-				case FREM:
-				case FCMPL: // 2 before 1 after
-				case FCMPG: // 2 before 1 after
-				case IMUL:
-				case IDIV:
-				case IREM:
-				case ISHL:
-				case ISHR:
-				case IUSHR:
-				case IAND:
-				case IOR:
-				case IXOR:
-
-				case IALOAD: // remove 2 add 1
-				case FALOAD: // remove 2 add 1
-				case AALOAD: // remove 2 add 1
-				case BALOAD: // remove 2 add 1
-				case CALOAD: // remove 2 add 1
-				case SALOAD: // remove 2 add 1
-				case LALOAD: // remove 2 add 2
-				case DALOAD: // remove 2 add 2
-
-				case LCMP: // 4 before 1 after
-				case DCMPL:
-				case DCMPG:
-					nToSkip--;
-					nToSkip += 2;
-					break;
-
-				case ACONST_NULL:
-				case ICONST_M1:
-				case ICONST_0:
-				case ICONST_1:
-				case ICONST_2:
-				case ICONST_3:
-				case ICONST_4:
-				case ICONST_5:
-				case FCONST_0:
-				case FCONST_1:
-				case FCONST_2:
-				case LCONST_0:
-				case LCONST_1:
-				case DCONST_0:
-				case DCONST_1:
-
-				case DUP:
-				case DUP_X1:
-				case DUP_X2:
-
-				case DUP2: // is this wrong to assume that dup2 is only used on
-							// longs and not 2 shorts?
-				case DUP2_X1:
-				case DUP2_X2:
-					// case POP:
-					// case MONITORENTER:
-					// case MONITOREXIT:
-					// case POP2:
-					if (nToSkip == 0) {
-						return new SimpleExpression(n);
-					}
-					nToSkip--;
-					break;
-
-				case LASTORE:
-				case DASTORE:
-				case IASTORE:
-				case FASTORE:
-				case AASTORE:
-				case BASTORE:
-				case CASTORE:
-				case SASTORE:
-					nToSkip--;
-					nToSkip += 3;
-					break;
-				}
-				break;
-			}
-
-		}
-		return null;
-	}
-
-	private AnnotatedMethod findOrAddMethod(String owner, String name, String desc, int access) {
-		String lookupKey = owner + "." + name + ":" + desc;
-		if (!lookupCache.containsKey(lookupKey))
-			lookupCache.put(lookupKey, new AnnotatedMethod(name, desc, owner, access));
-		return lookupCache.get(lookupKey);
-	}
-
-	private AnnotatedMethod findOrAddMethod(String owner, MethodNode mn) {
-		return findOrAddMethod(owner, mn.name, mn.desc, mn.access);
-	}
-
-	public static void main(String[] args) {
-		try {
-			ClassReader cr = new ClassReader("edu.columbia.cs.psl.invivo.sample.SimpleClass");
-			MutabilityAnalyzer ma = new MutabilityAnalyzer(new HashMap<String, AnnotatedMethod>());
-			ma.analyzeClass(cr);
-			ma.doneSupplyingClasses();
-		} catch (Exception ex) {
-			ex.printStackTrace();
-		}
-	}
+    private static Logger logger = Logger.getLogger(MutabilityAnalyzer.class);
+
+    public MutabilityAnalyzer(HashMap<String, AnnotatedMethod> lookupCache) {
+        this.lookupCache = lookupCache;
+    }
+
+    private HashMap<String, AnnotatedMethod> lookupCache;
+
+    private static boolean enabled = false;
+
+    /**
+     * Call when done calling analyzeClass
+     */
+    public void doneSupplyingClasses() {
+        if (!enabled)
+            return;
+        for (String s : lookupCache.keySet()) {
+            AnnotatedMethod method = lookupCache.get(s);
+            if (method.isMutatesFieldsDirectly()) {
+                for (AnnotatedMethod caller : method.functionsThatCallMe) {
+                    method.setMutatesFields();
+                    addAllRecursively(caller);
+                }
+            }
+        }
+    }
+
+    private void addAllRecursively(AnnotatedMethod method) {
+        if (method.isMutatesFields())
+            return;
+        method.setMutatesFields();
+        for (AnnotatedMethod caller : method.functionsThatCallMe)
+            addAllRecursively(caller);
+    }
+
+    /**
+     * Approach: Find all methods that can change fields Recurse that out to
+     * find all methods that might call methods that can change fields At the
+     * start of each methods that might change fields, keep track in a field:
+     * The starting count values for each storage array *recursively* this can
+     * be in local variables though When a field is changed OR a "not safe"
+     * local variable (not safe if it might point to a field): Store a reference
+     * to the field/local variable and a copy of the value When a method is
+     * invoked that might change fields, track: A reference to the callee When
+     * we need to reset the system to a pre-crash state: Go through the starting
+     * count for each field and compare with each current count. If count
+     * changed, reset and note To find each field, may need to (recursively)
+     * descend through the holder points-to fields Take 2: At the start of each
+     * method, make a reference copy to a local variable of every backup pt that
+     * we will subsequently read but might change If this method directly
+     * changes fields, store a local variable with the original value at time of
+     * change If this method indirectly changes fields, store a local variable
+     * with the original value before the method is called
+     *
+     * @param cr
+     */
+    public ClassNode analyzeClass(ClassReader cr) {
+        ClassNode cn = new ClassNode();
+        cr.accept(cn, ClassReader.SKIP_DEBUG);
+
+        for (Object o : cn.methods) {
+            MethodNode thisMethodNode = (MethodNode) o;
+            AnnotatedMethod thisMethod = findOrAddMethod(cn.name, thisMethodNode);
+            thisMethod.setFullyDiscovered(true);
+            thisMethod.setAccess(thisMethodNode.access);
+
+            if ((thisMethodNode.access & ACC_NATIVE) != 0) // is native
+                NonDeterministicLoggingMethodVisitor.registerNDMethod(cn.name, thisMethodNode.name,
+                        thisMethodNode.desc);
+
+            ListIterator<?> i = thisMethodNode.instructions.iterator();
+            boolean isFirstInsn = true;
+            while (i.hasNext()) {
+                AbstractInsnNode n = (AbstractInsnNode) i.next();
+                if (n.getType() == AbstractInsnNode.FIELD_INSN) // Field
+                                                                // Instruction
+                {
+                    FieldInsnNode fn = (FieldInsnNode) n;
+                    if (n.getOpcode() == Opcodes.PUTSTATIC) {
+                        // This instruction is changing a static field. Previous
+                        // instruction is the value to set to
+                        FieldExpression pi = new FieldExpression(fn.name, fn.owner, fn.desc,
+                                n.getOpcode());
+                        thisMethod.getPutFieldInsns().add(pi);
+                        thisMethod.setMutatesFieldsDirectly();
+                    } else if (n.getOpcode() == Opcodes.PUTFIELD) {
+
+                        // This instruction is changing a field.
+                        // Previous instruction will have the value that we are
+                        // setting to
+                        FieldExpression pi = new FieldExpression(fn.name, fn.owner, fn.desc,
+                                n.getOpcode());
+                        pi.setParent(parentInstructionOf(thisMethodNode, pi,
+                                thisMethodNode.instructions.iterator(i.previousIndex())));
+                        thisMethod.getPutFieldInsns().add(pi);
+                        thisMethod.setMutatesFieldsDirectly();
+                    }
+                } else if (n.getType() == AbstractInsnNode.METHOD_INSN) // Method
+                                                                        // invocation
+                {
+                    MethodInsnNode whatWeCall = (MethodInsnNode) n;
+                    AnnotatedMethod otherMethod = findOrAddMethod(whatWeCall.owner,
+                            whatWeCall.name, whatWeCall.desc, 0);
+                    otherMethod.functionsThatCallMe.add(thisMethod);
+                    MethodExpression otherMethodExp = new MethodExpression(otherMethod,
+                            whatWeCall.getOpcode());
+                    otherMethodExp.getParams().addAll(
+                            paramsOf(thisMethodNode, otherMethodExp,
+                                    thisMethodNode.instructions.iterator(i.previousIndex())));
+
+                    if (whatWeCall.getOpcode() != Opcodes.INVOKESTATIC)
+                        otherMethodExp.setParent(parentInstructionOf(thisMethodNode,
+                                otherMethodExp,
+                                thisMethodNode.instructions.iterator(i.previousIndex())));
+
+                    if (NonDeterministicLoggingMethodVisitor.isND(whatWeCall.owner,
+                            whatWeCall.name, whatWeCall.desc)
+                            && whatWeCall.name.equals("<init>")
+                            && whatWeCall.owner.equals(cn.superName)
+                            && thisMethodNode.name.equals("<init>") && isFirstInsn) {
+                        NonDeterministicLoggingMethodVisitor.registerNDMethod(cn.name,
+                                thisMethodNode.name, thisMethodNode.desc);
+                    }
+
+                    thisMethod.functionsThatICall.add(otherMethodExp);
+
+                    isFirstInsn = false;
+                } else if (n.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN) // Invoke
+                                                                                // dynamic
+                {
+
+                }
+            }
+        }
+        ClassNode ret = new ClassNode();
+        ret.name = cn.name;
+        ret.fields = cn.fields;
+        ret.superName = cn.superName;
+        ret.interfaces = cn.interfaces;
+        return ret;
+    }
+
+    private List<Expression> paramsOf(MethodNode sourceMethod,
+            MethodExpression methodInsnToFindParamsOf, ListIterator<?> i) {
+        ArrayList<Expression> ret = new ArrayList<Expression>();
+        int nParams = methodInsnToFindParamsOf.getNumParamsNeeded();
+        int nToSkip = 0;
+        logger.debug("Finding " + nParams + " params for " + methodInsnToFindParamsOf);
+        while (i.hasPrevious() && nParams > 0) {
+            AbstractInsnNode n = (AbstractInsnNode) i.previous();
+            switch (n.getType()) {
+                case AbstractInsnNode.METHOD_INSN:
+                    MethodInsnNode min = (MethodInsnNode) n;
+                    MethodExpression mi = new MethodExpression(findOrAddMethod(min.owner, min.name,
+                            min.desc, min.getOpcode() == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC
+                                    : 0), min.getOpcode());
+                    logger.debug("Encountered " + mi + ", skipping " + mi.getStackElementsToSkip());
+
+                    if (nToSkip == 0) {
+                        mi.setParent(parentInstructionOf(sourceMethod, mi,
+                                sourceMethod.instructions.iterator(i.previousIndex() + 1)));
+                        mi.getParams().addAll(
+                                paramsOf(sourceMethod, mi,
+                                        sourceMethod.instructions.iterator(i.previousIndex() + 1)));
+
+                        ret.add(mi);
+                        nParams--;
+                    }
+                    nToSkip--;
+                    nToSkip += mi.getStackElementsToSkip()
+                            + (mi.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1);
+                    logger.debug("NTOS" + nToSkip);
+                    if (nToSkip < 0)
+                        nToSkip = 0;
+                    break;
+                case AbstractInsnNode.INVOKE_DYNAMIC_INSN:
+                    // TODO
+                    break;
+                case AbstractInsnNode.TYPE_INSN:
+                    switch (n.getOpcode()) {
+                        case NEW:
+                            if (nToSkip == 0) {
+                                ret.add(new SimpleExpression(n));
+                                nParams--;
+                            } else
+                                nToSkip--;
+                            break;
+                        case ANEWARRAY:
+                        case CHECKCAST:
+                        case INSTANCEOF:
+                    }
+                    break;
+                case AbstractInsnNode.FIELD_INSN:
+                    FieldInsnNode fn = (FieldInsnNode) n;
+                    if (n.getOpcode() == Opcodes.GETFIELD) {
+                        FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc,
+                                n.getOpcode());
+                        logger.debug("Encoutnered" + fi);
+                        if (nToSkip == 0) {
+                            fi.setParent(parentInstructionOf(sourceMethod, fi,
+                                    sourceMethod.instructions.iterator(i.previousIndex() + 1)));
+                            ret.add(fi);
+                            nParams--;
+                        }
+                        nToSkip--;
+                        nToSkip += 1;
+                    } else if (n.getOpcode() == Opcodes.GETSTATIC) {
+                        FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc,
+                                n.getOpcode());
+                        if (nToSkip == 0) {
+                            ret.add(fi);
+                            nParams--;
+                        }
+                        nToSkip--;
+                    }
+                    break;
+                case AbstractInsnNode.INT_INSN:
+                case AbstractInsnNode.LDC_INSN:
+                case AbstractInsnNode.VAR_INSN:
+                    switch (n.getOpcode()) {
+                        case Opcodes.ILOAD:
+                        case Opcodes.LLOAD:
+                        case Opcodes.FLOAD:
+                        case Opcodes.DLOAD:
+                        case Opcodes.ALOAD:
+                        case BIPUSH:
+                        case SIPUSH:
+                        case Opcodes.LDC:
+                            if (nToSkip == 0) {
+                                ret.add(new SimpleExpression(n));
+                                nParams--;
+                            } else
+                                nToSkip--;
+                            break;
+                        case ISTORE:
+                        case LSTORE:
+                        case FSTORE:
+                        case DSTORE:
+                        case ASTORE:
+                            nToSkip--;
+                            nToSkip++;
+                            break;
+                        case LALOAD:
+                        case FALOAD:
+                        case AALOAD:
+                        case BALOAD:
+                        case CALOAD:
+                        case SALOAD:
+                            nToSkip--;
+                            nToSkip += 2;
+                            break;
+                        case AASTORE:
+                        case IASTORE:
+                        case FASTORE:
+                        case DASTORE:
+                        case BASTORE:
+                        case CASTORE:
+                        case SASTORE:
+                            nToSkip += 3;
+                            break;
+                        case NEWARRAY:
+                            nToSkip--;
+                            nToSkip++;
+                        default:
+                            logger.debug("Unknown opcode " + n.getOpcode());
+                            break;
+                    }
+                    break;
+                case AbstractInsnNode.INSN:
+                    switch (n.getOpcode()) {
+                    // case ATHROW: // 1 before n/a after
+                    // popValue();
+                    // onMethodExit(opcode);
+                    // break;
+                    //
+                    // case LRETURN: // 2 before n/a after
+                    // case DRETURN: // 2 before n/a after
+                    // popValue();
+                    // popValue();
+                    // onMethodExit(opcode);
+                    // break;
+
+                        case NOP:
+                        case LNEG:
+                        case DNEG:
+                        case FNEG:
+                        case INEG:
+                        case L2D:
+                        case D2L:
+                        case F2I:
+                        case I2B:
+                        case I2C:
+                        case I2S:
+                        case I2F:
+                        case F2L: // 1 before 2 after
+                        case F2D:
+                        case I2L:
+                        case I2D:
+
+                        case L2I: // 2 before 1 after
+                        case L2F: // 2 before 1 after
+                        case D2I: // 2 before 1 after
+                        case D2F: // 2 before 1 after
+                        case ARRAYLENGTH:
+                        case SWAP:
+                            nToSkip--;
+                            nToSkip++;
+                            break;
+
+                        case IADD:
+                        case FADD:
+                        case ISUB:
+                        case LSHL: // 3 before 2 after
+                        case LSHR: // 3 before 2 after
+                        case LUSHR: // 3 before 2 after
+                        case LSUB:
+                        case LMUL:
+                        case LDIV:
+                        case LREM:
+                        case LADD:
+                        case LAND:
+                        case LOR:
+                        case LXOR:
+                        case DADD:
+                        case DMUL:
+                        case DSUB:
+                        case DDIV:
+                        case DREM:
+
+                        case FSUB:
+                        case FMUL:
+                        case FDIV:
+                        case FREM:
+                        case FCMPL: // 2 before 1 after
+                        case FCMPG: // 2 before 1 after
+                        case IMUL:
+                        case IDIV:
+                        case IREM:
+                        case ISHL:
+                        case ISHR:
+                        case IUSHR:
+                        case IAND:
+                        case IOR:
+                        case IXOR:
+
+                        case IALOAD: // remove 2 add 1
+                        case FALOAD: // remove 2 add 1
+                        case AALOAD: // remove 2 add 1
+                        case BALOAD: // remove 2 add 1
+                        case CALOAD: // remove 2 add 1
+                        case SALOAD: // remove 2 add 1
+                        case LALOAD: // remove 2 add 2
+                        case DALOAD: // remove 2 add 2
+
+                        case LCMP: // 4 before 1 after
+                        case DCMPL:
+                        case DCMPG:
+                            nToSkip--;
+                            nToSkip += 2;
+                            break;
+
+                        case ACONST_NULL:
+                        case ICONST_M1:
+                        case ICONST_0:
+                        case ICONST_1:
+                        case ICONST_2:
+                        case ICONST_3:
+                        case ICONST_4:
+                        case ICONST_5:
+                        case FCONST_0:
+                        case FCONST_1:
+                        case FCONST_2:
+                        case LCONST_0:
+                        case LCONST_1:
+                        case DCONST_0:
+                        case DCONST_1:
+
+                        case DUP:
+                        case DUP_X1:
+                        case DUP_X2:
+
+                        case DUP2: // is this wrong to assume that dup2 is only
+                                   // used on
+                                   // longs and not 2 shorts?
+                        case DUP2_X1:
+                        case DUP2_X2:
+                            // case POP:
+                            // case MONITORENTER:
+                            // case MONITOREXIT:
+                            // case POP2:
+                            if (nToSkip == 0) {
+                                ret.add(new SimpleExpression(n));
+                                nParams--;
+                            } else
+                                nToSkip--;
+                            break;
+
+                        case LASTORE:
+                        case DASTORE:
+                        case IASTORE:
+                        case FASTORE:
+                        case AASTORE:
+                        case BASTORE:
+                        case CASTORE:
+                        case SASTORE:
+                            nToSkip--;
+                            nToSkip += 3;
+                            break;
+                    }
+                    break;
+            }
+        }
+        return ret;
+    }
+
+    private Expression parentInstructionOf(MethodNode mn, Expression insnToFindParentOf,
+            ListIterator<?> i) {
+        if (insnToFindParentOf.getType() == Expression.METHOD_TYPE
+                && ((MethodExpression) insnToFindParentOf).getMethod().getName().equals("<init>"))
+            return null;
+        int nToSkip = insnToFindParentOf.getStackElementsToSkip();
+        logger.debug("Examining " + insnToFindParentOf.toString() + " for parent, skipping "
+                + nToSkip);
+        while (i.hasPrevious()) {
+            AbstractInsnNode n = (AbstractInsnNode) i.previous();
+            switch (n.getType()) {
+                case AbstractInsnNode.METHOD_INSN:
+                    MethodInsnNode min = (MethodInsnNode) n;
+                    MethodExpression mi = new MethodExpression(findOrAddMethod(min.owner, min.name,
+                            min.desc, min.getOpcode() == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC
+                                    : 0), min.getOpcode());
+                    logger.debug("Encountered " + mi + ", skipping " + mi.getStackElementsToSkip());
+
+                    if (nToSkip == 0) {
+                        mi.setParent(parentInstructionOf(mn, mi,
+                                mn.instructions.iterator(i.previousIndex() + 1)));
+                        mi.getParams().addAll(
+                                paramsOf(mn, mi, mn.instructions.iterator(i.previousIndex() + 1)));
+                        return mi;
+                    }
+                    nToSkip--;
+                    nToSkip += mi.getStackElementsToSkip()
+                            + (mi.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1);
+                    logger.debug("NTos" + nToSkip);
+                    break;
+                case AbstractInsnNode.INVOKE_DYNAMIC_INSN:
+                    // TODO
+                    break;
+                case AbstractInsnNode.TYPE_INSN:
+                    switch (n.getOpcode()) {
+                        case NEW:
+                            if (nToSkip == 0) {
+                                return new SimpleExpression(n);
+                            } else
+                                nToSkip--;
+                            break;
+                        case ANEWARRAY:
+                        case CHECKCAST:
+                        case INSTANCEOF:
+                    }
+                    break;
+                case AbstractInsnNode.FIELD_INSN:
+                    FieldInsnNode fn = (FieldInsnNode) n;
+                    if (n.getOpcode() == Opcodes.GETFIELD) {
+                        FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc,
+                                n.getOpcode());
+                        logger.debug("Encoutnered field: " + fi);
+                        if (nToSkip == 0) {
+                            fi.setParent(parentInstructionOf(mn, fi,
+                                    mn.instructions.iterator(i.previousIndex() + 1)));
+                            return fi;
+                        }
+                        nToSkip--;
+                        nToSkip += 1;
+                        logger.debug("Ntos" + nToSkip);
+                    } else if (n.getOpcode() == Opcodes.GETSTATIC) {
+                        FieldExpression fi = new FieldExpression(fn.name, fn.owner, fn.desc,
+                                n.getOpcode());
+                        if (nToSkip == 0) {
+                            fi.setParent(parentInstructionOf(mn, fi,
+                                    mn.instructions.iterator(i.previousIndex() + 1)));
+                            return fi;
+                        }
+                        nToSkip--;
+                        // nToSkip += 1;
+                    }
+                    break;
+                case AbstractInsnNode.INT_INSN:
+                case AbstractInsnNode.LDC_INSN:
+                case AbstractInsnNode.VAR_INSN:
+                    switch (n.getOpcode()) {
+                        case Opcodes.ILOAD:
+                        case Opcodes.LLOAD:
+                        case Opcodes.FLOAD:
+                        case Opcodes.DLOAD:
+                        case Opcodes.ALOAD:
+                        case BIPUSH:
+                        case SIPUSH:
+                        case Opcodes.LDC:
+                            if (nToSkip == 0) {
+                                return new SimpleExpression(n);
+                            }
+                            nToSkip--;
+                            break;
+                        case ISTORE:
+                        case LSTORE:
+                        case FSTORE:
+                        case DSTORE:
+                        case ASTORE:
+                            nToSkip--;
+                            nToSkip++;
+                            break;
+                        case LALOAD:
+                        case FALOAD:
+                        case AALOAD:
+                        case BALOAD:
+                        case CALOAD:
+                        case SALOAD:
+                            nToSkip--;
+                            nToSkip += 2;
+                            break;
+                        case AASTORE:
+                        case IASTORE:
+                        case FASTORE:
+                        case DASTORE:
+                        case BASTORE:
+                        case CASTORE:
+                        case SASTORE:
+                            nToSkip += 3;
+                            break;
+                        case NEWARRAY:
+                            nToSkip--;
+                            nToSkip++;
+                        default:
+                            logger.debug("Unknown opcode " + n.getOpcode());
+                            break;
+                    }
+                    break;
+                case AbstractInsnNode.INSN:
+                    switch (n.getOpcode()) {
+                    // case ATHROW: // 1 before n/a after
+                    // popValue();
+                    // onMethodExit(opcode);
+                    // break;
+                    //
+                    // case LRETURN: // 2 before n/a after
+                    // case DRETURN: // 2 before n/a after
+                    // popValue();
+                    // popValue();
+                    // onMethodExit(opcode);
+                    // break;
+
+                        case NOP:
+                        case LNEG:
+                        case DNEG:
+                        case FNEG:
+                        case INEG:
+                        case L2D:
+                        case D2L:
+                        case F2I:
+                        case I2B:
+                        case I2C:
+                        case I2S:
+                        case I2F:
+                        case F2L: // 1 before 2 after
+                        case F2D:
+                        case I2L:
+                        case I2D:
+
+                        case L2I: // 2 before 1 after
+                        case L2F: // 2 before 1 after
+                        case D2I: // 2 before 1 after
+                        case D2F: // 2 before 1 after
+                        case ARRAYLENGTH:
+                        case SWAP:
+                            nToSkip--;
+                            nToSkip++;
+                            break;
+
+                        case IADD:
+                        case FADD:
+                        case ISUB:
+                        case LSHL: // 3 before 2 after
+                        case LSHR: // 3 before 2 after
+                        case LUSHR: // 3 before 2 after
+                        case LSUB:
+                        case LMUL:
+                        case LDIV:
+                        case LREM:
+                        case LADD:
+                        case LAND:
+                        case LOR:
+                        case LXOR:
+                        case DADD:
+                        case DMUL:
+                        case DSUB:
+                        case DDIV:
+                        case DREM:
+
+                        case FSUB:
+                        case FMUL:
+                        case FDIV:
+                        case FREM:
+                        case FCMPL: // 2 before 1 after
+                        case FCMPG: // 2 before 1 after
+                        case IMUL:
+                        case IDIV:
+                        case IREM:
+                        case ISHL:
+                        case ISHR:
+                        case IUSHR:
+                        case IAND:
+                        case IOR:
+                        case IXOR:
+
+                        case IALOAD: // remove 2 add 1
+                        case FALOAD: // remove 2 add 1
+                        case AALOAD: // remove 2 add 1
+                        case BALOAD: // remove 2 add 1
+                        case CALOAD: // remove 2 add 1
+                        case SALOAD: // remove 2 add 1
+                        case LALOAD: // remove 2 add 2
+                        case DALOAD: // remove 2 add 2
+
+                        case LCMP: // 4 before 1 after
+                        case DCMPL:
+                        case DCMPG:
+                            nToSkip--;
+                            nToSkip += 2;
+                            break;
+
+                        case ACONST_NULL:
+                        case ICONST_M1:
+                        case ICONST_0:
+                        case ICONST_1:
+                        case ICONST_2:
+                        case ICONST_3:
+                        case ICONST_4:
+                        case ICONST_5:
+                        case FCONST_0:
+                        case FCONST_1:
+                        case FCONST_2:
+                        case LCONST_0:
+                        case LCONST_1:
+                        case DCONST_0:
+                        case DCONST_1:
+
+                        case DUP:
+                        case DUP_X1:
+                        case DUP_X2:
+
+                        case DUP2: // is this wrong to assume that dup2 is only
+                                   // used on
+                                   // longs and not 2 shorts?
+                        case DUP2_X1:
+                        case DUP2_X2:
+                            // case POP:
+                            // case MONITORENTER:
+                            // case MONITOREXIT:
+                            // case POP2:
+                            if (nToSkip == 0) {
+                                return new SimpleExpression(n);
+                            }
+                            nToSkip--;
+                            break;
+
+                        case LASTORE:
+                        case DASTORE:
+                        case IASTORE:
+                        case FASTORE:
+                        case AASTORE:
+                        case BASTORE:
+                        case CASTORE:
+                        case SASTORE:
+                            nToSkip--;
+                            nToSkip += 3;
+                            break;
+                    }
+                    break;
+            }
+
+        }
+        return null;
+    }
+
+    private AnnotatedMethod findOrAddMethod(String owner, String name, String desc, int access) {
+        String lookupKey = owner + "." + name + ":" + desc;
+        if (!lookupCache.containsKey(lookupKey))
+            lookupCache.put(lookupKey, new AnnotatedMethod(name, desc, owner, access));
+        return lookupCache.get(lookupKey);
+    }
+
+    private AnnotatedMethod findOrAddMethod(String owner, MethodNode mn) {
+        return findOrAddMethod(owner, mn.name, mn.desc, mn.access);
+    }
+
+    public static void main(String[] args) {
+        try {
+            ClassReader cr = new ClassReader("edu.columbia.cs.psl.invivo.sample.SimpleClass");
+            MutabilityAnalyzer ma = new MutabilityAnalyzer(new HashMap<String, AnnotatedMethod>());
+            ma.analyzeClass(cr);
+            ma.doneSupplyingClasses();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/bench/ChroniclerJLogExplorer.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/bench/ChroniclerJLogExplorer.java
index 43ff9d7..ccf024c 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/bench/ChroniclerJLogExplorer.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/bench/ChroniclerJLogExplorer.java
@@ -1,25 +1,35 @@
+
 package edu.columbia.cs.psl.chroniclerj.bench;

 import java.io.File;
 import java.io.FileInputStream;
 import java.io.ObjectInputStream;
+import java.util.Arrays;

 import edu.columbia.cs.psl.chroniclerj.ExportedSerializableLog;

 public class ChroniclerJLogExplorer {
-	@SuppressWarnings({ "resource", "unused" })
-	public static void main(String[] args) throws Exception {
-		File f = new File("instrumented-test/chroniclerj_serializable_1355416858916.log");
-		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
-		ExportedSerializableLog log = (ExportedSerializableLog) ois.readObject();
-		Object[] alog = ExportedSerializableLog.aLog;
-
-		char[] clog = ExportedSerializableLog.cLog;
-		byte[] blog = ExportedSerializableLog.bLog;
-		String[] ownersA = ExportedSerializableLog.aLog_owners;
-		String[] ownersI = ExportedSerializableLog.iLog_owners;
-		System.out.println(ExportedSerializableLog.aLog_fill);
-		System.out.println(ExportedSerializableLog.cLog_fill);
-		System.out.println(ExportedSerializableLog.dLog_fill);
-	}
+    @SuppressWarnings({
+            "resource", "unused"
+    })
+    public static void main(String[] args) throws Exception {
+        File f = new File("../chroniclerj-test/inst-bin/chroniclerj_serializable_1362003992533.log");
+        if (!f.exists())
+            System.err.println("No such fiel");
+        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
+        ExportedSerializableLog log = (ExportedSerializableLog) ois.readObject();
+        Object[] alog = ExportedSerializableLog.aLog;
+
+        char[] clog = ExportedSerializableLog.cLog;
+        byte[] blog = ExportedSerializableLog.bLog;
+        String[] ownersA = ExportedSerializableLog.aLog_owners;
+        String[] ownersI = ExportedSerializableLog.iLog_owners;
+        System.out.println(ExportedSerializableLog.aLog_fill);
+        System.out.println(ExportedSerializableLog.cLog_fill);
+        System.out.println(ExportedSerializableLog.dLog_fill);
+        double[] dlog = ExportedSerializableLog.dLog;
+        String[] ownersD = ExportedSerializableLog.dLog_owners;
+        System.out.println(Arrays.toString(dlog));
+        System.out.println(Arrays.toString(ownersD));
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/FinalizerReplayingMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/FinalizerReplayingMethodVisitor.java
new file mode 100644
index 0000000..0096727
--- /dev/null
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/FinalizerReplayingMethodVisitor.java
@@ -0,0 +1,34 @@
+
+package edu.columbia.cs.psl.chroniclerj.replay;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import edu.columbia.cs.psl.chroniclerj.Instrumenter;
+
+public class FinalizerReplayingMethodVisitor extends MethodVisitor {
+
+    private boolean isFinalize;
+
+    private String className;
+
+    public FinalizerReplayingMethodVisitor(int api, MethodVisitor mv, String name, String desc,
+            String className) {
+        super(api, mv);
+        this.isFinalize = (name.equals("finalize")) && desc.equals("()V");
+        this.className = className;
+    }
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        if (this.isFinalize) {
+            // Log to the log our finalizer #
+            visitVarInsn(Opcodes.ALOAD, 0);
+            visitFieldInsn(Opcodes.GETFIELD, this.className, Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+            visitFieldInsn(Opcodes.PUTSTATIC, "edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils",
+                    "curFinalizer", "J");
+        }
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayClassVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayClassVisitor.java
index 10921f6..de2cd4d 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayClassVisitor.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayClassVisitor.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.replay;

 import java.util.ArrayList;
@@ -13,129 +14,142 @@ import org.objectweb.asm.commons.AnalyzerAdapter;
 import org.objectweb.asm.commons.JSRInlinerAdapter;
 import org.objectweb.asm.commons.LocalVariablesSorter;
 import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
 import org.objectweb.asm.tree.MethodInsnNode;

 import edu.columbia.cs.psl.chroniclerj.Instrumenter;
 import edu.columbia.cs.psl.chroniclerj.MethodCall;
 import edu.columbia.cs.psl.chroniclerj.visitor.NonDeterministicLoggingClassVisitor;

-public class NonDeterministicReplayClassVisitor extends ClassVisitor implements Opcodes{
-
-	private String className;
-	private boolean isAClass = true;
-
-	public NonDeterministicReplayClassVisitor(int api, ClassVisitor cv) {
-		super(api, cv);
-
-	}
-	private static Logger logger = Logger.getLogger(NonDeterministicReplayClassVisitor.class);
-	@Override
-	public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
-		super.visit(version, access, name, signature, superName, interfaces);
-		this.className = name;
-
-		logger.debug("Visiting " + name+ " for instrumentation");
-		if((access & Opcodes.ACC_INTERFACE) != 0)
-			isAClass = false;
-	}
-	private boolean isFirstConstructor = true;
-	@Override
-	public MethodVisitor visitMethod(int acc, String name, String desc,
-			String signature, String[] exceptions) {
-		//TODO need an annotation to disable doing this to some apps
-		if(isAClass)// && className.startsWith("edu"))
-		{
-
-			MethodVisitor smv = cv.visitMethod(acc, name, desc, signature, exceptions);
-
-			AnalyzerAdapter analyzer = new AnalyzerAdapter(className, acc, name, desc, smv);
-			LocalVariablesSorter sorter = new LocalVariablesSorter(acc, desc, analyzer);
-			NonDeterministicReplayMethodVisitor cloningMV = new NonDeterministicReplayMethodVisitor(Opcodes.ASM4, sorter, acc, name, desc,className,isFirstConstructor, analyzer,
-					classIsCallback(className) && name.equals("<init>"));
-			if(name.equals("<init>"))
-				isFirstConstructor = false;
-			cloningMV.setClassVisitor(this);
-			JSRInlinerAdapter mv2 = new JSRInlinerAdapter(cloningMV, acc, name, desc, signature, exceptions);
-
-			return mv2;
-		}
-		else
-			return 	cv.visitMethod(acc, name, desc, signature,
-					exceptions);
-	}
-
-	public HashSet<MethodCall> getLoggedMethodCalls() {
-		return loggedMethodCalls;
-	}
-	private HashSet<MethodCall> loggedMethodCalls = new HashSet<MethodCall>();
-	private HashMap<String, MethodInsnNode> captureMethodsToGenerate = new HashMap<String, MethodInsnNode>();
-	public void addFieldMarkup(ArrayList<MethodCall> calls) {
-		logger.debug("Received field markup from method visitor (" + calls.size() + ")");
-		loggedMethodCalls.addAll(calls);
-		//TODO also setup the new method to retrieve the list of replacements for the method
-	}
-
-	private boolean classIsCallback(String className)
-	{
-		if(NonDeterministicLoggingClassVisitor.callbackClasses.contains(className))
-			return true;
-		if(className.equals("java/lang/Object"))
-			return false;
-		if(!Instrumenter.instrumentedClasses.containsKey(className))
-		{
-			try{
-				Class<?> c = Instrumenter.loader.loadClass(className.replace("/", "."));
-				for(Class<?> i : c.getInterfaces())
-				{
-					if(NonDeterministicLoggingClassVisitor.callbackClasses.contains(Type.getInternalName(i)))
-							return true;
-				}
-				Class<?> superClass = c.getSuperclass();
-				if(superClass == null)
-					return false;
-				return classIsCallback(Type.getInternalName(superClass));
-			}
-			catch(ClassNotFoundException ex)
-			{
-				return false;
-			}
-		}
-		ClassNode cn = Instrumenter.instrumentedClasses.get(className);
-		for(Object s : cn.interfaces)
-		{
-			if(NonDeterministicLoggingClassVisitor.callbackClasses.contains(((String)s)))
-				return true;
-		}
-		if(cn.superName.equals(cn.name) || cn.superName.equals("java/lang/Object") || cn.name.equals("org/eclipse/jdt/core/compiler/BuildContext"))
-			return false;
-		else
-			return classIsCallback(cn.superName);
-	}
-	public static boolean methodIsCallback(String className, String name, String desc)
-	{
-		String key = "."+name +":"+desc;
-		if(NonDeterministicLoggingClassVisitor.callbackMethods.contains(className + key))
-			return true;
-		if(!Instrumenter.instrumentedClasses.containsKey(className))
-			return false;
-		ClassNode cn = Instrumenter.instrumentedClasses.get(className);
-		for(Object s : cn.interfaces)
-		{
-			if(NonDeterministicLoggingClassVisitor.callbackMethods.contains(((String)s) + key))
-				return true;
-		}
-		return methodIsCallback(cn.superName, name, desc);
-	}
-	@Override
-	public void visitEnd() {
-		super.visitEnd();
-
-	}
-	public String getClassName() {
-		return className;
-	}
-
-	public void addCaptureMethodsToGenerate(HashMap<String, MethodInsnNode> captureMethodsToGenerate) {
-		this.captureMethodsToGenerate.putAll(captureMethodsToGenerate);
-	}
+public class NonDeterministicReplayClassVisitor extends ClassVisitor implements Opcodes {
+
+    private String className;
+
+    private boolean isAClass = true;
+
+    public NonDeterministicReplayClassVisitor(int api, ClassVisitor cv) {
+        super(api, cv);
+
+    }
+
+    private static Logger logger = Logger.getLogger(NonDeterministicReplayClassVisitor.class);
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName,
+            String[] interfaces) {
+        super.visit(version, access, name, signature, superName, interfaces);
+        this.className = name;
+
+        logger.debug("Visiting " + name + " for instrumentation");
+        if ((access & Opcodes.ACC_INTERFACE) != 0)
+            isAClass = false;
+    }
+
+    private boolean isFirstConstructor = true;
+
+    @Override
+    public MethodVisitor visitMethod(int acc, String name, String desc, String signature,
+            String[] exceptions) {
+        // TODO need an annotation to disable doing this to some apps
+        if (isAClass)// && className.startsWith("edu"))
+        {
+
+            MethodVisitor smv = cv.visitMethod(acc, name, desc, signature, exceptions);
+            FinalizerReplayingMethodVisitor fmv = new FinalizerReplayingMethodVisitor(acc, smv,
+                    name, desc, this.className);
+            AnalyzerAdapter analyzer = new AnalyzerAdapter(className, acc, name, desc, fmv);
+            LocalVariablesSorter sorter = new LocalVariablesSorter(acc, desc, analyzer);
+            NonDeterministicReplayMethodVisitor cloningMV = new NonDeterministicReplayMethodVisitor(
+                    Opcodes.ASM4, sorter, acc, name, desc, className, isFirstConstructor, analyzer,
+                    classIsCallback(className) && name.equals("<init>"));
+            if (name.equals("<init>"))
+                isFirstConstructor = false;
+            cloningMV.setClassVisitor(this);
+            JSRInlinerAdapter mv2 = new JSRInlinerAdapter(cloningMV, acc, name, desc, signature,
+                    exceptions);
+
+            return mv2;
+        } else
+            return cv.visitMethod(acc, name, desc, signature, exceptions);
+    }
+
+    public HashSet<MethodCall> getLoggedMethodCalls() {
+        return loggedMethodCalls;
+    }
+
+    private HashSet<MethodCall> loggedMethodCalls = new HashSet<MethodCall>();
+
+    private HashMap<String, MethodInsnNode> captureMethodsToGenerate = new HashMap<String, MethodInsnNode>();
+
+    public void addFieldMarkup(ArrayList<MethodCall> calls) {
+        logger.debug("Received field markup from method visitor (" + calls.size() + ")");
+        loggedMethodCalls.addAll(calls);
+        // TODO also setup the new method to retrieve the list of replacements
+        // for the method
+    }
+
+    private boolean classIsCallback(String className) {
+        if (NonDeterministicLoggingClassVisitor.callbackClasses.contains(className))
+            return true;
+        if (className.equals("java/lang/Object"))
+            return false;
+        if (!Instrumenter.instrumentedClasses.containsKey(className)) {
+            try {
+                Class<?> c = Instrumenter.loader.loadClass(className.replace("/", "."));
+                for (Class<?> i : c.getInterfaces()) {
+                    if (NonDeterministicLoggingClassVisitor.callbackClasses.contains(Type
+                            .getInternalName(i)))
+                        return true;
+                }
+                Class<?> superClass = c.getSuperclass();
+                if (superClass == null)
+                    return false;
+                return classIsCallback(Type.getInternalName(superClass));
+            } catch (ClassNotFoundException ex) {
+                return false;
+            }
+        }
+        ClassNode cn = Instrumenter.instrumentedClasses.get(className);
+        for (Object s : cn.interfaces) {
+            if (NonDeterministicLoggingClassVisitor.callbackClasses.contains(((String) s)))
+                return true;
+        }
+        if (cn.superName.equals(cn.name) || cn.superName.equals("java/lang/Object")
+                || cn.name.equals("org/eclipse/jdt/core/compiler/BuildContext"))
+            return false;
+        else
+            return classIsCallback(cn.superName);
+    }
+
+    public static boolean methodIsCallback(String className, String name, String desc) {
+        String key = "." + name + ":" + desc;
+        if (NonDeterministicLoggingClassVisitor.callbackMethods.contains(className + key))
+            return true;
+        if (!Instrumenter.instrumentedClasses.containsKey(className))
+            return false;
+        ClassNode cn = Instrumenter.instrumentedClasses.get(className);
+        for (Object s : cn.interfaces) {
+            if (NonDeterministicLoggingClassVisitor.callbackMethods.contains(((String) s) + key))
+                return true;
+        }
+        return methodIsCallback(cn.superName, name, desc);
+    }
+
+    @Override
+    public void visitEnd() {
+        if (isAClass) {
+            FieldNode fn = new FieldNode(Opcodes.ACC_PRIVATE, Instrumenter.FIELD_LOGICAL_CLOCK,
+                    "J", null, 0);
+            fn.accept(this);
+        }
+        super.visitEnd();
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void addCaptureMethodsToGenerate(HashMap<String, MethodInsnNode> captureMethodsToGenerate) {
+        this.captureMethodsToGenerate.putAll(captureMethodsToGenerate);
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayMethodVisitor.java
index 89de88d..85c9d48 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayMethodVisitor.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/NonDeterministicReplayMethodVisitor.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.replay;

 import java.util.ArrayList;
@@ -22,337 +23,439 @@ import edu.columbia.cs.psl.chroniclerj.ExportedLog;
 import edu.columbia.cs.psl.chroniclerj.Instrumenter;
 import edu.columbia.cs.psl.chroniclerj.Log;
 import edu.columbia.cs.psl.chroniclerj.MethodCall;
+import edu.columbia.cs.psl.chroniclerj.struct.AnnotatedMethod;
 import edu.columbia.cs.psl.chroniclerj.visitor.CloningAdviceAdapter;
 import edu.columbia.cs.psl.chroniclerj.visitor.NonDeterministicLoggingMethodVisitor;

-public class NonDeterministicReplayMethodVisitor extends AdviceAdapter implements Opcodes  {
-	private static Logger logger = Logger.getLogger(NonDeterministicReplayMethodVisitor.class);
-	private String name;
-	private String desc;
-	private String classDesc;
-	private boolean isStatic;
-	private boolean constructor;
-	private boolean superInitialized;
-
-	private boolean isCallbackInit;
-
-	@Override
-	public void visitCode() {
-		super.visitCode();
-		if (!constructor)
-			superInitialized = true;
-	}
-
-	private boolean isFirstConstructor;
-	AnalyzerAdapter analyzer;
-
-	protected NonDeterministicReplayMethodVisitor(int api, MethodVisitor mv, int access, String name, String desc, String classDesc, boolean isFirstConstructor, AnalyzerAdapter analyzer,
-			boolean isCallbackInit) {
-		super(api,mv,access,name,desc);
-		this.name = name;
-		this.desc = desc;
-		this.classDesc = classDesc;
-		this.isStatic = (access & Opcodes.ACC_STATIC) != 0;
-		this.constructor = "<init>".equals(name);
-		this.isFirstConstructor = isFirstConstructor;
-		this.analyzer = analyzer;
-		this.isCallbackInit = isCallbackInit;
-	}
-
-	private NonDeterministicReplayClassVisitor parent;
-
-	public void setClassVisitor(NonDeterministicReplayClassVisitor coaClassVisitor) {
-		this.parent = coaClassVisitor;
-	}
-
-
-
-	@Override
-	public void visitEnd() {
-		super.visitEnd();
-		parent.addFieldMarkup(methodCallsToClear);
-		parent.addCaptureMethodsToGenerate(captureMethodsToGenerate);
-	}
-
-	private int lineNumber = 0;
-
-	@Override
-	public void visitLineNumber(int line, Label start) {
-		super.visitLineNumber(line, start);
-		lineNumber = line;
-	}
-
-	private void loadReplayIndex(String className, String fieldName) {
-		//		super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex", "Ljava/util/HashMap;");
-		//		super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Thread.class), "currentThread", "()Ljava/lang/Thread;");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Thread.class), "getName", "()Ljava/lang/String;");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(HashMap.class), "containsKey", "(Ljava/lang/Object;)Z");
-		//		Label exists = new Label();
-		//		super.visitJumpInsn(Opcodes.IFNE, exists);
-		//		super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex", "Ljava/util/HashMap;");
-		//		super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Thread.class), "currentThread", "()Ljava/lang/Thread;");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Thread.class), "getName", "()Ljava/lang/String;");
-		//		super.visitInsn(ICONST_0);
-		//		super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", "(I)Ljava/lang/Integer;");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(HashMap.class), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
-		//		super.visitInsn(POP);
-		//		super.visitLabel(exists);
-		//		super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex", "Ljava/util/HashMap;");
-		//		super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Thread.class), "currentThread", "()Ljava/lang/Thread;");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Thread.class), "getName", "()Ljava/lang/String;");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(HashMap.class), "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
-		//		super.visitTypeInsn(CHECKCAST, "java/lang/Integer");
-		//		super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Integer.class), "intValue", "()I");
-
-
-		Label load = new Label();
-		visitLabel(load);
-				super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex", "Ljava/util/HashMap;");
-				super.visitFieldInsn(GETSTATIC, className, fieldName + "_owners", "[Ljava/lang/String;");
-				super.visitFieldInsn(GETSTATIC, className, fieldName + "_fill", "I");
-				super.visitLdcInsn(className);
-				if(className.contains("Serializable"))
-					super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ReplayUtils.class), "getNextIndex", "(Ljava/util/HashMap;[Ljava/lang/String;ILjava/lang/String;)I");
-				else
-				{
-					super.visitFieldInsn(GETSTATIC, className, fieldName , "[Ljava/lang/Object;");
-
-					super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ReplayUtils.class), "getNextIndexO", "(Ljava/util/HashMap;[Ljava/lang/String;ILjava/lang/String;[Ljava/lang/Object;)I");
-				}
-				super.visitInsn(DUP);
-				Label cont = new Label();
-				super.visitJumpInsn(IFGE, cont);
-				super.visitInsn(POP);
-				super.visitLdcInsn(className);
-				super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ReplayRunner.class), "loadNextLog", "(Ljava/lang/String;)V");
-				super.visitJumpInsn(GOTO, load);
-				visitLabel(cont);
-//		super.visitInsn(ICONST_0);
-	}
-
-	private void incrementReplayIndex(String className, String fieldName) {
-				super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex", "Ljava/util/HashMap;");
-				super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Thread.class), "currentThread", "()Ljava/lang/Thread;");
-				super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Thread.class), "getName", "()Ljava/lang/String;");
-				loadReplayIndex(className, fieldName);
-				super.visitInsn(ICONST_1);
-				super.visitInsn(IADD);
-				super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", "(I)Ljava/lang/Integer;");
-				super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(HashMap.class), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
-				super.visitInsn(POP);
-
-				super.visitFieldInsn(GETSTATIC, Type.getInternalName(ExportedLog.class), "globalReplayIndex", "I");
-				super.visitInsn(ICONST_1);
-				super.visitInsn(IADD);
-				super.visitFieldInsn(PUTSTATIC, Type.getInternalName(ExportedLog.class), "globalReplayIndex", "I");
-	}
-
-	private HashMap<String, MethodInsnNode> captureMethodsToGenerate = new HashMap<String, MethodInsnNode>();
-	private boolean inited;
-	@Override
-	public void visitMethodInsn(int opcode, String owner, String name, String desc) {
-		if(owner.equals(Type.getInternalName(ChroniclerJExportRunner.class)) && name.equals("genTestCase"))
-			return;
-		try {
-			MethodCall m = new MethodCall(this.name, this.desc, this.classDesc, 0, lineNumber, owner, name, desc, isStatic);
-			Type returnType = Type.getMethodType(desc).getReturnType();
-			if (opcode == INVOKESPECIAL && name.equals("<init>") && NonDeterministicLoggingMethodVisitor.nonDeterministicMethods.contains(owner + "." + name + ":" + desc)) {
-
-				if (!(owner.equals(Instrumenter.instrumentedClasses.get(classDesc).superName) && this.name.equals("<init>"))) {
-					if (analyzer.stack == null) {
-						super.visitMethodInsn(opcode, owner, name, desc);
-					} else {
-						Type[] args = Type.getArgumentTypes(desc);
-						for (int i = args.length - 1; i >= 0; i--) {
-							Type t = args[i];
-							if (t.getSize() == 2)
-								mv.visitInsn(POP2);
-							else
-								mv.visitInsn(POP);
-						}
-
-						if (analyzer.stack != null && analyzer.stack.size() > 0 && analyzer.uninitializedTypes.containsKey(analyzer.stack.get(analyzer.stack.size() - 1))
-								&& analyzer.uninitializedTypes.get(analyzer.stack.get(analyzer.stack.size() - 1)).equals(owner)) {
-							mv.visitInsn(POP);
-							if (analyzer.stack.size() > 0 && analyzer.uninitializedTypes.containsKey(analyzer.stack.get(analyzer.stack.size() - 1))
-									&& analyzer.uninitializedTypes.get(analyzer.stack.get(analyzer.stack.size() - 1)).equals(owner))
-								mv.visitInsn(POP);
-
-							String replayClassName = MethodCall.getReplayClassName(Type.getType("L" + m.getMethodOwner() + ";"));
-							mv.visitFieldInsn(GETSTATIC, replayClassName, m.getLogFieldName(), "[Ljava/lang/Object;");
-
-							loadReplayIndex(replayClassName, m.getLogFieldName());
-
-							mv.visitInsn(AALOAD);
-							mv.visitTypeInsn(CHECKCAST, m.getMethodOwner());
-							incrementReplayIndex(replayClassName, m.getLogFieldName());
-						}
-					}
-				} else {
-					super.visitMethodInsn(opcode, owner, name, desc);
-				}
-
-			} else if ((!constructor || isFirstConstructor || superInitialized) && returnType.equals(Type.VOID_TYPE) && !name.equals("<init>")
-					&& NonDeterministicLoggingMethodVisitor.nonDeterministicMethods.contains(owner + "." + name + ":" + desc)) {
-				Type[] args = Type.getArgumentTypes(desc);
-				for (int i = args.length - 1; i >= 0; i--) {
-					Type t = args[i];
-					if (t.getSize() == 2)
-						mv.visitInsn(POP2);
-					else
-						mv.visitInsn(POP);
-				}
-				if (opcode != INVOKESTATIC)
-					mv.visitInsn(POP);
-
-				//				else
-				//					super.visitMethodInsn(opcode, owner, name, desc);
-
-			} else if ((!constructor || isFirstConstructor || superInitialized) && !returnType.equals(Type.VOID_TYPE)
-					&& NonDeterministicLoggingMethodVisitor.nonDeterministicMethods.contains(owner + "." + name + ":" + desc)) {
-
-
-				super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock", Type.getDescriptor(Lock.class));
-				super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "lock", "()V");
-
-				logger.debug("Adding field in MV to list " + m.getLogFieldName());
-				methodCallsToClear.add(m);
-				Type[] args = Type.getArgumentTypes(desc);
-				boolean hasArray = false;
-				for (Type t : args)
-					if (t.getSort() == Type.ARRAY)
-						hasArray = true;
-
-				if (hasArray) {
-
-					Type[] targs = Type.getArgumentTypes(desc);
-					for (int i = targs.length - 1; i >= 0; i--) {
-						Type t = targs[i];
-						if (t.getSort() == Type.ARRAY) {
-							/*
-							 * stack (grows down): dest (fill not incremented
-							 * yet)
-							 */
-							String replayClassName = MethodCall.getReplayClassName(t);
-							String replayFieldName = MethodCall.getLogFieldName(t);
-							mv.visitFieldInsn(GETSTATIC, replayClassName, MethodCall.getLogFieldName(t), MethodCall.getLogFieldType(t).getDescriptor());
-							//							mv.visitFieldInsn(GETSTATIC,replayClassName,
-							//									MethodCall.getLogFieldName(t)+"_replayIndex",
-							//									"I");
-							loadReplayIndex(replayClassName, replayFieldName);
-//							mv.visitInsn(DUP);
-//							mv.visitFieldInsn(GETSTATIC, replayClassName, MethodCall.getLogFieldName(t) + "_fill", "I");
-//							Label fallThrough = new Label();
-//
-//							mv.visitJumpInsn(Opcodes.IF_ICMPNE, fallThrough);
-//							mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(ReplayRunner.class), "loadNextLog", "()V");
-//							pop();
-//							loadReplayIndex(replayClassName, replayFieldName);
-//							visitLabel(fallThrough);
-
-							arrayLoad(t);
-
-							/*
-							 * stack (grows down): dest src
-							 */
-							swap();
-							/*
-							 * stack (grows down): src dest
-							 */
-							push(0);
-							/*
-							 * stack (grows down): src dest 0
-							 */
-							swap();
-							/*
-							 * stack (grows down): src 0 dest
-							 */
-							push(0);
-							/*
-							 * stack (grows down): src 0 dest 0
-							 */
-
-							mv.visitFieldInsn(GETSTATIC, replayClassName, MethodCall.getLogFieldName(t), MethodCall.getLogFieldType(t).getDescriptor());
-							loadReplayIndex(replayClassName, replayFieldName);
-							arrayLoad(t);
-							mv.visitTypeInsn(Opcodes.CHECKCAST, t.getInternalName());
-							mv.visitInsn(ARRAYLENGTH);
-							incrementReplayIndex(replayClassName, replayFieldName);
-							/*
-							 * stack: src (fill incremented) 0 dest 0 length
-							 */
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
-							/*
-							 * stack: dest popped
-							 */
-						} else {
-							switch (t.getSize()) {
-							case 2:
-								mv.visitInsn(POP2);
-								break;
-							case 1:
-							default:
-								mv.visitInsn(POP);
-								break;
-							}
-						}
-					}
-
-				} else {
-//					Type[] targs = Type.getArgumentTypes(desc);
-//					for (Type t : targs) {
-//						switch (t.getSize()) {
-//						case 2:
-//							visitInsn(POP2);
-//							break;
-//						case 1:
-//						default:
-//							visitInsn(POP);
-//							break;
-//						}
-//					}
-					for (int i = args.length - 1; i >= 0; i--) {
-						Type t = args[i];
-						if (t.getSize() == 2)
-							mv.visitInsn(POP2);
-						else
-							mv.visitInsn(POP);
-					}
-				}
-
-				if (opcode != INVOKESTATIC)
-					mv.visitInsn(POP);
-
-				if (returnType.getSort() == Type.VOID)
-					mv.visitInsn(NOP);
-				else {
-					mv.visitFieldInsn(GETSTATIC, m.getReplayClassName(), m.getLogFieldName(), m.getLogFieldType().getDescriptor());
-
-					loadReplayIndex(m.getReplayClassName(), m.getLogFieldName());
-					arrayLoad(m.getReturnType());
-					incrementReplayIndex(m.getReplayClassName(), m.getLogFieldName());
-				}
-				//Unlock
-				super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock", Type.getDescriptor(Lock.class));
-				super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "unlock", "()V");
-
-			} else {
-				super.visitMethodInsn(opcode, owner, name, desc);
-			}
-		} catch (Exception ex) {
-			logger.error("Unable to instrument method call", ex);
-		}
-	}
-	@Override
-	protected void onMethodEnter() {
-		if(this.name.equals("<init>") && isCallbackInit)
-		{
-			super.visitVarInsn(ALOAD, 0);
-			super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(CallbackRegistry.class), "register", "(Ljava/lang/Object;)V");
-			inited = true;
-		}
-	}
-	private ArrayList<MethodCall> methodCallsToClear = new ArrayList<MethodCall>();
-
+public class NonDeterministicReplayMethodVisitor extends AdviceAdapter implements Opcodes {
+    private static Logger logger = Logger.getLogger(NonDeterministicReplayMethodVisitor.class);
+
+    private String name;
+
+    private String desc;
+
+    private String classDesc;
+
+    private boolean isStatic;
+
+    private boolean constructor;
+
+    private boolean superInitialized;
+
+    private boolean isCallbackInit;
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        if (constructor) {
+            AnnotatedMethod am = Instrumenter.getAnnotatedMethod(this.classDesc, "finalize", "()V");
+            if (am != null && am.isCallsNDMethods()) {
+                super.visitVarInsn(ALOAD, 0);
+                super.visitFieldInsn(Opcodes.GETSTATIC, "edu/columbia/cs/psl/chroniclerj/Log",
+                        Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+                super.visitInsn(DUP2_X1);
+                super.visitFieldInsn(Opcodes.PUTFIELD, this.classDesc,
+                        Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+                super.visitInsn(LCONST_1);
+                super.visitInsn(LADD);
+                super.visitFieldInsn(Opcodes.PUTSTATIC, "edu/columbia/cs/psl/chroniclerj/Log",
+                        Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+            }
+        }
+        if (!constructor)
+            superInitialized = true;
+    }
+
+    private boolean isFirstConstructor;
+
+    AnalyzerAdapter analyzer;
+
+    protected NonDeterministicReplayMethodVisitor(int api, MethodVisitor mv, int access,
+            String name, String desc, String classDesc, boolean isFirstConstructor,
+            AnalyzerAdapter analyzer, boolean isCallbackInit) {
+        super(api, mv, access, name, desc);
+        this.name = name;
+        this.desc = desc;
+        this.classDesc = classDesc;
+        this.isStatic = (access & Opcodes.ACC_STATIC) != 0;
+        this.constructor = "<init>".equals(name);
+        this.isFirstConstructor = isFirstConstructor;
+        this.analyzer = analyzer;
+        this.isCallbackInit = isCallbackInit;
+    }
+
+    private NonDeterministicReplayClassVisitor parent;
+
+    public void setClassVisitor(NonDeterministicReplayClassVisitor coaClassVisitor) {
+        this.parent = coaClassVisitor;
+    }
+
+    @Override
+    public void visitEnd() {
+        super.visitEnd();
+        parent.addFieldMarkup(methodCallsToClear);
+        parent.addCaptureMethodsToGenerate(captureMethodsToGenerate);
+    }
+
+    private int lineNumber = 0;
+
+    @Override
+    public void visitLineNumber(int line, Label start) {
+        super.visitLineNumber(line, start);
+        lineNumber = line;
+    }
+
+    private void loadReplayIndex(String className, String fieldName) {
+        // super.visitFieldInsn(GETSTATIC, className, fieldName +
+        // "_replayIndex", "Ljava/util/HashMap;");
+        // super.visitMethodInsn(INVOKESTATIC,
+        // Type.getInternalName(Thread.class), "currentThread",
+        // "()Ljava/lang/Thread;");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(Thread.class), "getName",
+        // "()Ljava/lang/String;");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(HashMap.class), "containsKey",
+        // "(Ljava/lang/Object;)Z");
+        // Label exists = new Label();
+        // super.visitJumpInsn(Opcodes.IFNE, exists);
+        // super.visitFieldInsn(GETSTATIC, className, fieldName +
+        // "_replayIndex", "Ljava/util/HashMap;");
+        // super.visitMethodInsn(INVOKESTATIC,
+        // Type.getInternalName(Thread.class), "currentThread",
+        // "()Ljava/lang/Thread;");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(Thread.class), "getName",
+        // "()Ljava/lang/String;");
+        // super.visitInsn(ICONST_0);
+        // super.visitMethodInsn(INVOKESTATIC,
+        // Type.getInternalName(Integer.class), "valueOf",
+        // "(I)Ljava/lang/Integer;");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(HashMap.class), "put",
+        // "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+        // super.visitInsn(POP);
+        // super.visitLabel(exists);
+        // super.visitFieldInsn(GETSTATIC, className, fieldName +
+        // "_replayIndex", "Ljava/util/HashMap;");
+        // super.visitMethodInsn(INVOKESTATIC,
+        // Type.getInternalName(Thread.class), "currentThread",
+        // "()Ljava/lang/Thread;");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(Thread.class), "getName",
+        // "()Ljava/lang/String;");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(HashMap.class), "get",
+        // "(Ljava/lang/Object;)Ljava/lang/Object;");
+        // super.visitTypeInsn(CHECKCAST, "java/lang/Integer");
+        // super.visitMethodInsn(INVOKEVIRTUAL,
+        // Type.getInternalName(Integer.class), "intValue", "()I");
+
+        Label load = new Label();
+        visitLabel(load);
+        super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex",
+                "Ljava/util/HashMap;");
+        super.visitFieldInsn(GETSTATIC, className, fieldName + "_owners", "[Ljava/lang/String;");
+        super.visitFieldInsn(GETSTATIC, className, fieldName + "_fill", "I");
+        super.visitLdcInsn(className);
+        if (className.contains("Serializable"))
+            super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ReplayUtils.class),
+                    "getNextIndex", "(Ljava/util/HashMap;[Ljava/lang/String;ILjava/lang/String;)I");
+        else {
+            super.visitFieldInsn(GETSTATIC, className, fieldName, "[Ljava/lang/Object;");
+
+            super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ReplayUtils.class),
+                    "getNextIndexO",
+                    "(Ljava/util/HashMap;[Ljava/lang/String;ILjava/lang/String;[Ljava/lang/Object;)I");
+        }
+        super.visitInsn(DUP);
+        Label cont = new Label();
+        super.visitJumpInsn(IFGE, cont);
+        super.visitInsn(POP);
+        super.visitLdcInsn(className);
+        super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ReplayRunner.class),
+                "loadNextLog", "(Ljava/lang/String;)V");
+        super.visitJumpInsn(GOTO, load);
+        visitLabel(cont);
+        // super.visitInsn(ICONST_0);
+    }
+
+    private void incrementReplayIndex(String className, String fieldName) {
+        super.visitFieldInsn(GETSTATIC, className, fieldName + "_replayIndex",
+                "Ljava/util/HashMap;");
+        super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Thread.class), "currentThread",
+                "()Ljava/lang/Thread;");
+        super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Thread.class), "getName",
+                "()Ljava/lang/String;");
+        loadReplayIndex(className, fieldName);
+        super.visitInsn(ICONST_1);
+        super.visitInsn(IADD);
+        super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf",
+                "(I)Ljava/lang/Integer;");
+        super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(HashMap.class), "put",
+                "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+        super.visitInsn(POP);
+
+        super.visitFieldInsn(GETSTATIC, Type.getInternalName(ExportedLog.class),
+                "globalReplayIndex", "I");
+        super.visitInsn(ICONST_1);
+        super.visitInsn(IADD);
+        super.visitFieldInsn(PUTSTATIC, Type.getInternalName(ExportedLog.class),
+                "globalReplayIndex", "I");
+    }
+
+    private HashMap<String, MethodInsnNode> captureMethodsToGenerate = new HashMap<String, MethodInsnNode>();
+
+    private boolean inited;
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+        if (owner.equals(Type.getInternalName(ChroniclerJExportRunner.class))
+                && name.equals("genTestCase"))
+            return;
+        if (owner.equals("java/lang/reflect/Method") && name.equals("invoke")) {
+            opcode = Opcodes.INVOKESTATIC;
+            owner = "edu/columbia/cs/psl/chroniclerj/MethodInterceptor";
+            super.visitMethodInsn(Opcodes.INVOKESTATIC,
+                    "edu/columbia/cs/psl/chroniclerj/MethodInterceptor", "invokeReplay",
+                    "(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
+            return;
+        }
+        try {
+            MethodCall m = new MethodCall(this.name, this.desc, this.classDesc, 0, lineNumber,
+                    owner, name, desc, isStatic);
+            Type returnType = Type.getMethodType(desc).getReturnType();
+            if (opcode == INVOKESPECIAL
+                    && name.equals("<init>")
+                    && NonDeterministicLoggingMethodVisitor.nonDeterministicMethods.contains(owner
+                            + "." + name + ":" + desc)) {
+
+                if (!(owner.equals(Instrumenter.instrumentedClasses.get(classDesc).superName) && this.name
+                        .equals("<init>"))) {
+                    if (analyzer.stack == null) {
+                        super.visitMethodInsn(opcode, owner, name, desc);
+                    } else {
+                        Type[] args = Type.getArgumentTypes(desc);
+                        for (int i = args.length - 1; i >= 0; i--) {
+                            Type t = args[i];
+                            if (t.getSize() == 2)
+                                mv.visitInsn(POP2);
+                            else
+                                mv.visitInsn(POP);
+                        }
+
+                        if (analyzer.stack != null
+                                && analyzer.stack.size() > 0
+                                && analyzer.uninitializedTypes.containsKey(analyzer.stack
+                                        .get(analyzer.stack.size() - 1))
+                                && analyzer.uninitializedTypes.get(
+                                        analyzer.stack.get(analyzer.stack.size() - 1))
+                                        .equals(owner)) {
+                            mv.visitInsn(POP);
+                            if (analyzer.stack.size() > 0
+                                    && analyzer.uninitializedTypes.containsKey(analyzer.stack
+                                            .get(analyzer.stack.size() - 1))
+                                    && analyzer.uninitializedTypes.get(
+                                            analyzer.stack.get(analyzer.stack.size() - 1)).equals(
+                                            owner))
+                                mv.visitInsn(POP);
+
+                            String replayClassName = MethodCall.getReplayClassName(Type.getType("L"
+                                    + m.getMethodOwner() + ";"));
+                            mv.visitFieldInsn(GETSTATIC, replayClassName, m.getLogFieldName(),
+                                    "[Ljava/lang/Object;");
+
+                            loadReplayIndex(replayClassName, m.getLogFieldName());
+
+                            mv.visitInsn(AALOAD);
+                            mv.visitTypeInsn(CHECKCAST, m.getMethodOwner());
+                            incrementReplayIndex(replayClassName, m.getLogFieldName());
+                        }
+                    }
+                } else {
+                    super.visitMethodInsn(opcode, owner, name, desc);
+                }
+
+            } else if ((!constructor || isFirstConstructor || superInitialized)
+                    && returnType.equals(Type.VOID_TYPE)
+                    && !name.equals("<init>")
+                    && NonDeterministicLoggingMethodVisitor.nonDeterministicMethods.contains(owner
+                            + "." + name + ":" + desc)) {
+                Type[] args = Type.getArgumentTypes(desc);
+                for (int i = args.length - 1; i >= 0; i--) {
+                    Type t = args[i];
+                    if (t.getSize() == 2)
+                        mv.visitInsn(POP2);
+                    else
+                        mv.visitInsn(POP);
+                }
+                if (opcode != INVOKESTATIC)
+                    mv.visitInsn(POP);
+
+                // else
+                // super.visitMethodInsn(opcode, owner, name, desc);
+
+            } else if ((!constructor || isFirstConstructor || superInitialized)
+                    && !returnType.equals(Type.VOID_TYPE)
+                    && NonDeterministicLoggingMethodVisitor.nonDeterministicMethods.contains(owner
+                            + "." + name + ":" + desc)) {
+
+                super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock",
+                        Type.getDescriptor(Lock.class));
+                super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "lock",
+                        "()V");
+
+                logger.debug("Adding field in MV to list " + m.getLogFieldName());
+                methodCallsToClear.add(m);
+                Type[] args = Type.getArgumentTypes(desc);
+                boolean hasArray = false;
+                for (Type t : args)
+                    if (t.getSort() == Type.ARRAY)
+                        hasArray = true;
+
+                if (hasArray) {
+
+                    Type[] targs = Type.getArgumentTypes(desc);
+                    for (int i = targs.length - 1; i >= 0; i--) {
+                        Type t = targs[i];
+                        if (t.getSort() == Type.ARRAY) {
+                            /*
+                             * stack (grows down): dest (fill not incremented
+                             * yet)
+                             */
+                            String replayClassName = MethodCall.getReplayClassName(t);
+                            String replayFieldName = MethodCall.getLogFieldName(t);
+                            mv.visitFieldInsn(GETSTATIC, replayClassName, MethodCall
+                                    .getLogFieldName(t), MethodCall.getLogFieldType(t)
+                                    .getDescriptor());
+                            // mv.visitFieldInsn(GETSTATIC,replayClassName,
+                            // MethodCall.getLogFieldName(t)+"_replayIndex",
+                            // "I");
+                            loadReplayIndex(replayClassName, replayFieldName);
+                            // mv.visitInsn(DUP);
+                            // mv.visitFieldInsn(GETSTATIC, replayClassName,
+                            // MethodCall.getLogFieldName(t) + "_fill", "I");
+                            // Label fallThrough = new Label();
+                            //
+                            // mv.visitJumpInsn(Opcodes.IF_ICMPNE, fallThrough);
+                            // mv.visitMethodInsn(Opcodes.INVOKESTATIC,
+                            // Type.getInternalName(ReplayRunner.class),
+                            // "loadNextLog", "()V");
+                            // pop();
+                            // loadReplayIndex(replayClassName,
+                            // replayFieldName);
+                            // visitLabel(fallThrough);
+
+                            arrayLoad(t);
+
+                            /*
+                             * stack (grows down): dest src
+                             */
+                            swap();
+                            /*
+                             * stack (grows down): src dest
+                             */
+                            push(0);
+                            /*
+                             * stack (grows down): src dest 0
+                             */
+                            swap();
+                            /*
+                             * stack (grows down): src 0 dest
+                             */
+                            push(0);
+                            /*
+                             * stack (grows down): src 0 dest 0
+                             */
+
+                            mv.visitFieldInsn(GETSTATIC, replayClassName, MethodCall
+                                    .getLogFieldName(t), MethodCall.getLogFieldType(t)
+                                    .getDescriptor());
+                            loadReplayIndex(replayClassName, replayFieldName);
+                            arrayLoad(t);
+                            mv.visitTypeInsn(Opcodes.CHECKCAST, t.getInternalName());
+                            mv.visitInsn(ARRAYLENGTH);
+                            incrementReplayIndex(replayClassName, replayFieldName);
+                            /*
+                             * stack: src (fill incremented) 0 dest 0 length
+                             */
+                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "arraycopy",
+                                    "(Ljava/lang/Object;ILjava/lang/Object;II)V");
+                            /*
+                             * stack: dest popped
+                             */
+                        } else {
+                            switch (t.getSize()) {
+                                case 2:
+                                    mv.visitInsn(POP2);
+                                    break;
+                                case 1:
+                                default:
+                                    mv.visitInsn(POP);
+                                    break;
+                            }
+                        }
+                    }
+
+                } else {
+                    // Type[] targs = Type.getArgumentTypes(desc);
+                    // for (Type t : targs) {
+                    // switch (t.getSize()) {
+                    // case 2:
+                    // visitInsn(POP2);
+                    // break;
+                    // case 1:
+                    // default:
+                    // visitInsn(POP);
+                    // break;
+                    // }
+                    // }
+                    for (int i = args.length - 1; i >= 0; i--) {
+                        Type t = args[i];
+                        if (t.getSize() == 2)
+                            mv.visitInsn(POP2);
+                        else
+                            mv.visitInsn(POP);
+                    }
+                }
+
+                if (opcode != INVOKESTATIC)
+                    mv.visitInsn(POP);
+
+                if (returnType.getSort() == Type.VOID)
+                    mv.visitInsn(NOP);
+                else {
+                    mv.visitFieldInsn(GETSTATIC, m.getReplayClassName(), m.getLogFieldName(), m
+                            .getLogFieldType().getDescriptor());
+
+                    loadReplayIndex(m.getReplayClassName(), m.getLogFieldName());
+                    arrayLoad(m.getReturnType());
+                    incrementReplayIndex(m.getReplayClassName(), m.getLogFieldName());
+                }
+                // Unlock
+                super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock",
+                        Type.getDescriptor(Lock.class));
+                super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "unlock",
+                        "()V");
+
+            } else {
+                super.visitMethodInsn(opcode, owner, name, desc);
+            }
+        } catch (Exception ex) {
+            logger.error("Unable to instrument method call", ex);
+        }
+    }
+
+    @Override
+    protected void onMethodEnter() {
+        if (this.name.equals("<init>") && isCallbackInit) {
+            super.visitVarInsn(ALOAD, 0);
+            super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(CallbackRegistry.class),
+                    "register", "(Ljava/lang/Object;)V");
+            inited = true;
+        }
+    }
+
+    private ArrayList<MethodCall> methodCallsToClear = new ArrayList<MethodCall>();

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayRunner.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayRunner.java
index 45ac3d6..982822a 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayRunner.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayRunner.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.replay;

 import java.io.File;
@@ -25,139 +26,138 @@ import edu.columbia.cs.psl.chroniclerj.Log;
 import edu.columbia.cs.psl.chroniclerj.xstream.StaticReflectionProvider;

 public class ReplayRunner {
-	public static String[] logFiles;
-	public static String[] serializableLogFiles;
-
-	private static int nextLog = 0;
-	private static int nextSerializableLog = 0;
-
-	public static void loadNextLog(String logClass) {
-		try {
-			Log.logLock.lock();
-			_loadNextLog(logClass);
-			Log.logLock.unlock();
-			ReplayUtils.checkForDispatch();
-		} catch (Exception exi) {
-			exi.printStackTrace();
-		}
-	}
-
-	private static void _loadNextLog(String logClass) {
-		try {
-			if (logClass.contains("Serializable")) {
-				ObjectInputStream is = new ObjectInputStream(loader.getResourceAsStream(serializableLogFiles[nextSerializableLog]));
-				@SuppressWarnings("unused")
-				ExportedSerializableLog el = (ExportedSerializableLog) is.readObject();
-				is.close();
-				nextSerializableLog++;
-			} else {
-				XStream xstream = new XStream(new StaticReflectionProvider());
-				@SuppressWarnings("unused")
-				Object o = xstream.fromXML(loader.getResourceAsStream(logFiles[nextLog]));
-				nextLog++;
-
-				ReplayUtils.dispatchesToRun = new HashMap<Integer,CallbackInvocation>();
-				for(Object e : ExportedLog.aLog)
-				{
-					if(e != null && e.getClass().equals(CallbackInvocation.class))
-					{
-//						System.out.println(e);
-						CallbackInvocation ci = (CallbackInvocation) e;
-						ReplayUtils.dispatchesToRun.put(ci.getClock(), ci);
-					}
-				}
-			}
-//			System.out.println(ExportedSerializableLog.aLog_fill);
-//			System.out.println(ExportedLog.aLog_fill);
-		} catch (Exception exi) {
-			exi.printStackTrace();
-		}
-	}
-	private static 		URLClassLoader loader = null;
-	public static void _main(String[] classpath) {
-	if(! new File(classpath[0]).exists())
-	{
-		System.err.println("Unable to load test case " + classpath[0]);
-		System.exit(-1);
-	}
-		try {
-			URL[] urls = new URL[classpath.length];
-			for(int i = 0; i < classpath.length; i++)
-			{
-				urls[i] = new File(classpath[i]).toURI().toURL();
-			}
-			loader = new URLClassLoader(urls);
-		} catch (MalformedURLException e1) {
-			e1.printStackTrace();
-			System.exit(-1);
-		}
-
-		InputStream inputStream  = loader.getResourceAsStream("main-info");
-
-		Scanner s = new Scanner(inputStream);
-		String mainClass = s.nextLine();
-		ArrayList<String> _serializableLogs = new ArrayList<String>();
-		ArrayList<String> _logs = new ArrayList<String>();
-		int nArgs = Integer.parseInt(s.nextLine());
-		String[] params = new String[nArgs];
-		int nSerializableLogs = 0;
-
-		int nLogs = 0;
-		for(int i = 0; i<nArgs;i++)
-		{
-			params[i] = s.nextLine();
-		}
-		while(s.hasNextLine())
-		{
-			String l = s.nextLine();
-			if(l.contains("_serializable_"))
-			{
-				_serializableLogs.add(l);
-				nSerializableLogs++;
-			}
-			else
-			{
-				_logs.add(l);
-				nLogs++;
-
-			}
-		}
-		s.close();
-		logFiles = new String[nLogs];
-		serializableLogFiles = new String[nSerializableLogs];
-
-		logFiles = _logs.toArray(logFiles);
-		serializableLogFiles = _serializableLogs.toArray(serializableLogFiles);
-
-		System.out.println("Available logs: " + Arrays.deepToString(logFiles) + Arrays.deepToString(serializableLogFiles));
-		_loadNextLog(Type.getDescriptor(ExportedSerializableLog.class));
-
-		_loadNextLog(Type.getDescriptor(ExportedLog.class));
-		ReplayUtils.checkForDispatch();
-		Class<?> toRun;
-		try {
-			toRun = loader.loadClass(mainClass.replace("/", "."));
-			Method meth = toRun.getMethod("main", String[].class);
-			meth.invoke(null, new Object[] { params });
-
-		} catch (ClassNotFoundException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (IllegalArgumentException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (SecurityException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (IllegalAccessException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (InvocationTargetException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (NoSuchMethodException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-	}
+    public static String[] logFiles;
+
+    public static String[] serializableLogFiles;
+
+    private static int nextLog = 0;
+
+    private static int nextSerializableLog = 0;
+
+    public static void loadNextLog(String logClass) {
+        try {
+            Log.logLock.lock();
+            _loadNextLog(logClass);
+            Log.logLock.unlock();
+            ReplayUtils.checkForDispatch();
+        } catch (Exception exi) {
+            exi.printStackTrace();
+        }
+    }
+
+    private static void _loadNextLog(String logClass) {
+        try {
+            if (logClass.contains("Serializable")) {
+                ObjectInputStream is = new ObjectInputStream(
+                        loader.getResourceAsStream(serializableLogFiles[nextSerializableLog]));
+                @SuppressWarnings("unused")
+                ExportedSerializableLog el = (ExportedSerializableLog) is.readObject();
+                is.close();
+                nextSerializableLog++;
+            } else {
+                XStream xstream = new XStream(new StaticReflectionProvider());
+                @SuppressWarnings("unused")
+                Object o = xstream.fromXML(loader.getResourceAsStream(logFiles[nextLog]));
+                nextLog++;
+
+                ReplayUtils.dispatchesToRun = new HashMap<Integer, CallbackInvocation>();
+                for (Object e : ExportedLog.aLog) {
+                    if (e != null && e.getClass().equals(CallbackInvocation.class)) {
+                        // System.out.println(e);
+                        CallbackInvocation ci = (CallbackInvocation) e;
+                        ReplayUtils.dispatchesToRun.put(ci.getClock(), ci);
+                    }
+                }
+            }
+            // System.out.println(ExportedSerializableLog.aLog_fill);
+            // System.out.println(ExportedLog.aLog_fill);
+        } catch (Exception exi) {
+            exi.printStackTrace();
+        }
+    }
+
+    private static URLClassLoader loader = null;
+
+    public static void _main(String[] classpath) {
+        if (!new File(classpath[0]).exists()) {
+            System.err.println("Unable to load test case " + classpath[0]);
+            System.exit(-1);
+        }
+        try {
+            URL[] urls = new URL[classpath.length];
+            for (int i = 0; i < classpath.length; i++) {
+                urls[i] = new File(classpath[i]).toURI().toURL();
+            }
+            loader = new URLClassLoader(urls);
+        } catch (MalformedURLException e1) {
+            e1.printStackTrace();
+            System.exit(-1);
+        }
+
+        InputStream inputStream = loader.getResourceAsStream("main-info");
+
+        Scanner s = new Scanner(inputStream);
+        String mainClass = s.nextLine();
+        ArrayList<String> _serializableLogs = new ArrayList<String>();
+        ArrayList<String> _logs = new ArrayList<String>();
+        int nArgs = Integer.parseInt(s.nextLine());
+        String[] params = new String[nArgs];
+        int nSerializableLogs = 0;
+
+        int nLogs = 0;
+        for (int i = 0; i < nArgs; i++) {
+            params[i] = s.nextLine();
+        }
+        while (s.hasNextLine()) {
+            String l = s.nextLine();
+            if (l.contains("_serializable_")) {
+                _serializableLogs.add(l);
+                nSerializableLogs++;
+            } else {
+                _logs.add(l);
+                nLogs++;
+
+            }
+        }
+        s.close();
+        logFiles = new String[nLogs];
+        serializableLogFiles = new String[nSerializableLogs];
+
+        logFiles = _logs.toArray(logFiles);
+        serializableLogFiles = _serializableLogs.toArray(serializableLogFiles);
+
+        System.out.println("Available logs: " + Arrays.deepToString(logFiles)
+                + Arrays.deepToString(serializableLogFiles));
+        _loadNextLog(Type.getDescriptor(ExportedSerializableLog.class));
+
+        _loadNextLog(Type.getDescriptor(ExportedLog.class));
+        ReplayUtils.checkForDispatch();
+        Class<?> toRun;
+        try {
+            toRun = loader.loadClass(mainClass.replace("/", "."));
+            Method meth = toRun.getMethod("main", String[].class);
+            meth.invoke(null, new Object[] {
+                params
+            });
+
+        } catch (ClassNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils.java
index 2ed6ce4..0b2ba27 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils.java
@@ -1,90 +1,93 @@
+
 package edu.columbia.cs.psl.chroniclerj.replay;

-import java.util.Arrays;
 import java.util.HashMap;

 import edu.columbia.cs.psl.chroniclerj.CallbackInvocation;
 import edu.columbia.cs.psl.chroniclerj.ExportedLog;
-import edu.columbia.cs.psl.chroniclerj.ExportedSerializableLog;

 public class ReplayUtils {
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	public static int getNextIndex(HashMap replayIndexMap, String[] threadEntries, int fill, String logClass)
-	{
-		String threadName = Thread.currentThread().getName();
+    @SuppressWarnings({
+            "rawtypes", "unchecked"
+    })
+    public static int getNextIndex(HashMap replayIndexMap, String[] threadEntries, int fill,
+            String logClass) {
+        String threadName = Thread.currentThread().getName();
+        if (threadName.equals("Finalizer"))
+            threadName = threadName + curFinalizer;
+        if (!replayIndexMap.containsKey(threadName))
+            replayIndexMap.put(threadName, 0);
+        int r = (int) replayIndexMap.get(threadName);
+        while (r <= fill && threadEntries[r] != null && !threadEntries[r].equals(threadName)) {
+            r++;
+        }
+        checkForDispatch();
+        if (threadEntries[r] == null) {
+            // System.out.println(Arrays.deepToString(threadEntries));
+
+            // System.out.println(Arrays.deepToString(ExportedSerializableLog.iLog_owners));
+            return r;
+        }
+        if (threadEntries[r] != null && threadEntries[r].equals(threadName)) {
+            replayIndexMap.put(threadName, r);
+            return r;
+        }
+
+        // System.out.println("Skipping " + threadEntries[r] + " vs " +
+        // threadName);
+        return -1;
+    }
+
+    public static HashMap<Integer, CallbackInvocation> dispatchesToRun;
+
+    public static void checkForDispatch() {
+        int curClock = ExportedLog.globalReplayIndex;
+        // System.out.println("Looking for dispatches at " + curClock);
+        if (dispatchesToRun.get(curClock) != null) {
+            // System.out.println("Invoke " + dispatchesToRun.get(curClock));
+            if (dispatchesToRun.get(curClock).invoke()) {
+                // System.out.println("Success");
+                ExportedLog.globalReplayIndex++;
+                checkForDispatch();
+            }
+        }
+        curClock++;
+        if (dispatchesToRun.get(curClock) != null) {
+            // System.out.println("Invoke " + dispatchesToRun.get(curClock));
+            if (dispatchesToRun.get(curClock).invoke()) {
+                // System.out.println("Success");
+                ExportedLog.globalReplayIndex += 2;
+                checkForDispatch();
+            }
+        }
+    }
+
+    public static long curFinalizer;

-		if(!replayIndexMap.containsKey(threadName))
-			replayIndexMap.put(threadName, 0);
-		int r = (int) replayIndexMap.get(threadName);
-		while(r <= fill && threadEntries[r] != null && !threadEntries[r].equals(threadName))
-		{
-			r++;
-		}
-		checkForDispatch();
-		if(threadEntries[r] == null)
-		{
-//			System.out.println(Arrays.deepToString(threadEntries));
-
-//			System.out.println(Arrays.deepToString(ExportedSerializableLog.iLog_owners));
-			return r;
-		}
-		if(threadEntries[r] != null && threadEntries[r].equals(threadName))
-		{
-			replayIndexMap.put(threadName, r);
-			return r;
-		}
+    @SuppressWarnings({
+            "rawtypes", "unchecked"
+    })
+    public static int getNextIndexO(HashMap replayIndexMap, String[] threadEntries, int fill,
+            String logClass, Object[] log) {

-//		System.out.println("Skipping " + threadEntries[r] + " vs " + threadName);
-		return -1;
-	}
-	public static HashMap<Integer, CallbackInvocation> dispatchesToRun;
-	public static void checkForDispatch()
-	{
-		int curClock = ExportedLog.globalReplayIndex;
-//		System.out.println("Looking for dispatches at " + curClock);
-		if(dispatchesToRun.get(curClock) != null)
-		{
-//			System.out.println("Invoke " + dispatchesToRun.get(curClock));
-			if(dispatchesToRun.get(curClock).invoke())
-			{
-//				System.out.println("Success");
-				ExportedLog.globalReplayIndex++;
-				checkForDispatch();
-			}
-		}
-		curClock++;
-		if(dispatchesToRun.get(curClock) != null)
-		{
-//			System.out.println("Invoke " + dispatchesToRun.get(curClock));
-			if(dispatchesToRun.get(curClock).invoke())
-			{
-//				System.out.println("Success");
-				ExportedLog.globalReplayIndex+=2;
-				checkForDispatch();
-			}
-		}
-	}
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	public static int getNextIndexO(HashMap replayIndexMap, String[] threadEntries, int fill, String logClass, Object[] log)
-	{
-		String threadName = Thread.currentThread().getName();
-		if(!replayIndexMap.containsKey(threadName))
-			replayIndexMap.put(threadName, 0);
-		int r = (int) replayIndexMap.get(threadName);
-		while(r <= fill && threadEntries[r] != null && !threadEntries[r].equals(threadName))
-		{
-			r++;
-		}
+        String threadName = Thread.currentThread().getName();
+        if (threadName.equals("Finalizer"))
+            threadName = threadName + curFinalizer;
+        if (!replayIndexMap.containsKey(threadName))
+            replayIndexMap.put(threadName, 0);
+        int r = (int) replayIndexMap.get(threadName);
+        while (r <= fill && threadEntries[r] != null && !threadEntries[r].equals(threadName)) {
+            r++;
+        }

-		checkForDispatch();
-		if(threadEntries[r] == null)
-			System.exit(-1);
-		if(threadEntries[r].equals(threadName))
-		{
-			replayIndexMap.put(threadName, r);
-			return r;
-		}
+        checkForDispatch();
+        if (threadEntries[r] == null)
+            System.exit(-1);
+        if (threadEntries[r].equals(threadName)) {
+            replayIndexMap.put(threadName, r);
+            return r;
+        }

-		return -1;
-	}
+        return -1;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/Replayer.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/Replayer.java
index d357b25..c889b26 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/Replayer.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/replay/Replayer.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.replay;

 import java.io.ByteArrayOutputStream;
@@ -33,313 +34,298 @@ import edu.columbia.cs.psl.chroniclerj.struct.AnnotatedMethod;

 public class Replayer {

-	private static Logger logger = Logger.getLogger(Replayer.class);
-
-
-	private static final int NUM_PASSES = 2;
-	private static final int PASS_ANALYZE = 0;
-	private static final int PASS_OUTPUT = 1;
-
-	private static int pass_number = 0;
-
-	private static File rootOutputDir;
-	private static String lastInstrumentedClass;
-
-	public static AnnotatedMethod getAnnotatedMethod(String owner, String name,
-			String desc) {
-		String lookupKey = owner + "." + name + ":" + desc;
-		return Instrumenter.annotatedMethods.get(lookupKey);
-	}
-
-
-
-	private static void finishedPass() {
-		switch (pass_number) {
-		case PASS_ANALYZE:
-			break;
-		case PASS_OUTPUT:
-			break;
-		}
-	}
-
-	private static byte[] instrumentClass(InputStream is) {
-		try {
-			ClassReader cr = new ClassReader(is);
-			{
-				ClassWriter cw = new ClassWriter(cr, 0);
-				SerialVersionUIDAdder uidAdder = new SerialVersionUIDAdder(cw);
-				cr.accept(uidAdder, 0);
-				byte[] b = cw.toByteArray();
-				cr = new ClassReader(b);
-			}
-			ClassWriter cw = new InstrumenterClassWriter(cr,
-					ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES,
-					Instrumenter.loader);
-			NonDeterministicReplayClassVisitor cv = new NonDeterministicReplayClassVisitor(
-					Opcodes.ASM4, cw);
-			cr.accept(cv, ClassReader.EXPAND_FRAMES);
-			Instrumenter.methodCalls.put(cv.getClassName(), cv.getLoggedMethodCalls());
-			lastInstrumentedClass = cv.getClassName();
-			byte[] out = cw.toByteArray();
-			try{
-//				 ClassReader cr2 = new ClassReader(out);
-//				 cr2.accept(new CheckClassAdapter(new ClassWriter(0)), 0);
-				}
-				catch(Exception ex)
-				{
-					System.err.println(lastInstrumentedClass);
-					ex.printStackTrace();
-				}
-
-			return out;
-		} catch (Exception ex) {
-			logger.error("Exception processing class:", ex);
-			return null;
-		}
-	}
-
-	public static void _main(String[] args) {
-
-		String outputFolder = args[1];
-		rootOutputDir = new File(outputFolder);
-		if (!rootOutputDir.exists())
-			rootOutputDir.mkdir();
-		String inputFolder = args[0];
-
-		pass_number = PASS_OUTPUT;
-			File f = new File(inputFolder);
-			if (!f.exists()) {
-				System.err.println("Unable to read path " + inputFolder);
-				System.exit(-1);
-			}
-			if (f.isDirectory())
-				processDirectory(f, rootOutputDir, true);
-			else if (inputFolder.endsWith(".jar"))
-				processJar(f, rootOutputDir);
-			else if (inputFolder.endsWith(".class"))
-				try {
-					processClass(f.getName(), new FileInputStream(f),
-							rootOutputDir);
-				} catch (FileNotFoundException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			else {
-				System.err.println("Unknown type for path " + inputFolder);
-				System.exit(-1);
-			}
-			finishedPass();
-
-	}
-
-	private static void processClass(String name, InputStream is, File outputDir) {
-		ByteArrayOutputStream bos = null;
-		FileOutputStream fos = null;
-
-		switch (pass_number) {
-		case PASS_ANALYZE:
-			break;
-		case PASS_OUTPUT:
-			try {
-				File f = new File(outputDir.getPath()
-						+ File.separator + name);
-				if(f.exists())
-					f.delete();
-				fos = new FileOutputStream(f);
-				bos = new ByteArrayOutputStream();
-				bos.write(instrumentClass(is));
-
-//				if (name.contains("Reader")) {
-//					ReplayRunner.run(bos.toByteArray(), "ReaderUser");
-//				}
-
-			} catch (Exception ex) {
-				ex.printStackTrace();
-				System.exit(-1);
-			} finally {
-				try {
-					bos.writeTo(fos);
-					fos.close();
-				} catch (IOException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			}
-		}
-	}
-
-	/*
-	 * private static byte[] generateReplayClass() { return
-	 * generateReplayClass(lastInstrumentedClass); }
-	 */
-
-	private static void processDirectory(File f, File parentOutputDir,
-			boolean isFirstLevel) {
-		File thisOutputDir;
-		if (isFirstLevel) {
-			thisOutputDir = parentOutputDir;
-		} else {
-			thisOutputDir = new File(parentOutputDir.getAbsolutePath()
-					+ File.separator + f.getName());
-			if (pass_number == PASS_OUTPUT)
-				thisOutputDir.mkdir();
-		}
-		for (File fi : f.listFiles()) {
-			if (fi.isDirectory())
-				processDirectory(fi, thisOutputDir, false);
-			else if (fi.getName().endsWith(".class"))
-				try {
-					processClass(fi.getName(), new FileInputStream(fi),
-							thisOutputDir);
-				} catch (FileNotFoundException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			else if (fi.getName().endsWith(".jar"))
-				processJar(fi, thisOutputDir);
-			else if (pass_number == PASS_OUTPUT) {
-				File dest = new File(thisOutputDir.getPath() + File.separator
-						+ fi.getName());
-				FileChannel source = null;
-				FileChannel destination = null;
-
-				try {
-					source = new FileInputStream(fi).getChannel();
-					destination = new FileOutputStream(dest).getChannel();
-					destination.transferFrom(source, 0, source.size());
-				} catch (Exception ex) {
-					logger.error("Unable to copy file " + fi, ex);
-					System.exit(-1);
-				} finally {
-					if (source != null) {
-						try {
-							source.close();
-						} catch (IOException e) {
-							// TODO Auto-generated catch block
-							e.printStackTrace();
-						}
-					}
-					if (destination != null) {
-						try {
-							destination.close();
-						} catch (IOException e) {
-							// TODO Auto-generated catch block
-							e.printStackTrace();
-						}
-					}
-				}
-
-			}
-		}
-
-	}
-
-	private static void processJar(File f, File outputDir) {
-		try {
-			@SuppressWarnings("resource")
-			JarFile jar = new JarFile(f);
-			JarOutputStream jos = null;
-			if (pass_number == PASS_OUTPUT)
-				jos = new JarOutputStream(new FileOutputStream(
-						outputDir.getPath() + File.separator + f.getName()));
-			Enumeration<JarEntry> entries = jar.entries();
-			while (entries.hasMoreElements()) {
-				JarEntry e = entries.nextElement();
-				switch (pass_number) {
-				case PASS_ANALYZE:
-					break;
-				case PASS_OUTPUT:
-					if (e.getName().endsWith(".class")
-							&& !e.getName().startsWith("java")
-							&& !e.getName().startsWith("org/objenesis")
-							&& !e.getName().startsWith(
-									"com/thoughtworks/xstream/")
-							&& !e.getName().startsWith("com/rits/cloning")
-							&& !e.getName().startsWith(
-									"com/apple/java/Application") && !e.getName().startsWith("net/sf/cglib/")) {
-						{
-							JarEntry outEntry = new JarEntry(e.getName());
-							jos.putNextEntry(outEntry);
-							byte[] clazz = instrumentClass(jar
-									.getInputStream(e));
-							if(clazz == null)
-							{
-								InputStream is = jar.getInputStream(e);
-								byte[] buffer = new byte[1024];
-								while (true) {
-									int count = is.read(buffer);
-									if (count == -1)
-										break;
-									jos.write(buffer, 0, count);
-								}
-							}
-							else
-									jos.write(clazz);
-							jos.closeEntry();
-						}
-						{
-							/*
-							 * JarEntry outEntry = new
-							 * JarEntry(e.getName().replace(".class",
-							 * Constants.LOG_CLASS_SUFFIX +".class"));
-							 * jos.putNextEntry(outEntry); byte[] clazz =
-							 * generateReplayClass(); jos.write(clazz);
-							 * jos.closeEntry();
-							 */
-						}
-
-					} else {
-						JarEntry outEntry = new JarEntry(e.getName());
-						if (e.isDirectory()) {
-							jos.putNextEntry(outEntry);
-							jos.closeEntry();
-						} else if (e.getName().startsWith("META-INF")
-								&& (e.getName().endsWith(".SF") || e.getName()
-										.endsWith(".RSA"))) {
-							// don't copy this
-						} else if (e.getName().equals("META-INF/MANIFEST.MF")) {
-							Scanner s = new Scanner(jar.getInputStream(e));
-							jos.putNextEntry(outEntry);
-
-							String curPair = "";
-							while (s.hasNextLine()) {
-								String line = s.nextLine();
-								if (line.equals("")) {
-									curPair += "\n";
-									if (!curPair.contains("SHA1-Digest:"))
-										jos.write(curPair.getBytes());
-									curPair = "";
-								} else {
-									curPair += line + "\n";
-								}
-							}
-							s.close();
-							jos.write("\n".getBytes());
-							jos.closeEntry();
-						} else {
-							jos.putNextEntry(outEntry);
-							InputStream is = jar.getInputStream(e);
-							byte[] buffer = new byte[1024];
-							while (true) {
-								int count = is.read(buffer);
-								if (count == -1)
-									break;
-								jos.write(buffer, 0, count);
-							}
-							jos.closeEntry();
-						}
-					}
-				}
-
-			}
-			if (pass_number == PASS_OUTPUT) {
-				jos.close();
-			}
-		} catch (Exception e) {
-			// TODO Auto-generated catch block
-			logger.error("Unable to process jar" + f, e);
-			System.exit(-1);
-		}
-
-	}
+    private static Logger logger = Logger.getLogger(Replayer.class);
+
+    private static final int NUM_PASSES = 2;
+
+    private static final int PASS_ANALYZE = 0;
+
+    private static final int PASS_OUTPUT = 1;
+
+    private static int pass_number = 0;
+
+    private static File rootOutputDir;
+
+    private static String lastInstrumentedClass;
+
+    public static AnnotatedMethod getAnnotatedMethod(String owner, String name, String desc) {
+        String lookupKey = owner + "." + name + ":" + desc;
+        return Instrumenter.annotatedMethods.get(lookupKey);
+    }
+
+    private static void finishedPass() {
+        switch (pass_number) {
+            case PASS_ANALYZE:
+                break;
+            case PASS_OUTPUT:
+                break;
+        }
+    }
+
+    private static byte[] instrumentClass(InputStream is) {
+        try {
+            ClassReader cr = new ClassReader(is);
+            {
+                ClassWriter cw = new ClassWriter(cr, 0);
+                SerialVersionUIDAdder uidAdder = new SerialVersionUIDAdder(cw);
+                cr.accept(uidAdder, 0);
+                byte[] b = cw.toByteArray();
+                cr = new ClassReader(b);
+            }
+            ClassWriter cw = new InstrumenterClassWriter(cr, ClassWriter.COMPUTE_MAXS
+                    | ClassWriter.COMPUTE_FRAMES, Instrumenter.loader);
+            NonDeterministicReplayClassVisitor cv = new NonDeterministicReplayClassVisitor(
+                    Opcodes.ASM4, cw);
+            cr.accept(cv, ClassReader.EXPAND_FRAMES);
+            Instrumenter.methodCalls.put(cv.getClassName(), cv.getLoggedMethodCalls());
+            lastInstrumentedClass = cv.getClassName();
+            byte[] out = cw.toByteArray();
+            try {
+                // ClassReader cr2 = new ClassReader(out);
+                // cr2.accept(new CheckClassAdapter(new ClassWriter(0)), 0);
+            } catch (Exception ex) {
+                System.err.println(lastInstrumentedClass);
+                ex.printStackTrace();
+            }
+
+            return out;
+        } catch (Exception ex) {
+            logger.error("Exception processing class:", ex);
+            return null;
+        }
+    }
+
+    public static void _main(String[] args) {
+
+        String outputFolder = args[1];
+        rootOutputDir = new File(outputFolder);
+        if (!rootOutputDir.exists())
+            rootOutputDir.mkdir();
+        String inputFolder = args[0];
+
+        pass_number = PASS_OUTPUT;
+        File f = new File(inputFolder);
+        if (!f.exists()) {
+            System.err.println("Unable to read path " + inputFolder);
+            System.exit(-1);
+        }
+        if (f.isDirectory())
+            processDirectory(f, rootOutputDir, true);
+        else if (inputFolder.endsWith(".jar"))
+            processJar(f, rootOutputDir);
+        else if (inputFolder.endsWith(".class"))
+            try {
+                processClass(f.getName(), new FileInputStream(f), rootOutputDir);
+            } catch (FileNotFoundException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        else {
+            System.err.println("Unknown type for path " + inputFolder);
+            System.exit(-1);
+        }
+        finishedPass();
+
+    }
+
+    private static void processClass(String name, InputStream is, File outputDir) {
+        ByteArrayOutputStream bos = null;
+        FileOutputStream fos = null;
+
+        switch (pass_number) {
+            case PASS_ANALYZE:
+                break;
+            case PASS_OUTPUT:
+                try {
+                    File f = new File(outputDir.getPath() + File.separator + name);
+                    if (f.exists())
+                        f.delete();
+                    fos = new FileOutputStream(f);
+                    bos = new ByteArrayOutputStream();
+                    bos.write(instrumentClass(is));
+
+                    // if (name.contains("Reader")) {
+                    // ReplayRunner.run(bos.toByteArray(), "ReaderUser");
+                    // }
+
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                    System.exit(-1);
+                } finally {
+                    try {
+                        bos.writeTo(fos);
+                        fos.close();
+                    } catch (IOException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    }
+                }
+        }
+    }
+
+    /*
+     * private static byte[] generateReplayClass() { return
+     * generateReplayClass(lastInstrumentedClass); }
+     */
+
+    private static void processDirectory(File f, File parentOutputDir, boolean isFirstLevel) {
+        File thisOutputDir;
+        if (isFirstLevel) {
+            thisOutputDir = parentOutputDir;
+        } else {
+            thisOutputDir = new File(parentOutputDir.getAbsolutePath() + File.separator
+                    + f.getName());
+            if (pass_number == PASS_OUTPUT)
+                thisOutputDir.mkdir();
+        }
+        for (File fi : f.listFiles()) {
+            if (fi.isDirectory())
+                processDirectory(fi, thisOutputDir, false);
+            else if (fi.getName().endsWith(".class"))
+                try {
+                    processClass(fi.getName(), new FileInputStream(fi), thisOutputDir);
+                } catch (FileNotFoundException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            else if (fi.getName().endsWith(".jar"))
+                processJar(fi, thisOutputDir);
+            else if (pass_number == PASS_OUTPUT) {
+                File dest = new File(thisOutputDir.getPath() + File.separator + fi.getName());
+                FileChannel source = null;
+                FileChannel destination = null;
+
+                try {
+                    source = new FileInputStream(fi).getChannel();
+                    destination = new FileOutputStream(dest).getChannel();
+                    destination.transferFrom(source, 0, source.size());
+                } catch (Exception ex) {
+                    logger.error("Unable to copy file " + fi, ex);
+                    System.exit(-1);
+                } finally {
+                    if (source != null) {
+                        try {
+                            source.close();
+                        } catch (IOException e) {
+                            // TODO Auto-generated catch block
+                            e.printStackTrace();
+                        }
+                    }
+                    if (destination != null) {
+                        try {
+                            destination.close();
+                        } catch (IOException e) {
+                            // TODO Auto-generated catch block
+                            e.printStackTrace();
+                        }
+                    }
+                }
+
+            }
+        }
+
+    }
+
+    private static void processJar(File f, File outputDir) {
+        try {
+            @SuppressWarnings("resource")
+            JarFile jar = new JarFile(f);
+            JarOutputStream jos = null;
+            if (pass_number == PASS_OUTPUT)
+                jos = new JarOutputStream(new FileOutputStream(outputDir.getPath() + File.separator
+                        + f.getName()));
+            Enumeration<JarEntry> entries = jar.entries();
+            while (entries.hasMoreElements()) {
+                JarEntry e = entries.nextElement();
+                switch (pass_number) {
+                    case PASS_ANALYZE:
+                        break;
+                    case PASS_OUTPUT:
+                        if (e.getName().endsWith(".class") && !e.getName().startsWith("java")
+                                && !e.getName().startsWith("org/objenesis")
+                                && !e.getName().startsWith("com/thoughtworks/xstream/")
+                                && !e.getName().startsWith("com/rits/cloning")
+                                && !e.getName().startsWith("com/apple/java/Application")
+                                && !e.getName().startsWith("net/sf/cglib/")) {
+                            {
+                                JarEntry outEntry = new JarEntry(e.getName());
+                                jos.putNextEntry(outEntry);
+                                byte[] clazz = instrumentClass(jar.getInputStream(e));
+                                if (clazz == null) {
+                                    InputStream is = jar.getInputStream(e);
+                                    byte[] buffer = new byte[1024];
+                                    while (true) {
+                                        int count = is.read(buffer);
+                                        if (count == -1)
+                                            break;
+                                        jos.write(buffer, 0, count);
+                                    }
+                                } else
+                                    jos.write(clazz);
+                                jos.closeEntry();
+                            }
+                            {
+                                /*
+                                 * JarEntry outEntry = new
+                                 * JarEntry(e.getName().replace(".class",
+                                 * Constants.LOG_CLASS_SUFFIX +".class"));
+                                 * jos.putNextEntry(outEntry); byte[] clazz =
+                                 * generateReplayClass(); jos.write(clazz);
+                                 * jos.closeEntry();
+                                 */
+                            }
+
+                        } else {
+                            JarEntry outEntry = new JarEntry(e.getName());
+                            if (e.isDirectory()) {
+                                jos.putNextEntry(outEntry);
+                                jos.closeEntry();
+                            } else if (e.getName().startsWith("META-INF")
+                                    && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
+                                // don't copy this
+                            } else if (e.getName().equals("META-INF/MANIFEST.MF")) {
+                                Scanner s = new Scanner(jar.getInputStream(e));
+                                jos.putNextEntry(outEntry);
+
+                                String curPair = "";
+                                while (s.hasNextLine()) {
+                                    String line = s.nextLine();
+                                    if (line.equals("")) {
+                                        curPair += "\n";
+                                        if (!curPair.contains("SHA1-Digest:"))
+                                            jos.write(curPair.getBytes());
+                                        curPair = "";
+                                    } else {
+                                        curPair += line + "\n";
+                                    }
+                                }
+                                s.close();
+                                jos.write("\n".getBytes());
+                                jos.closeEntry();
+                            } else {
+                                jos.putNextEntry(outEntry);
+                                InputStream is = jar.getInputStream(e);
+                                byte[] buffer = new byte[1024];
+                                while (true) {
+                                    int count = is.read(buffer);
+                                    if (count == -1)
+                                        break;
+                                    jos.write(buffer, 0, count);
+                                }
+                                jos.closeEntry();
+                            }
+                        }
+                }
+
+            }
+            if (pass_number == PASS_OUTPUT) {
+                jos.close();
+            }
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            logger.error("Unable to process jar" + f, e);
+            System.exit(-1);
+        }
+
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/AnnotatedMethod.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/AnnotatedMethod.java
index ed03f68..3abf89a 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/AnnotatedMethod.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/AnnotatedMethod.java
@@ -1,156 +1,185 @@
+
 package edu.columbia.cs.psl.chroniclerj.struct;

 import java.util.LinkedList;

 import org.objectweb.asm.commons.Method;

+import edu.columbia.cs.psl.chroniclerj.Instrumenter;
+import edu.columbia.cs.psl.chroniclerj.visitor.NonDeterministicLoggingMethodVisitor;
+
 public class AnnotatedMethod {

-	/**
-	 * Encoded access flags for this method. private int access
-	 *
-	 * @see Method
-	 */
-	private int access;
-
-	/**
-	 * Fully qualified class name of the class owning this method. private
-	 * String clazz
-	 */
-	private String clazz;
-
-	public LinkedList<AnnotatedMethod> functionsThatCallMe = new LinkedList<AnnotatedMethod>();
-
-	public LinkedList<MethodExpression> functionsThatICall = new LinkedList<MethodExpression>();
-
-	private LinkedList<FieldExpression> putFieldInsns = new LinkedList<FieldExpression>();
-
-	/**
-	 * ASM method at the core of this MethodInstance object. private Method
-	 * method
-	 *
-	 * @see Method
-	 */
-	private Method method;
-
-	private boolean mutatesFieldsDirectly;
-	private boolean mutatesFields;
-	private boolean isFullyDiscovered;
-
-	public String getName()
-	{
-		return this.method.getName();
-	}
-
-	public String getDescriptor()
-	{
-		return this.method.getDescriptor();
-	}
-	public AnnotatedMethod(String fullName) {
-
-		String[] pieces = fullName.split("\\.|:");
-		this.clazz = pieces[0];
-		this.method = new Method(pieces[1], pieces[2]);
-	}
-
-	/**
-	 * Constructor for MethodInstance - accepts method name, method description,
-	 * class name, and access flag.
-	 *
-	 * @param name
-	 *            String name of method
-	 * @param desc
-	 *            String method descriptor
-	 * @param clazz
-	 *            String fully qualified class name
-	 * @param access
-	 *            int access flags in decimal
-	 */
-	public AnnotatedMethod(String name, String desc, String clazz, int access) {
-		this.method = new Method(name, desc);
-		this.clazz = clazz;
-		this.access = access;
-	}
-
-	/**
-	 * (Override) This function declares two MethodInstances A, B "equal" if and
-	 * only if: ((A.getMethod().equals(B.getMethod)) &&
-	 * (A.getClazz().equals(B.getClazz())) == true
-	 *
-	 * @see Object#equals(Object)
-	 * @see AnnotatedMethod#hashCode()
-	 */
-	@Override
-	public boolean equals(Object obj) {
-		if (obj.getClass().equals(this.getClass())) {
-			AnnotatedMethod other = (AnnotatedMethod) obj;
-			if ((other.getClazz().equals(this.getClazz()))
-					&& (other.getMethod().getName().equals(this.getMethod().getName()) && other.getMethod().getDescriptor().equals(this.getMethod().getDescriptor())))
-				return true;
-		}
-		return false;
-	}
-
-	public int getAccess() {
-		return access;
-	}
-
-	/**
-	 * Get the owner class name.
-	 *
-	 * @return String
-	 */
-	public String getClazz() {
-		return clazz;
-	}
-
-	public String getFullName() {
-		return this.clazz + "." + this.method.getName() + ":" + this.method.getDescriptor();
-	}
-
-	/**
-	 * Get the Method underlying this MethodInstance.
-	 *
-	 * @return Method
-	 */
-	public Method getMethod() {
-		return method;
-	}
-
-	@Override
-	public int hashCode() {
-		return this.getClazz().hashCode() * this.getMethod().getName().hashCode() * this.getMethod().getDescriptor().hashCode();
-	}
-
-	@Override
-	public String toString() {
-		return "MethodInstance [method=" + method + ", class=" + clazz + "]";
-	}
-
-	public LinkedList<FieldExpression> getPutFieldInsns() {
-		return putFieldInsns;
-	}
-	public boolean isMutatesFields() {
-		return mutatesFields;
-	}
-	public boolean isMutatesFieldsDirectly() {
-		return mutatesFieldsDirectly;
-	}
-	public void setMutatesFieldsDirectly() {
-		this.mutatesFieldsDirectly = true;
-	}
-	public void setMutatesFields() {
-		this.mutatesFields = true;
-	}
-
-	public void setAccess(int access) {
-		this.access = access;
-	}
-	public boolean isFullyDiscovered() {
-		return isFullyDiscovered;
-	}
-	public void setFullyDiscovered(boolean isFullyDiscovered) {
-		this.isFullyDiscovered = isFullyDiscovered;
-	}
+    /**
+     * Encoded access flags for this method. private int access
+     *
+     * @see Method
+     */
+    private int access;
+
+    /**
+     * Fully qualified class name of the class owning this method. private
+     * String clazz
+     */
+    private String clazz;
+
+    public LinkedList<AnnotatedMethod> functionsThatCallMe = new LinkedList<AnnotatedMethod>();
+
+    public LinkedList<MethodExpression> functionsThatICall = new LinkedList<MethodExpression>();
+
+    private LinkedList<FieldExpression> putFieldInsns = new LinkedList<FieldExpression>();
+
+    /**
+     * ASM method at the core of this MethodInstance object. private Method
+     * method
+     *
+     * @see Method
+     */
+    private Method method;
+
+    private boolean mutatesFieldsDirectly;
+
+    private boolean mutatesFields;
+
+    private boolean isFullyDiscovered;
+
+    public String getName() {
+        return this.method.getName();
+    }
+
+    public String getDescriptor() {
+        return this.method.getDescriptor();
+    }
+
+    public AnnotatedMethod(String fullName) {
+
+        String[] pieces = fullName.split("\\.|:");
+        this.clazz = pieces[0];
+        this.method = new Method(pieces[1], pieces[2]);
+    }
+
+    /**
+     * Constructor for MethodInstance - accepts method name, method description,
+     * class name, and access flag.
+     *
+     * @param name String name of method
+     * @param desc String method descriptor
+     * @param clazz String fully qualified class name
+     * @param access int access flags in decimal
+     */
+    public AnnotatedMethod(String name, String desc, String clazz, int access) {
+        this.method = new Method(name, desc);
+        this.clazz = clazz;
+        this.access = access;
+    }
+
+    /**
+     * (Override) This function declares two MethodInstances A, B "equal" if and
+     * only if: ((A.getMethod().equals(B.getMethod)) &&
+     * (A.getClazz().equals(B.getClazz())) == true
+     *
+     * @see Object#equals(Object)
+     * @see AnnotatedMethod#hashCode()
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj.getClass().equals(this.getClass())) {
+            AnnotatedMethod other = (AnnotatedMethod) obj;
+            if ((other.getClazz().equals(this.getClazz()))
+                    && (other.getMethod().getName().equals(this.getMethod().getName()) && other
+                            .getMethod().getDescriptor().equals(this.getMethod().getDescriptor())))
+                return true;
+        }
+        return false;
+    }
+
+    public int getAccess() {
+        return access;
+    }
+
+    /**
+     * Get the owner class name.
+     *
+     * @return String
+     */
+    public String getClazz() {
+        return clazz;
+    }
+
+    public String getFullName() {
+        return this.clazz + "." + this.method.getName() + ":" + this.method.getDescriptor();
+    }
+
+    /**
+     * Get the Method underlying this MethodInstance.
+     *
+     * @return Method
+     */
+    public Method getMethod() {
+        return method;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.getClazz().hashCode() * this.getMethod().getName().hashCode()
+                * this.getMethod().getDescriptor().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "MethodInstance [method=" + method + ", class=" + clazz + "]";
+    }
+
+    public LinkedList<FieldExpression> getPutFieldInsns() {
+        return putFieldInsns;
+    }
+
+    public boolean isMutatesFields() {
+        return mutatesFields;
+    }
+
+    public boolean isMutatesFieldsDirectly() {
+        return mutatesFieldsDirectly;
+    }
+
+    public void setMutatesFieldsDirectly() {
+        this.mutatesFieldsDirectly = true;
+    }
+
+    public void setMutatesFields() {
+        this.mutatesFields = true;
+    }
+
+    public void setAccess(int access) {
+        this.access = access;
+    }
+
+    public boolean isFullyDiscovered() {
+        return isFullyDiscovered;
+    }
+
+    public void setFullyDiscovered(boolean isFullyDiscovered) {
+        this.isFullyDiscovered = isFullyDiscovered;
+    }
+
+    private int callsNDMethods = -1;
+
+    public boolean isCallsNDMethods() {
+        if (callsNDMethods > -1)
+            return callsNDMethods == 1;
+        for (MethodExpression ex : functionsThatICall) {
+            AnnotatedMethod am = ex.getMethod();
+            if (am != null) {
+                if (NonDeterministicLoggingMethodVisitor.isND(am.getClazz(), am.getName(),
+                        am.getDescriptor())
+                        || am.isCallsNDMethods()) {
+                    callsNDMethods = 1;
+                    return true;
+                }
+            }
+        }
+        callsNDMethods = 0;
+        return false;
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/Expression.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/Expression.java
index 906592a..bc28263 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/Expression.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/Expression.java
@@ -1,34 +1,41 @@
-package edu.columbia.cs.psl.chroniclerj.struct;

+package edu.columbia.cs.psl.chroniclerj.struct;

 public abstract class Expression {
-	public abstract int getType();
-	public static int FIELD_TYPE = 1;
-	public static int METHOD_TYPE = 2;
-	public static int CONSTANT_TYPE = 3;
-	public Expression getParent()
-	{
-		return parent;
-	}
-	public void setParent(Expression ir){
-		this.parent = ir;
-	}
-	public Expression getRootParent()
-	{
-		if(getParent() == null)
-			return this;
-		else
-			return getParent().getRootParent();
-	}
-	private Expression parent;
-	public abstract int getStackElementsToSkip();
-	public abstract int getOpcode();
-
-	public String printParents() {
-		String r = "";
-		if (getParent() != null)
-			r += getParent().printParents() + ".";
-		r += toString();
-		return r;
-	}
+    public abstract int getType();
+
+    public static int FIELD_TYPE = 1;
+
+    public static int METHOD_TYPE = 2;
+
+    public static int CONSTANT_TYPE = 3;
+
+    public Expression getParent() {
+        return parent;
+    }
+
+    public void setParent(Expression ir) {
+        this.parent = ir;
+    }
+
+    public Expression getRootParent() {
+        if (getParent() == null)
+            return this;
+        else
+            return getParent().getRootParent();
+    }
+
+    private Expression parent;
+
+    public abstract int getStackElementsToSkip();
+
+    public abstract int getOpcode();
+
+    public String printParents() {
+        String r = "";
+        if (getParent() != null)
+            r += getParent().printParents() + ".";
+        r += toString();
+        return r;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/FieldExpression.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/FieldExpression.java
index 0f22255..e901df2 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/FieldExpression.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/FieldExpression.java
@@ -1,49 +1,57 @@
+
 package edu.columbia.cs.psl.chroniclerj.struct;

 import org.objectweb.asm.Opcodes;

 public class FieldExpression extends Expression {
-	private String name;
-	private String owner;
-	private String desc;
-	private int opcode;
-
-	public FieldExpression(String name, String owner, String desc, int opcode)
-	{
-		this.name = name;
-		this.owner = owner;
-		this.desc = desc;
-		this.opcode = opcode;
-	}
-	@Override
-	public int getOpcode() {
-		return opcode;
-	}
-	public String getName() {
-		return name;
-	}
-	public String getOwner() {
-		return owner;
-	}
-	public String getDesc() {
-		return desc;
-	}
-
-	@Override
-	public int getType() {
-		return FIELD_TYPE;
-	}
-
-	@Override
-	public int getStackElementsToSkip() {
-		if(opcode == Opcodes.GETFIELD || opcode == Opcodes.GETSTATIC)
-			return 0;
-		return 1;
-	}
-
-	@Override
-	public String toString() {
-//		return "FieldInvocation [name=" + name + ", owner=" + owner + ", desc=" + desc + "]";
-		return name;
-	}
+    private String name;
+
+    private String owner;
+
+    private String desc;
+
+    private int opcode;
+
+    public FieldExpression(String name, String owner, String desc, int opcode) {
+        this.name = name;
+        this.owner = owner;
+        this.desc = desc;
+        this.opcode = opcode;
+    }
+
+    @Override
+    public int getOpcode() {
+        return opcode;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getOwner() {
+        return owner;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    @Override
+    public int getType() {
+        return FIELD_TYPE;
+    }
+
+    @Override
+    public int getStackElementsToSkip() {
+        if (opcode == Opcodes.GETFIELD || opcode == Opcodes.GETSTATIC)
+            return 0;
+        return 1;
+    }
+
+    @Override
+    public String toString() {
+        // return "FieldInvocation [name=" + name + ", owner=" + owner +
+        // ", desc=" + desc + "]";
+        return name;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/MethodExpression.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/MethodExpression.java
index 8e661d8..0ad858c 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/MethodExpression.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/MethodExpression.java
@@ -1,71 +1,78 @@
+
 package edu.columbia.cs.psl.chroniclerj.struct;

 import java.util.Stack;

 public class MethodExpression extends Expression {
-	@Override
-	public String toString() {
-		String r ="";
-		if(method.getMethod().getName().equals("<init>"))
-			r+="new "+method.getClazz()+"(";
-		else
-			r += method.getMethod().getName()+"(";
-
-		for(int j = 0; j<params.size() - (method.getMethod().getName().equals("<init>") ? 2: 0); j++)
-		{
-			Expression i = params.get(j);
-			Expression parent = i.getParent();
-			String paramParent = "";
-			while(parent != null)
-			{
-				paramParent = parent.toString()+"."+paramParent;
-				parent = parent.getParent();
-			}
-			r+= paramParent;
-			r += i.toString();
-			if(j != params.size() - 1 - (method.getMethod().getName().equals("<init>") ? 2 : 0))
-				r += ",";
-		}
-		r+=")";
-		return r;
-
-	}
-	private Stack<Expression> params = new Stack<Expression>();
-
-	private AnnotatedMethod method;
-	private int opcode;
-	public MethodExpression(AnnotatedMethod method, int opcode)
-	{
-
-		this.method = method;
-		this.opcode = opcode;
-	}
-	@Override
-	public int getOpcode() {
-		return opcode;
-	}
-	@Override
-	public int getType() {
-		return METHOD_TYPE;
-	}
-	public Stack<Expression> getParams() {
-		return params;
-	}
-
-	public AnnotatedMethod getMethod() {
-		return method;
-	}
-	public int getNumParamsNeeded()
-	{
-		return (method.getMethod().getName().equals("<init>") ? 2 : 0) + method.getMethod().getArgumentTypes().length;
-	}
-
-	public boolean hasAllParameters() {
-		// TODO Auto-generated method stub
-		return getNumParamsNeeded() == params.size();
-	}
-	@Override
-	public int getStackElementsToSkip() {
-		return (method.getMethod().getName().equals("<init>") ? 1 : 0) + method.getMethod().getArgumentTypes().length;
-	}
-}
\ No newline at end of file
+    @Override
+    public String toString() {
+        String r = "";
+        if (method.getMethod().getName().equals("<init>"))
+            r += "new " + method.getClazz() + "(";
+        else
+            r += method.getMethod().getName() + "(";
+
+        for (int j = 0; j < params.size() - (method.getMethod().getName().equals("<init>") ? 2 : 0); j++) {
+            Expression i = params.get(j);
+            Expression parent = i.getParent();
+            String paramParent = "";
+            while (parent != null) {
+                paramParent = parent.toString() + "." + paramParent;
+                parent = parent.getParent();
+            }
+            r += paramParent;
+            r += i.toString();
+            if (j != params.size() - 1 - (method.getMethod().getName().equals("<init>") ? 2 : 0))
+                r += ",";
+        }
+        r += ")";
+        return r;
+
+    }
+
+    private Stack<Expression> params = new Stack<Expression>();
+
+    private AnnotatedMethod method;
+
+    private int opcode;
+
+    public MethodExpression(AnnotatedMethod method, int opcode) {
+
+        this.method = method;
+        this.opcode = opcode;
+    }
+
+    @Override
+    public int getOpcode() {
+        return opcode;
+    }
+
+    @Override
+    public int getType() {
+        return METHOD_TYPE;
+    }
+
+    public Stack<Expression> getParams() {
+        return params;
+    }
+
+    public AnnotatedMethod getMethod() {
+        return method;
+    }
+
+    public int getNumParamsNeeded() {
+        return (method.getMethod().getName().equals("<init>") ? 2 : 0)
+                + method.getMethod().getArgumentTypes().length;
+    }
+
+    public boolean hasAllParameters() {
+        // TODO Auto-generated method stub
+        return getNumParamsNeeded() == params.size();
+    }
+
+    @Override
+    public int getStackElementsToSkip() {
+        return (method.getMethod().getName().equals("<init>") ? 1 : 0)
+                + method.getMethod().getArgumentTypes().length;
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/SimpleExpression.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/SimpleExpression.java
index 981a7cd..1337325 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/SimpleExpression.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/struct/SimpleExpression.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.struct;

 import org.objectweb.asm.tree.AbstractInsnNode;
@@ -7,59 +8,59 @@ import org.objectweb.asm.tree.VarInsnNode;
 import org.objectweb.asm.util.Printer;

 public class SimpleExpression extends Expression {
-	private AbstractInsnNode insn;
+    private AbstractInsnNode insn;

-	@Override
-	public int getOpcode() {
-		return insn.getOpcode();
-	}
+    @Override
+    public int getOpcode() {
+        return insn.getOpcode();
+    }

-	public SimpleExpression(AbstractInsnNode insn) {
-		this.insn = insn;
-	}
+    public SimpleExpression(AbstractInsnNode insn) {
+        this.insn = insn;
+    }

-	public AbstractInsnNode getInsn() {
-		return insn;
-	}
+    public AbstractInsnNode getInsn() {
+        return insn;
+    }

-	@Override
-	public Expression getParent() {
-		// TODO Auto-generated method stub
-		return null;
-	}
+    @Override
+    public Expression getParent() {
+        // TODO Auto-generated method stub
+        return null;
+    }

-	@Override
-	public void setParent(Expression ir) {
+    @Override
+    public void setParent(Expression ir) {

-	}
+    }

-	@Override
-	public int getType() {
-		return CONSTANT_TYPE;
-	}
+    @Override
+    public int getType() {
+        return CONSTANT_TYPE;
+    }

-	@Override
-	public int getStackElementsToSkip() {
-		return 0;
-	}
+    @Override
+    public int getStackElementsToSkip() {
+        return 0;
+    }

-	public String getDesc() {
-		switch (insn.getType()) {
-		case AbstractInsnNode.TYPE_INSN:
-			return ((TypeInsnNode) insn).desc;
-		case AbstractInsnNode.VAR_INSN:
-			return "" + ((VarInsnNode) insn).var;
-		case AbstractInsnNode.LDC_INSN:
-			return ((LdcInsnNode) insn).cst.toString();
-		default:
-			return "";
-		}
+    public String getDesc() {
+        switch (insn.getType()) {
+            case AbstractInsnNode.TYPE_INSN:
+                return ((TypeInsnNode) insn).desc;
+            case AbstractInsnNode.VAR_INSN:
+                return "" + ((VarInsnNode) insn).var;
+            case AbstractInsnNode.LDC_INSN:
+                return ((LdcInsnNode) insn).cst.toString();
+            default:
+                return "";
+        }

-	}
+    }

-	@Override
-	public String toString() {
-		return "[" + Printer.OPCODES[getOpcode()] + " " + getDesc() + "]";
-	}
+    @Override
+    public String toString() {
+        return "[" + Printer.OPCODES[getOpcode()] + " " + getDesc() + "]";
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackDuplicatingClassVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackDuplicatingClassVisitor.java
new file mode 100644
index 0000000..4a1dc70
--- /dev/null
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackDuplicatingClassVisitor.java
@@ -0,0 +1,82 @@
+
+package edu.columbia.cs.psl.chroniclerj.visitor;
+
+import java.util.HashSet;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.LocalVariablesSorter;
+import org.objectweb.asm.tree.MethodNode;
+
+import edu.columbia.cs.psl.chroniclerj.MethodCall;
+
+/**
+ * If we identify a method as a callback method: Rename it. the renamed one will
+ * then not be logged. Create a new method with the original name, and the only
+ * instructions are to call the _chronicler_ version
+ *
+ * @author jon
+ */
+public class CallbackDuplicatingClassVisitor extends ClassVisitor {
+
+    private String className;
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName,
+            String[] interfaces) {
+        super.visit(version, access, name, signature, superName, interfaces);
+        this.className = name;
+    }
+
+    public CallbackDuplicatingClassVisitor(int api, ClassVisitor cv) {
+        super(api, cv);
+    }
+
+    private HashSet<MethodNode> methodsToGenerateLogging = new HashSet<MethodNode>();
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+        if (NonDeterministicLoggingClassVisitor.methodIsCallback(className, name, desc)) {
+            methodsToGenerateLogging.add(new MethodNode(access, name, desc, signature, exceptions));
+            return super.visitMethod(access, "_chronicler_" + name, desc, signature, exceptions);
+        }
+        return super.visitMethod(access, name, desc, signature, exceptions);
+    }
+
+    @Override
+    public void visitEnd() {
+        for (MethodNode mn : methodsToGenerateLogging) {
+            // mn.name = "BBB"+mn.name;
+            MethodVisitor mv = super.visitMethod(mn.access, mn.name, mn.desc, mn.signature,
+                    (String[]) mn.exceptions.toArray(new String[0]));
+            CloningAdviceAdapter caa = new CloningAdviceAdapter(Opcodes.ASM4, mv, mn.access,
+                    mn.name, mn.desc, className);
+            LocalVariablesSorter lvsorter = new LocalVariablesSorter(mn.access, mn.desc, mv);
+            CallbackLoggingMethodVisitor clmv = new CallbackLoggingMethodVisitor(api, mv,
+                    mn.access, mn.name, mn.desc, className, lvsorter, caa);
+            caa.setLocalVariableSorter(lvsorter);
+
+            if ((mn.access & Opcodes.ACC_STATIC) == 0) // not static
+                clmv.loadThis();
+
+            // load all of the arguments onto the stack again
+            Type[] args = Type.getArgumentTypes(mn.desc);
+
+            for (int i = 0; i < args.length; i++) {
+                clmv.loadArg(i);
+            }
+            clmv.visitMethodInsn((mn.access & Opcodes.ACC_STATIC) == 0 ? Opcodes.INVOKESPECIAL
+                    : Opcodes.INVOKESTATIC, className, "_chronicler_" + mn.name, mn.desc);
+            clmv.returnValue();
+            clmv.visitMaxs(0, 0);
+
+            clmv.visitEnd();
+        }
+        super.visitEnd();
+
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackLoggingMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackLoggingMethodVisitor.java
index 29695fe..41f16b5 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackLoggingMethodVisitor.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CallbackLoggingMethodVisitor.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.visitor;

 import org.objectweb.asm.MethodVisitor;
@@ -13,48 +14,58 @@ import edu.columbia.cs.psl.chroniclerj.Log;

 public class CallbackLoggingMethodVisitor extends AdviceAdapter implements Opcodes {

-	private String className;
-	private String methodName;
-	private String methodDesc;
-	private boolean isCallback;
-	private boolean isInit;
-	private CloningAdviceAdapter caa;
-
-	public CallbackLoggingMethodVisitor(int api, MethodVisitor mv, int access, String name, String desc, String classname, LocalVariablesSorter lvsorter, CloningAdviceAdapter caa) {
-		super(api, mv, access, name, desc);
-		this.className = classname;
-		this.methodName = name;
-		this.methodDesc = desc;
-		this.isInit = name.equals("<init>");
-		this.isCallback = NonDeterministicLoggingClassVisitor.methodIsCallback(classname, name, desc);
-		this.caa = caa;
-	}
-
-	@Override
-	protected void onMethodEnter() {
-		if (this.isInit) {
-			super.visitVarInsn(ALOAD, 0);
-			super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(CallbackRegistry.class), "register", "(Ljava/lang/Object;)V");
-		}
-	}
-
-	@Override
-	public void visitCode() {
-		super.visitCode();
-		if (this.isCallback) {
-			super.visitTypeInsn(NEW, Type.getInternalName(CallbackInvocation.class));
-			super.visitInsn(DUP);
-			super.visitLdcInsn(className);
-			super.visitLdcInsn(methodName);
-			super.visitLdcInsn(methodDesc);
-			super.loadArgArray();
-			super.loadThis();
-			super.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(CallbackInvocation.class), "<init>",
-					"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;Ljava/lang/Object;)V");
-			caa.logValueAtTopOfStackToArrayNoDup(Type.getInternalName(Log.class), "aLog", "[Ljava/lang/Object;", Type.getType(Object.class), true, "callback\t" + className + "." + methodName + methodDesc
-					+ "\t", false, true);
-//			super.visitInsn(POP);
-		}
-	}
+    private String className;
+
+    private String methodName;
+
+    private String methodDesc;
+
+    private boolean isCallback;
+
+    private boolean isInit;
+
+    private CloningAdviceAdapter caa;
+
+    public CallbackLoggingMethodVisitor(int api, MethodVisitor mv, int access, String name,
+            String desc, String classname, LocalVariablesSorter lvsorter, CloningAdviceAdapter caa) {
+        super(api, mv, access, name, desc);
+        this.className = classname;
+        this.methodName = name;
+        this.methodDesc = desc;
+        this.isInit = name.equals("<init>");
+        this.isCallback = NonDeterministicLoggingClassVisitor.methodIsCallback(classname, name,
+                desc);
+        this.caa = caa;
+    }
+
+    @Override
+    protected void onMethodEnter() {
+        if (this.isInit) {
+            super.visitVarInsn(ALOAD, 0);
+            super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(CallbackRegistry.class),
+                    "register", "(Ljava/lang/Object;)V");
+        }
+    }
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        if (this.isCallback) {
+            super.visitTypeInsn(NEW, Type.getInternalName(CallbackInvocation.class));
+            super.visitInsn(DUP);
+            super.visitLdcInsn(className);
+            super.visitLdcInsn(methodName);
+            super.visitLdcInsn(methodDesc);
+            super.loadArgArray();
+            super.loadThis();
+            super.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(CallbackInvocation.class),
+                    "<init>",
+                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;Ljava/lang/Object;)V");
+            caa.logValueAtTopOfStackToArrayNoDup(Type.getInternalName(Log.class), "aLog",
+                    "[Ljava/lang/Object;", Type.getType(Object.class), true, "callback\t"
+                            + className + "." + methodName + methodDesc + "\t", false, true);
+            // super.visitInsn(POP);
+        }
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CloningAdviceAdapter.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CloningAdviceAdapter.java
index 1226c4a..7ce3a44 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CloningAdviceAdapter.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/CloningAdviceAdapter.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.visitor;

 import java.util.HashSet;
@@ -14,367 +15,456 @@ import org.objectweb.asm.commons.Method;
 import edu.columbia.cs.psl.chroniclerj.ChroniclerJExportRunner;
 import edu.columbia.cs.psl.chroniclerj.CloningUtils;
 import edu.columbia.cs.psl.chroniclerj.Constants;
+import edu.columbia.cs.psl.chroniclerj.Instrumenter;
 import edu.columbia.cs.psl.chroniclerj.Log;
 import edu.columbia.cs.psl.chroniclerj.SerializableLog;

 public class CloningAdviceAdapter extends GeneratorAdapter implements Opcodes {

-	private static final HashSet<String> immutableClasses = new HashSet<String>();
-	static {
-		immutableClasses.add("Ljava/lang/Integer;");
-		immutableClasses.add("Ljava/lang/Long;");
-		immutableClasses.add("Ljava/lang/Short;");
-		immutableClasses.add("Ljava/lang/Float;");
-		immutableClasses.add("Ljava/lang/String;");
-		immutableClasses.add("Ljava/lang/Char;");
-		immutableClasses.add("Ljava/lang/Byte;");
-		immutableClasses.add("Ljava/lang/Integer;");
-		immutableClasses.add("Ljava/lang/Long;");
-		immutableClasses.add("Ljava/lang/Short;");
-		immutableClasses.add("Ljava/lang/Float;");
-		immutableClasses.add("Ljava/lang/String;");
-		immutableClasses.add("Ljava/lang/Char;");
-		immutableClasses.add("Ljava/lang/Byte;");
-		immutableClasses.add("Ljava/sql/ResultSet;");
-		immutableClasses.add("Ljava/lang/Class;");
-		immutableClasses.add("Z");
-		immutableClasses.add("B");
-		immutableClasses.add("C");
-		immutableClasses.add("S");
-		immutableClasses.add("I");
-		immutableClasses.add("J");
-		immutableClasses.add("F");
-		immutableClasses.add("L");
-
-	}
-
-	private LocalVariablesSorter lvsorter;
-
-	public CloningAdviceAdapter(int api, MethodVisitor mv, int access, String name, String desc, String classname) {
-		super(api, mv, access, name, desc);
-	}
-
-	/**
-	 * Precondition: Current element at the top of the stack is the element we
-	 * need cloned Post condition: Current element at the top of the stack is
-	 * the cloned element (and non-cloned is removed)
-	 */
-
-	protected void cloneValAtTopOfStack(String typeOfField) {
-		_generateClone(typeOfField, Constants.OUTER_COPY_METHOD_NAME, null, false);
-	}
-
-	protected void cloneValAtTopOfStack(String typeOfField, String debug, boolean secondElHasArrayLen) {
-		_generateClone(typeOfField, Constants.OUTER_COPY_METHOD_NAME, debug, secondElHasArrayLen);
-	}
-
-	protected void generateCloneInner(String typeOfField) {
-		_generateClone(typeOfField, Constants.INNER_COPY_METHOD_NAME, null, false);
-	}
-
-	public void println(String toPrint) {
-		visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
-		visitLdcInsn(toPrint + " : ");
-		super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
-
-		visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
-		super.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;");
-		super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getName", "()Ljava/lang/String;");
-		super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
-	}
-
-	private void _generateClone(String typeOfField, String copyMethodToCall, String debug, boolean secondElHasArrayLen) {
-		Type fieldType = Type.getType(typeOfField);
-
-		if (
-		// fieldType.getSort() == Type.ARRAY &&
-		// fieldType.getElementType().getSort()
-		// ||
-		fieldType.getSort() == Type.VOID || (fieldType.getSort() != Type.ARRAY && (fieldType.getSort() != Type.OBJECT || immutableClasses.contains(typeOfField)))) {
-//						 println("reference> " + debug);
-			return;
-		}
-		if (fieldType.getSort() == Type.ARRAY) {
-			if (fieldType.getElementType().getSort() != Type.OBJECT || immutableClasses.contains(fieldType.getElementType().getDescriptor())) {
-//								 println("array> " + debug);
-
-				// Just need to duplicate the array
-				dup();
-				Label nullContinue = new Label();
-				ifNull(nullContinue);
-				if (secondElHasArrayLen) {
-					swap();
-				} else {
-					dup();
-					visitInsn(ARRAYLENGTH);
-				}
-				dup();
-				newArray(Type.getType(fieldType.getDescriptor().substring(1)));
-				dupX2();
-				swap();
-				push(0);
-				dupX2();
-				swap();
-				super.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
-				Label noNeedToPop = new Label();
-				if (secondElHasArrayLen) {
-					visitJumpInsn(GOTO, noNeedToPop);
-					visitLabel(nullContinue);
-					swap();
-					pop();
-				} else {
-					visitLabel(nullContinue);
-				}
-
-				visitLabel(noNeedToPop);
-
-			} else {
-//				 println("heavy> " + debug);
-				// Just use the reflective cloner
-				visitLdcInsn(debug);
-				invokeStatic(Type.getType(CloningUtils.class), Method.getMethod("Object clone(Object, String)"));
-				checkCast(fieldType);
-			}
-		} else if (fieldType.getClassName().contains("InputStream") || fieldType.getClassName().contains("OutputStream") || fieldType.getClassName().contains("Socket")) {
-			// Do nothing
-		} else {
-//			 println("heavy> " + debug);
-			visitLdcInsn(debug);
-			invokeStatic(Type.getType(CloningUtils.class), Method.getMethod("Object clone(Object, String)"));
-			checkCast(fieldType);
-
-		}
-	}
-	protected void logValueAtTopOfStackToArray(String logFieldOwner, String logFieldName, String logFieldTypeDesc, Type elementType, boolean isStaticLoggingField, String debug,
-			boolean secondElHasArrayLen, boolean doLocking) {
-		if(secondElHasArrayLen)
-		{
-			dupX1();
-//			swap(); //data, size
-//			dupX1(); //size, data, size
-//			swap(); //size, size, data
-//			dupX2(); //size, data ,size, data
-		}
-		else
-		{
-		if(elementType.getSize() == 1)
-			dup(); //size?, data,size?,  data
-		else
-			dup2();
-		}
-		cloneValAtTopOfStack(elementType.getDescriptor(), debug, secondElHasArrayLen);
-		logValueAtTopOfStackToArrayNoDup(logFieldOwner, logFieldName, logFieldTypeDesc, elementType, isStaticLoggingField, debug, secondElHasArrayLen, doLocking);
-	}
-	protected void logValueAtTopOfStackToArrayNoDup(String logFieldOwner, String logFieldName, String logFieldTypeDesc, Type elementType, boolean isStaticLoggingField, String debug,
-			boolean secondElHasArrayLen, boolean doLocking) {
-		int getOpcode = (isStaticLoggingField ? Opcodes.GETSTATIC : Opcodes.GETFIELD);
-		int putOpcode = (isStaticLoggingField ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD);
-
-		//Lock
-		if (doLocking) {
-			super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock", Type.getDescriptor(Lock.class));
-			super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "lock", "()V");
-		}
-		// Grow the array if necessary
-
-		super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-		super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-		super.arrayLength();
-		Label labelForNoNeedToGrow = new Label();
-		super.ifCmp(Type.INT_TYPE, Opcodes.IFNE, labelForNoNeedToGrow);
-		// In this case, it's necessary to grow it
-		// Create the new array and initialize its size
-
-		int newArray = lvsorter.newLocal(Type.getType(logFieldTypeDesc));
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-		arrayLength();
-		visitInsn(Opcodes.I2D);
-		visitLdcInsn(Constants.LOG_GROWTH_RATE);
-		visitInsn(Opcodes.DMUL);
-		visitInsn(Opcodes.D2I);
-
-		newArray(Type.getType(logFieldTypeDesc.substring(1))); // Bug in
-																// ASM
-																// prevents
-																// us
-																// from
-																// doing
-																// type.getElementType
-		storeLocal(newArray, Type.getType(logFieldTypeDesc));
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-		visitInsn(Opcodes.ICONST_0);
-		loadLocal(newArray);
-		visitInsn(Opcodes.ICONST_0);
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-		arrayLength();
-		visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
-
-		// array = newarray
-
-		loadLocal(newArray);
-		visitFieldInsn(putOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-
-		int newArray2 = lvsorter.newLocal(Type.getType("[Ljava/lang/String;"));
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
-		arrayLength();
-		visitInsn(Opcodes.I2D);
-		visitLdcInsn(Constants.LOG_GROWTH_RATE);
-		visitInsn(Opcodes.DMUL);
-		visitInsn(Opcodes.D2I);
-
-		newArray(Type.getType("Ljava/lang/String;"));
-
-		storeLocal(newArray2, Type.getType("[Ljava/lang/String;"));
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
-		visitInsn(Opcodes.ICONST_0);
-		loadLocal(newArray2);
-		visitInsn(Opcodes.ICONST_0);
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
-		arrayLength();
-		visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
-
-		// array = newarray
-
-		loadLocal(newArray2);
-		visitFieldInsn(putOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
-
-		visitLabel(labelForNoNeedToGrow);
-		// Load this into the end piece of the array
-		if (elementType.getSize() == 1) {
-//			if (secondElHasArrayLen) {
-//				/*
-//				 * size buf
-//				 */
-//				dupX1();
-//				/*
-//				 * buf size buf
-//				 */
-//				visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-//				dupX2();
-//				pop();
-//				/*
-//				 * buf logfield size buf
-//				 */
-//				visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-//				dupX2();
-//				pop();
-//				/*
-//				 * buf logfield logsize size buf
-//				 */
-//			} else {
-//				dup();
-				visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-				swap();
-				visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-				swap();
-//			}
-		} else if (elementType.getSize() == 2) {
-//			dup2();
-			if (!isStaticLoggingField)
-				super.loadThis();
-			super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
-			dupX2();
-			pop();
-			if (!isStaticLoggingField)
-				super.loadThis();
-			super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-			dupX2();
-			pop();
-		}
-
-		arrayStore(elementType);
-
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-
-		if (debug.startsWith("callback"))
-			visitLdcInsn("callback-handler");
-		else {
-			visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;");
-			visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getName", "()Ljava/lang/String;");
-		}
-		arrayStore(Type.getType(String.class));
-		visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-
-		super.visitInsn(Opcodes.ICONST_1);
-		super.visitInsn(Opcodes.IADD);
-		super.visitFieldInsn(putOpcode, logFieldOwner, logFieldName + "_fill", Type.INT_TYPE.getDescriptor());
-		// println("Incremented fill for " + logFieldOwner+"."+logFieldName);
-		// Release the export lock
-		// super.visitFieldInsn(GETSTATIC,
-		// Type.getInternalName(CloningUtils.class), "exportLock",
-		// Type.getDescriptor(ReadWriteLock.class));
-		// super.visitMethodInsn(INVOKEINTERFACE,
-		// Type.getInternalName(ReadWriteLock.class), "readLock",
-		// "()Ljava/util/concurrent/locks/Lock;");
-		// super.visitMethodInsn(INVOKEINTERFACE,
-		// Type.getInternalName(Lock.class), "unlock", "()V");
-
-		// if (threadSafe) {
-		// Unlock
-		// super.visitVarInsn(ALOAD, monitorIndx);
-		// super.monitorExit();
-		// visitLabel(monitorEndLabel);
-		Label endLbl = new Label();
-
-		//		if (elementType.getSort() == Type.ARRAY) {
-		//			super.visitInsn(DUP);
-		//			super.visitInsn(ARRAYLENGTH);
-		//		} else
-		super.visitInsn(ICONST_1);
-		// super.visitVarInsn(ALOAD, monitorIndx);
-		// super.monitorEnter();
-		super.visitFieldInsn(getOpcode, logFieldOwner, "logsize", Type.INT_TYPE.getDescriptor());
-		super.visitInsn(IADD);
-		super.visitInsn(DUP);
-		super.visitFieldInsn(PUTSTATIC, logFieldOwner, "logsize", Type.INT_TYPE.getDescriptor());
-
-		super.visitLdcInsn(Constants.MAX_LOG_SIZE);
-		// super.visitInsn(ISUB);
-		super.visitJumpInsn(IF_ICMPLE, endLbl);
-		// super.ifCmp(Type.INT_TYPE, Opcodes.IFGE, endLbl);
-		// super.visitVarInsn(ALOAD, monitorIndx);
-		// super.monitorExit();
-		if (logFieldOwner.equals(Type.getInternalName(SerializableLog.class)))
-			super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ChroniclerJExportRunner.class), "_exportSerializable", "()V");
-		else
-			super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(ChroniclerJExportRunner.class), "_export", "()V");
-		// super.visitVarInsn(ALOAD, monitorIndx);
-		// super.monitorEnter();
-		//		super.visitFieldInsn(getOpcode, logFieldOwner, "logsize", Type.INT_TYPE.getDescriptor());
-		//		super.visitLdcInsn(Constants.VERY_MAX_LOG_SIZE);
-		//		super.visitJumpInsn(IF_ICMPLE, endLbl);
-
-		// println("GOing to wait for " + logFieldOwner);
-		// super.visitLabel(tryStart);
-
-		//		super.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(Log.class), "lock", "Ljava/lang/Object;");
-		//		super.visitLdcInsn(500L);
-		//		super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "wait", "(J)V");
-
-		// super.visitLabel(tryEnd);
-
-		// super.visitJumpInsn(GOTO, endLbl);
-		// super.visitLabel(handlerStart);
-		// int n = newLocal(Type.getType(InterruptedException.class));
-		// super.visitVarInsn(ASTORE, n);
-		// super.visitInsn(POP);
-		visitLabel(endLbl);
-		//		super.visitVarInsn(ALOAD, monitorIndx);
-		//		super.monitorExit();
-		if (doLocking) {
-			super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock", Type.getDescriptor(Lock.class));
-			super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "unlock", "()V");
-		}
-		// super.visitLocalVariable(logFieldName + "_monitor",
-		// "Ljava/lang/Object;", null, monitorStart, monitorEndLabel,
-		// monitorIndx);
-		// }
-
-	}
-
-	public void setLocalVariableSorter(LocalVariablesSorter smv) {
-		this.lvsorter = smv;
-	}
+    private static final HashSet<String> immutableClasses = new HashSet<String>();
+
+    private static final HashSet<String> nullInsteads = new HashSet<>();
+    static {
+        immutableClasses.add("Ljava/lang/Integer;");
+        immutableClasses.add("Ljava/lang/Long;");
+        immutableClasses.add("Ljava/lang/Short;");
+        immutableClasses.add("Ljava/lang/Float;");
+        immutableClasses.add("Ljava/lang/String;");
+        immutableClasses.add("Ljava/lang/Char;");
+        immutableClasses.add("Ljava/lang/Byte;");
+        immutableClasses.add("Ljava/lang/Integer;");
+        immutableClasses.add("Ljava/lang/Long;");
+        immutableClasses.add("Ljava/lang/Short;");
+        immutableClasses.add("Ljava/lang/Float;");
+        immutableClasses.add("Ljava/lang/String;");
+        immutableClasses.add("Ljava/lang/Char;");
+        immutableClasses.add("Ljava/lang/Byte;");
+        immutableClasses.add("Ljava/sql/ResultSet;");
+        immutableClasses.add("Ljava/lang/Class;");
+        immutableClasses.add("Ljava/net/InetAddress;");
+        immutableClasses.add("Ljava/util/TimeZone;");
+        immutableClasses.add("Ljava/util/zip/ZipEntry;");
+        immutableClasses.add("Z");
+        immutableClasses.add("B");
+        immutableClasses.add("C");
+        immutableClasses.add("S");
+        immutableClasses.add("I");
+        immutableClasses.add("J");
+        immutableClasses.add("F");
+        immutableClasses.add("L");
+        for (Class<?> cz : CloningUtils.moreIgnoredImmutables) {
+            immutableClasses.add(Type.getDescriptor(cz));
+        }
+
+        for (Class<?> cz : CloningUtils.nullInsteads) {
+            nullInsteads.add(Type.getDescriptor(cz));
+        }
+    }
+
+    private LocalVariablesSorter lvsorter;
+
+    public CloningAdviceAdapter(int api, MethodVisitor mv, int access, String name, String desc,
+            String classname) {
+        super(api, mv, access, name, desc);
+    }
+
+    /**
+     * Precondition: Current element at the top of the stack is the element we
+     * need cloned Post condition: Current element at the top of the stack is
+     * the cloned element (and non-cloned is removed)
+     */
+
+    protected void cloneValAtTopOfStack(String typeOfField) {
+        _generateClone(typeOfField, Constants.OUTER_COPY_METHOD_NAME, null, false);
+    }
+
+    protected void cloneValAtTopOfStack(String typeOfField, String debug,
+            boolean secondElHasArrayLen) {
+        _generateClone(typeOfField, Constants.OUTER_COPY_METHOD_NAME, debug, secondElHasArrayLen);
+    }
+
+    protected void generateCloneInner(String typeOfField) {
+        _generateClone(typeOfField, Constants.INNER_COPY_METHOD_NAME, null, false);
+    }
+
+    public void println(String toPrint) {
+        visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+        visitLdcInsn(toPrint + " : ");
+        super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print",
+                "(Ljava/lang/String;)V");
+
+        visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+        super.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread",
+                "()Ljava/lang/Thread;");
+        super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getName", "()Ljava/lang/String;");
+        super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
+                "(Ljava/lang/String;)V");
+    }
+
+    private void _generateClone(String typeOfField, String copyMethodToCall, String debug,
+            boolean secondElHasArrayLen) {
+        Type fieldType = Type.getType(typeOfField);
+
+        if (
+        // fieldType.getSort() == Type.ARRAY &&
+        // fieldType.getElementType().getSort()
+        // ||
+        fieldType.getSort() == Type.VOID
+                || (fieldType.getSort() != Type.ARRAY && (fieldType.getSort() != Type.OBJECT || isImmutable(typeOfField)))) {
+            // println("reference> " + debug);
+            return;
+        } else if (isSetNull(typeOfField)) {
+            pop();
+            visitInsn(ACONST_NULL);
+        }
+        if (fieldType.getSort() == Type.ARRAY) {
+            if (fieldType.getElementType().getSort() != Type.OBJECT
+                    || immutableClasses.contains(fieldType.getElementType().getDescriptor())) {
+                // println("array> " + debug);
+
+                // Just need to duplicate the array
+                dup();
+                Label nullContinue = new Label();
+                ifNull(nullContinue);
+                if (secondElHasArrayLen) {
+                    swap();
+                } else {
+                    dup();
+                    visitInsn(ARRAYLENGTH);
+                }
+                dup();
+                newArray(Type.getType(fieldType.getDescriptor().substring(1)));
+                dupX2();
+                swap();
+                push(0);
+                dupX2();
+                swap();
+                super.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy",
+                        "(Ljava/lang/Object;ILjava/lang/Object;II)V");
+                Label noNeedToPop = new Label();
+                if (secondElHasArrayLen) {
+                    visitJumpInsn(GOTO, noNeedToPop);
+                    visitLabel(nullContinue);
+                    swap();
+                    pop();
+                } else {
+                    visitLabel(nullContinue);
+                }
+
+                visitLabel(noNeedToPop);
+
+            } else {
+                // println("heavy> " + debug);
+                // Just use the reflective cloner
+                visitLdcInsn(debug);
+                invokeStatic(Type.getType(CloningUtils.class),
+                        Method.getMethod("Object clone(Object, String)"));
+                checkCast(fieldType);
+            }
+        } else if (fieldType.getClassName().contains("InputStream")
+                || fieldType.getClassName().contains("OutputStream")
+                || fieldType.getClassName().contains("Socket")) {
+            // Do nothing
+        } else {
+            // println("heavy> " + debug);
+            visitLdcInsn(debug);
+            invokeStatic(Type.getType(CloningUtils.class),
+                    Method.getMethod("Object clone(Object, String)"));
+            checkCast(fieldType);
+
+        }
+    }
+
+    private boolean isImmutable(String desc) {
+        if (immutableClasses.contains(desc))
+            return true;
+        final String parent = Instrumenter.getParentType(desc);
+        if (parent == null)
+            return false;
+        return isImmutable(parent);
+    }
+
+    private boolean isSetNull(String desc) {
+        if (nullInsteads.contains(desc))
+            return true;
+        final String parent = Instrumenter.getParentType(desc);
+        if (parent == null)
+            return false;
+        return isSetNull(parent);
+    }
+
+    protected void logValueAtTopOfStackToArray(String logFieldOwner, String logFieldName,
+            String logFieldTypeDesc, Type elementType, boolean isStaticLoggingField, String debug,
+            boolean secondElHasArrayLen, boolean doLocking) {
+        if (secondElHasArrayLen) {
+            dupX1();
+            // swap(); //data, size
+            // dupX1(); //size, data, size
+            // swap(); //size, size, data
+            // dupX2(); //size, data ,size, data
+        } else {
+            if (elementType.getSize() == 1)
+                dup(); // size?, data,size?, data
+            else
+                dup2();
+        }
+        cloneValAtTopOfStack(elementType.getDescriptor(), debug, secondElHasArrayLen);
+        logValueAtTopOfStackToArrayNoDup(logFieldOwner, logFieldName, logFieldTypeDesc,
+                elementType, isStaticLoggingField, debug, secondElHasArrayLen, doLocking);
+    }
+
+    protected void logValueAtTopOfStackToArrayNoDup(String logFieldOwner, String logFieldName,
+            String logFieldTypeDesc, Type elementType, boolean isStaticLoggingField, String debug,
+            boolean secondElHasArrayLen, boolean doLocking) {
+        int getOpcode = (isStaticLoggingField ? Opcodes.GETSTATIC : Opcodes.GETFIELD);
+        int putOpcode = (isStaticLoggingField ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD);
+
+        // Lock
+        if (doLocking) {
+            super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock",
+                    Type.getDescriptor(Lock.class));
+            super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "lock", "()V");
+        }
+        // Grow the array if necessary
+
+        super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill",
+                Type.INT_TYPE.getDescriptor());
+        super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+        super.arrayLength();
+        Label labelForNoNeedToGrow = new Label();
+        super.ifCmp(Type.INT_TYPE, Opcodes.IFNE, labelForNoNeedToGrow);
+        // In this case, it's necessary to grow it
+        // Create the new array and initialize its size
+
+        int newArray = lvsorter.newLocal(Type.getType(logFieldTypeDesc));
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+        arrayLength();
+        visitInsn(Opcodes.I2D);
+        visitLdcInsn(Constants.LOG_GROWTH_RATE);
+        visitInsn(Opcodes.DMUL);
+        visitInsn(Opcodes.D2I);
+
+        newArray(Type.getType(logFieldTypeDesc.substring(1))); // Bug in
+                                                               // ASM
+                                                               // prevents
+                                                               // us
+                                                               // from
+                                                               // doing
+                                                               // type.getElementType
+        storeLocal(newArray, Type.getType(logFieldTypeDesc));
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+        visitInsn(Opcodes.ICONST_0);
+        loadLocal(newArray);
+        visitInsn(Opcodes.ICONST_0);
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+        arrayLength();
+        visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy",
+                "(Ljava/lang/Object;ILjava/lang/Object;II)V");
+
+        // array = newarray
+
+        loadLocal(newArray);
+        visitFieldInsn(putOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+
+        int newArray2 = lvsorter.newLocal(Type.getType("[Ljava/lang/String;"));
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
+        arrayLength();
+        visitInsn(Opcodes.I2D);
+        visitLdcInsn(Constants.LOG_GROWTH_RATE);
+        visitInsn(Opcodes.DMUL);
+        visitInsn(Opcodes.D2I);
+
+        newArray(Type.getType("Ljava/lang/String;"));
+
+        storeLocal(newArray2, Type.getType("[Ljava/lang/String;"));
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
+        visitInsn(Opcodes.ICONST_0);
+        loadLocal(newArray2);
+        visitInsn(Opcodes.ICONST_0);
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
+        arrayLength();
+        visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy",
+                "(Ljava/lang/Object;ILjava/lang/Object;II)V");
+
+        // array = newarray
+
+        loadLocal(newArray2);
+        visitFieldInsn(putOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
+
+        visitLabel(labelForNoNeedToGrow);
+        // Load this into the end piece of the array
+        if (elementType.getSize() == 1) {
+            // if (secondElHasArrayLen) {
+            // /*
+            // * size buf
+            // */
+            // dupX1();
+            // /*
+            // * buf size buf
+            // */
+            // visitFieldInsn(getOpcode, logFieldOwner, logFieldName,
+            // logFieldTypeDesc);
+            // dupX2();
+            // pop();
+            // /*
+            // * buf logfield size buf
+            // */
+            // visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill",
+            // Type.INT_TYPE.getDescriptor());
+            // dupX2();
+            // pop();
+            // /*
+            // * buf logfield logsize size buf
+            // */
+            // } else {
+            // dup();
+            visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+            swap();
+            visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill",
+                    Type.INT_TYPE.getDescriptor());
+            swap();
+            // }
+        } else if (elementType.getSize() == 2) {
+            // dup2();
+            if (!isStaticLoggingField)
+                super.loadThis();
+            super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName, logFieldTypeDesc);
+            dupX2();
+            pop();
+            if (!isStaticLoggingField)
+                super.loadThis();
+            super.visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill",
+                    Type.INT_TYPE.getDescriptor());
+            dupX2();
+            pop();
+        }
+
+        arrayStore(elementType);
+
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_owners", "[Ljava/lang/String;");
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill",
+                Type.INT_TYPE.getDescriptor());
+
+        if (debug.startsWith("callback"))
+            visitLdcInsn("callback-handler");
+        else {
+            visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread",
+                    "()Ljava/lang/Thread;");
+            visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getName", "()Ljava/lang/String;");
+
+            visitInsn(DUP);
+            visitLdcInsn("Finalizer");
+            visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
+            Label contin = new Label();
+            visitJumpInsn(IFEQ, contin);
+            // we are in finalize thread
+            visitInsn(POP);
+            visitTypeInsn(NEW, "java/lang/StringBuilder");
+            visitInsn(DUP);
+            visitLdcInsn("Finalizer");
+            visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>",
+                    "(Ljava/lang/String;)V");
+            visitFieldInsn(Opcodes.GETSTATIC, "edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils",
+                    "curFinalizer", "J");
+            visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
+                    "(J)Ljava/lang/StringBuilder;");
+            visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString",
+                    "()Ljava/lang/String;");
+            visitLabel(contin);
+
+        }
+        arrayStore(Type.getType(String.class));
+        visitFieldInsn(getOpcode, logFieldOwner, logFieldName + "_fill",
+                Type.INT_TYPE.getDescriptor());
+
+        super.visitInsn(Opcodes.ICONST_1);
+        super.visitInsn(Opcodes.IADD);
+        super.visitFieldInsn(putOpcode, logFieldOwner, logFieldName + "_fill",
+                Type.INT_TYPE.getDescriptor());
+        // println("Incremented fill for " + logFieldOwner+"."+logFieldName);
+        // Release the export lock
+        // super.visitFieldInsn(GETSTATIC,
+        // Type.getInternalName(CloningUtils.class), "exportLock",
+        // Type.getDescriptor(ReadWriteLock.class));
+        // super.visitMethodInsn(INVOKEINTERFACE,
+        // Type.getInternalName(ReadWriteLock.class), "readLock",
+        // "()Ljava/util/concurrent/locks/Lock;");
+        // super.visitMethodInsn(INVOKEINTERFACE,
+        // Type.getInternalName(Lock.class), "unlock", "()V");
+
+        // if (threadSafe) {
+        // Unlock
+        // super.visitVarInsn(ALOAD, monitorIndx);
+        // super.monitorExit();
+        // visitLabel(monitorEndLabel);
+        Label endLbl = new Label();
+
+        // if (elementType.getSort() == Type.ARRAY) {
+        // super.visitInsn(DUP);
+        // super.visitInsn(ARRAYLENGTH);
+        // } else
+        super.visitInsn(ICONST_1);
+        // super.visitVarInsn(ALOAD, monitorIndx);
+        // super.monitorEnter();
+        super.visitFieldInsn(getOpcode, logFieldOwner, "logsize", Type.INT_TYPE.getDescriptor());
+        super.visitInsn(IADD);
+        super.visitInsn(DUP);
+        super.visitFieldInsn(PUTSTATIC, logFieldOwner, "logsize", Type.INT_TYPE.getDescriptor());
+
+        super.visitLdcInsn(Constants.MAX_LOG_SIZE);
+        // super.visitInsn(ISUB);
+        super.visitJumpInsn(IF_ICMPLE, endLbl);
+        // super.ifCmp(Type.INT_TYPE, Opcodes.IFGE, endLbl);
+        // super.visitVarInsn(ALOAD, monitorIndx);
+        // super.monitorExit();
+        if (logFieldOwner.equals(Type.getInternalName(SerializableLog.class)))
+            super.visitMethodInsn(INVOKESTATIC,
+                    Type.getInternalName(ChroniclerJExportRunner.class), "_exportSerializable",
+                    "()V");
+        else
+            super.visitMethodInsn(INVOKESTATIC,
+                    Type.getInternalName(ChroniclerJExportRunner.class), "_export", "()V");
+        // super.visitVarInsn(ALOAD, monitorIndx);
+        // super.monitorEnter();
+        // super.visitFieldInsn(getOpcode, logFieldOwner, "logsize",
+        // Type.INT_TYPE.getDescriptor());
+        // super.visitLdcInsn(Constants.VERY_MAX_LOG_SIZE);
+        // super.visitJumpInsn(IF_ICMPLE, endLbl);
+
+        // println("GOing to wait for " + logFieldOwner);
+        // super.visitLabel(tryStart);
+
+        // super.visitFieldInsn(Opcodes.GETSTATIC,
+        // Type.getInternalName(Log.class), "lock", "Ljava/lang/Object;");
+        // super.visitLdcInsn(500L);
+        // super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "wait",
+        // "(J)V");
+
+        // super.visitLabel(tryEnd);
+
+        // super.visitJumpInsn(GOTO, endLbl);
+        // super.visitLabel(handlerStart);
+        // int n = newLocal(Type.getType(InterruptedException.class));
+        // super.visitVarInsn(ASTORE, n);
+        // super.visitInsn(POP);
+        visitLabel(endLbl);
+        // super.visitVarInsn(ALOAD, monitorIndx);
+        // super.monitorExit();
+        if (doLocking) {
+            super.visitFieldInsn(GETSTATIC, Type.getInternalName(Log.class), "logLock",
+                    Type.getDescriptor(Lock.class));
+            super.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Lock.class), "unlock",
+                    "()V");
+        }
+        // super.visitLocalVariable(logFieldName + "_monitor",
+        // "Ljava/lang/Object;", null, monitorStart, monitorEndLabel,
+        // monitorIndx);
+        // }
+
+    }
+
+    public void setLocalVariableSorter(LocalVariablesSorter smv) {
+        this.lvsorter = smv;
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/FinalizerLoggingMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/FinalizerLoggingMethodVisitor.java
new file mode 100644
index 0000000..3a3569a
--- /dev/null
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/FinalizerLoggingMethodVisitor.java
@@ -0,0 +1,34 @@
+
+package edu.columbia.cs.psl.chroniclerj.visitor;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import edu.columbia.cs.psl.chroniclerj.Instrumenter;
+
+public class FinalizerLoggingMethodVisitor extends MethodVisitor {
+
+    private boolean isFinalize;
+
+    private String className;
+
+    public FinalizerLoggingMethodVisitor(int api, MethodVisitor mv, String name, String desc,
+            String className) {
+        super(api, mv);
+        this.isFinalize = (name.equals("finalize")) && desc.equals("()V");
+        this.className = className;
+    }
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        if (this.isFinalize) {
+            // Log to the log our finalizer #
+            visitVarInsn(Opcodes.ALOAD, 0);
+            visitFieldInsn(Opcodes.GETFIELD, this.className, Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+            visitFieldInsn(Opcodes.PUTSTATIC, "edu/columbia/cs/psl/chroniclerj/replay/ReplayUtils",
+                    "curFinalizer", "J");
+        }
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/MainLoggingMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/MainLoggingMethodVisitor.java
index 7def601..b785d72 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/MainLoggingMethodVisitor.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/MainLoggingMethodVisitor.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.visitor;

 import org.objectweb.asm.MethodVisitor;
@@ -9,17 +10,20 @@ import edu.columbia.cs.psl.chroniclerj.ChroniclerJExportRunner;

 public class MainLoggingMethodVisitor extends AdviceAdapter {

-	private String className;
-	protected MainLoggingMethodVisitor(int api, MethodVisitor mv, int access, String name, String desc,String className) {
-		super(api, mv, access, name, desc);
-		this.className = className;
-	}
+    private String className;
+
+    protected MainLoggingMethodVisitor(int api, MethodVisitor mv, int access, String name,
+            String desc, String className) {
+        super(api, mv, access, name, desc);
+        this.className = className;
+    }

-	@Override
-	protected void onMethodEnter() {
-		super.onMethodEnter();
-		visitLdcInsn(this.className);
-		loadArg(0);
-		super.invokeStatic(Type.getType(ChroniclerJExportRunner.class), Method.getMethod("void logMain(String, String[])"));
-	}
+    @Override
+    protected void onMethodEnter() {
+        super.onMethodEnter();
+        visitLdcInsn(this.className);
+        loadArg(0);
+        super.invokeStatic(Type.getType(ChroniclerJExportRunner.class),
+                Method.getMethod("void logMain(String, String[])"));
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingClassVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingClassVisitor.java
index 1c4c220..480d70c 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingClassVisitor.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingClassVisitor.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.visitor;

 import java.io.File;
@@ -17,6 +18,7 @@ import org.objectweb.asm.commons.AnalyzerAdapter;
 import org.objectweb.asm.commons.JSRInlinerAdapter;
 import org.objectweb.asm.commons.LocalVariablesSorter;
 import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
 import org.objectweb.asm.tree.MethodInsnNode;

 import edu.columbia.cs.psl.chroniclerj.Constants;
@@ -25,250 +27,259 @@ import edu.columbia.cs.psl.chroniclerj.MethodCall;

 public class NonDeterministicLoggingClassVisitor extends ClassVisitor implements Opcodes {

-	private String className;
-	private boolean isAClass = true;
-
-	public static HashSet<String> callbackClasses = new HashSet<String>();
-	public static HashSet<String> callbackMethods = new HashSet<String>();
-	static
-	{
-		Scanner s;
-		try {
-			s = new Scanner(NonDeterministicLoggingClassVisitor.class.getClassLoader().getResourceAsStream("listenerMethods.txt"));
-			while (s.hasNextLine())
-			{
-				String l = s.nextLine();
-				callbackMethods.add(l);
-				callbackClasses.add(l.substring(0,l.indexOf(".")));
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-	public NonDeterministicLoggingClassVisitor(int api, ClassVisitor cv) {
-		super(api, cv);
-
-	}
-
-	private static Logger logger = Logger.getLogger(NonDeterministicLoggingClassVisitor.class);
-
-	@Override
-	public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
-		super.visit(version, access, name, signature, superName, interfaces);
-		this.className = name;
-
-		logger.debug("Visiting " + name + " for instrumentation");
-		if ((access & Opcodes.ACC_INTERFACE) != 0)
-			isAClass = false;
-	}
-
-	private boolean isFirstConstructor = true;
-
-	private boolean classIsCallback(String className)
-	{
-		if(callbackClasses.contains(className))
-			return true;
-		if(className.equals("java/lang/Object"))
-			return false;
-		if(!Instrumenter.instrumentedClasses.containsKey(className))
-		{
-			try{
-				Class<?> c = Instrumenter.loader.loadClass(className.replace("/", "."));
-				for(Class<?> i : c.getInterfaces())
-				{
-					if(callbackClasses.contains(Type.getInternalName(i)))
-							return true;
-				}
-				Class<?> superClass = c.getSuperclass();
-				if(superClass == null)
-					return false;
-				return classIsCallback(Type.getInternalName(superClass));
-			}
-			catch(ClassNotFoundException ex)
-			{
-				return false;
-			}
-		}
-		ClassNode cn = Instrumenter.instrumentedClasses.get(className);
-		for(Object s : cn.interfaces)
-		{
-			if(callbackClasses.contains(((String)s)))
-				return true;
-		}
-		if(cn.superName.equals(cn.name) || cn.superName.equals("java/lang/Object") || cn.name.equals("org/eclipse/jdt/core/compiler/BuildContext"))
-			return false;
-		else
-			return classIsCallback(cn.superName);
-	}
-	public static boolean methodIsCallback(String className, String name, String desc)
-	{
-
-		String key = "."+name +":"+desc;
-		if(callbackMethods.contains(className + key))
-			return true;
-		if(!Instrumenter.instrumentedClasses.containsKey(className))
-		{
-			try{
-				Class<?> c = Instrumenter.loader.loadClass(className.replace("/", "."));
-				for(Class<?> i : c.getInterfaces())
-				{
-					if(callbackMethods.contains(Type.getInternalName(i) + key))
-							return true;
-				}
-				Class<?> superClass = c.getSuperclass();
-				if(superClass == null)
-					return false;
-				return methodIsCallback(Type.getInternalName(superClass),name, desc);
-			}
-			catch(ClassNotFoundException ex)
-			{
-				return false;
-			}
-		}
-		ClassNode cn = Instrumenter.instrumentedClasses.get(className);
-		for(Object s : cn.interfaces)
-		{
-			if(callbackMethods.contains(((String)s) + key))
-				return true;
-		}
-		return methodIsCallback(cn.superName, name, desc);
-	}
-	@Override
-	public MethodVisitor visitMethod(int acc, String name, String desc, String signature, String[] exceptions) {
-		// TODO need an annotation to disable doing this to some apps
-		MethodVisitor primaryMV = cv.visitMethod(acc, name, desc, signature, exceptions);
-		MethodVisitor smv = primaryMV;
-		if(name.equals("main") && desc.equals("([Ljava/lang/String;)V"))
-		{
-			smv = new MainLoggingMethodVisitor(Opcodes.ASM4, primaryMV, acc, name, desc, className);
-		}
-
-		if(classIsCallback(className))
-		{
-			AnalyzerAdapter analyzer = new AnalyzerAdapter(className, acc, name, desc, smv);
-			JSRInlinerAdapter mv = new JSRInlinerAdapter(analyzer, acc, name, desc, signature, exceptions);
-			CloningAdviceAdapter caa = new CloningAdviceAdapter(Opcodes.ASM4, mv, acc, name, desc, className);
-			smv = new CallbackLoggingMethodVisitor(Opcodes.ASM4,caa, acc, name, desc, className, null,caa);
-			smv = new JSRInlinerAdapter(smv, acc, name, desc, signature, exceptions);
-			smv = new LocalVariablesSorter(acc, desc, smv);
-			caa.setLocalVariableSorter((LocalVariablesSorter) smv);
-
-		}
-		if (isAClass && !name.equals(Constants.INNER_COPY_METHOD_NAME) && !name.equals(Constants.OUTER_COPY_METHOD_NAME) && !name.equals(Constants.SET_FIELDS_METHOD_NAME)
-				&& !className.startsWith("com/thoughtworks")
-				)
-		{
-
-			AnalyzerAdapter analyzer = new AnalyzerAdapter(className, acc, name, desc, smv);
-			JSRInlinerAdapter mv = new JSRInlinerAdapter(analyzer, acc, name, desc, signature, exceptions);
-//			LocalVariablesSorter sorter  = new LocalVariablesSorter(acc, desc, analyzer);
-
-			// CheckMethodAdapter cmv = new CheckMethodAdapter(mv);
-
-			NonDeterministicLoggingMethodVisitor cloningMV = new NonDeterministicLoggingMethodVisitor(Opcodes.ASM4, mv, acc, name, desc, className, isFirstConstructor, analyzer);
-			if (name.equals("<init>"))
-				isFirstConstructor = false;
-			cloningMV.setClassVisitor(this);
-			JSRInlinerAdapter mv2 = new JSRInlinerAdapter(cloningMV, acc, name, desc, signature, exceptions);
-			LocalVariablesSorter sorter = new LocalVariablesSorter(acc, desc, mv2);
-			cloningMV.setLocalVariableSorter(sorter);
-			return sorter;
-		} else
-			return smv;
-	}
-
-	public HashSet<MethodCall> getLoggedMethodCalls() {
-		return loggedMethodCalls;
-	}
-
-	private HashSet<MethodCall> loggedMethodCalls = new HashSet<MethodCall>();
-	private HashMap<MethodCall, MethodInsnNode> captureMethodsToGenerate = new HashMap<MethodCall, MethodInsnNode>();
-
-	public void addFieldMarkup(Collection<MethodCall> calls) {
-		logger.debug("Received field markup from method visitor (" + calls.size() + ")");
-		loggedMethodCalls.addAll(calls);
-		// TODO also setup the new method to retrieve the list of replacements
-		// for the method
-	}
-
-	@Override
-	public void visitEnd() {
-		super.visitEnd();
-		for (MethodCall mc : captureMethodsToGenerate.keySet()) {
-			MethodInsnNode mi = captureMethodsToGenerate.get(mc);
-			String methodDesc = mi.desc;
-
-			String captureDesc = mi.desc;
-
-			int opcode = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
-			if(mi.getOpcode() == Opcodes.INVOKESPECIAL && !mi.name.equals("<init>"))
-				opcode = Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL;
-			else if (mi.getOpcode() != Opcodes.INVOKESTATIC) {
-				// Need to put owner of the method on the top of the args list
-				captureDesc = "(L" + mi.owner + ";";
-				for (Type t : Type.getArgumentTypes(mi.desc))
-					captureDesc += t.getDescriptor();
-				captureDesc += ")" + Type.getReturnType(mi.desc).getDescriptor();
-			}
-			MethodVisitor mv = super.visitMethod(opcode, mc.getCapturePrefix() + "_capture", captureDesc, null, null);
-			CloningAdviceAdapter caa = new CloningAdviceAdapter(Opcodes.ASM4, mv, opcode, mc.getCapturePrefix() + "_capture", captureDesc, className);
-			LocalVariablesSorter lvs = new LocalVariablesSorter(opcode, captureDesc, caa);
-			caa.setLocalVariableSorter(lvs);
-			Type[] args = Type.getArgumentTypes(captureDesc);
-			if(mi.name.equals("<init>"))
-			{
-				for (int i = 0; i < args.length; i++) {
-					caa.loadArg(i);
-				}
-				lvs.visitMethodInsn(Opcodes.INVOKESPECIAL, mi.owner, mi.name, mi.desc);
-				caa.loadArg(0);
-			}
-			else
-			{
-				if((opcode & Opcodes.ACC_STATIC) == 0)
-					caa.loadThis();
-				for (int i = 0; i < args.length; i++) {
-					caa.loadArg(i);
-				}
-				lvs.visitMethodInsn(mi.getOpcode(), mi.owner, mi.name, mi.desc);
-				for (int i = 0; i < args.length; i++) {
-					if (args[i].getSort() == Type.ARRAY) {
-						boolean minimalCopy = (Type.getReturnType(methodDesc).getSort() == Type.INT);
-						if(minimalCopy)
-						{
-							caa.dup();
-							Label isNegative = new Label();
-							Label notNegative = new Label();
-							caa.visitJumpInsn(Opcodes.IFLT, isNegative);
-							caa.dup();
-							caa.visitJumpInsn(Opcodes.GOTO, notNegative);
-							caa.visitLabel(isNegative);
-							caa.visitInsn(ICONST_0);
-							caa.visitLabel(notNegative);
-						}
-						caa.loadArg(i);
-						//- (mi.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1)
-						caa.logValueAtTopOfStackToArray(MethodCall.getLogClassName(args[i]), "aLog", "[Ljava/lang/Object;",
-								args[i], true, mi.owner+"."+mi.name+"->_"+i+"\t"+args[i].getDescriptor()+"\t\t"+className,minimalCopy,false);
-						if (args[i].getSize() == 1)
-							caa.pop();
-						else
-							caa.pop2();
-					}
-				}
-			}
-			caa.returnValue();
-			caa.visitMaxs(0, 0);
-			caa.visitEnd();
-		}
-	}
-
-	public String getClassName() {
-		return className;
-	}
-
-	public void addCaptureMethodsToGenerate(HashMap<MethodCall, MethodInsnNode> captureMethodsToGenerate) {
-		this.captureMethodsToGenerate.putAll(captureMethodsToGenerate);
-	}
+    private String className;
+
+    private boolean isAClass = true;
+
+    public static HashSet<String> callbackClasses = new HashSet<String>();
+
+    public static HashSet<String> callbackMethods = new HashSet<String>();
+    static {
+        Scanner s;
+        try {
+            s = new Scanner(NonDeterministicLoggingClassVisitor.class.getClassLoader()
+                    .getResourceAsStream("listenerMethods.txt"));
+            while (s.hasNextLine()) {
+                String l = s.nextLine();
+                callbackMethods.add(l);
+                callbackClasses.add(l.substring(0, l.indexOf(".")));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public NonDeterministicLoggingClassVisitor(int api, ClassVisitor cv) {
+        super(api, cv);
+
+    }
+
+    private static Logger logger = Logger.getLogger(NonDeterministicLoggingClassVisitor.class);
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName,
+            String[] interfaces) {
+        super.visit(version, access, name, signature, superName, interfaces);
+        this.className = name;
+
+        logger.debug("Visiting " + name + " for instrumentation");
+        if ((access & Opcodes.ACC_INTERFACE) != 0)
+            isAClass = false;
+    }
+
+    private boolean isFirstConstructor = true;
+
+    private boolean classIsCallback(String className) {
+        if (callbackClasses.contains(className))
+            return true;
+        if (className.equals("java/lang/Object"))
+            return false;
+        if (!Instrumenter.instrumentedClasses.containsKey(className)) {
+            try {
+                Class<?> c = Instrumenter.loader.loadClass(className.replace("/", "."));
+                for (Class<?> i : c.getInterfaces()) {
+                    if (callbackClasses.contains(Type.getInternalName(i)))
+                        return true;
+                }
+                Class<?> superClass = c.getSuperclass();
+                if (superClass == null)
+                    return false;
+                return classIsCallback(Type.getInternalName(superClass));
+            } catch (ClassNotFoundException ex) {
+                return false;
+            }
+        }
+        ClassNode cn = Instrumenter.instrumentedClasses.get(className);
+        for (Object s : cn.interfaces) {
+            if (callbackClasses.contains(((String) s)))
+                return true;
+        }
+        if (cn.superName.equals(cn.name) || cn.superName.equals("java/lang/Object")
+                || cn.name.equals("org/eclipse/jdt/core/compiler/BuildContext"))
+            return false;
+        else
+            return classIsCallback(cn.superName);
+    }
+
+    public static boolean methodIsCallback(String className, String name, String desc) {
+
+        String key = "." + name + ":" + desc;
+        if (callbackMethods.contains(className + key))
+            return true;
+        if (!Instrumenter.instrumentedClasses.containsKey(className)) {
+            try {
+                Class<?> c = Instrumenter.loader.loadClass(className.replace("/", "."));
+                for (Class<?> i : c.getInterfaces()) {
+                    if (callbackMethods.contains(Type.getInternalName(i) + key))
+                        return true;
+                }
+                Class<?> superClass = c.getSuperclass();
+                if (superClass == null)
+                    return false;
+                return methodIsCallback(Type.getInternalName(superClass), name, desc);
+            } catch (ClassNotFoundException ex) {
+                return false;
+            }
+        }
+        ClassNode cn = Instrumenter.instrumentedClasses.get(className);
+        for (Object s : cn.interfaces) {
+            if (callbackMethods.contains(((String) s) + key))
+                return true;
+        }
+        return methodIsCallback(cn.superName, name, desc);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int acc, String name, String desc, String signature,
+            String[] exceptions) {
+        // TODO need an annotation to disable doing this to some apps
+        MethodVisitor primaryMV = cv.visitMethod(acc, name, desc, signature, exceptions);
+        MethodVisitor smv = new ReflectionInterceptingMethodVisitor(Opcodes.ASM4, primaryMV);
+        smv = new FinalizerLoggingMethodVisitor(acc, smv, name, desc, className);
+        if (name.equals("main") && desc.equals("([Ljava/lang/String;)V")) {
+            smv = new MainLoggingMethodVisitor(Opcodes.ASM4, smv, acc, name, desc, className);
+        }
+
+        if (classIsCallback(className)) {
+            AnalyzerAdapter analyzer = new AnalyzerAdapter(className, acc, name, desc, smv);
+            JSRInlinerAdapter mv = new JSRInlinerAdapter(analyzer, acc, name, desc, signature,
+                    exceptions);
+            CloningAdviceAdapter caa = new CloningAdviceAdapter(Opcodes.ASM4, mv, acc, name, desc,
+                    className);
+            smv = new CallbackLoggingMethodVisitor(Opcodes.ASM4, caa, acc, name, desc, className,
+                    null, caa);
+            smv = new JSRInlinerAdapter(smv, acc, name, desc, signature, exceptions);
+            smv = new LocalVariablesSorter(acc, desc, smv);
+            caa.setLocalVariableSorter((LocalVariablesSorter) smv);
+
+        }
+        if (isAClass && !name.equals(Constants.INNER_COPY_METHOD_NAME)
+                && !name.equals(Constants.OUTER_COPY_METHOD_NAME)
+                && !name.equals(Constants.SET_FIELDS_METHOD_NAME)
+                && !className.startsWith("com/thoughtworks")) {
+
+            AnalyzerAdapter analyzer = new AnalyzerAdapter(className, acc, name, desc, smv);
+            JSRInlinerAdapter mv = new JSRInlinerAdapter(analyzer, acc, name, desc, signature,
+                    exceptions);
+            // LocalVariablesSorter sorter = new LocalVariablesSorter(acc, desc,
+            // analyzer);
+
+            // CheckMethodAdapter cmv = new CheckMethodAdapter(mv);
+
+            NonDeterministicLoggingMethodVisitor cloningMV = new NonDeterministicLoggingMethodVisitor(
+                    Opcodes.ASM4, mv, acc, name, desc, className, isFirstConstructor, analyzer);
+            if (name.equals("<init>"))
+                isFirstConstructor = false;
+            cloningMV.setClassVisitor(this);
+            JSRInlinerAdapter mv2 = new JSRInlinerAdapter(cloningMV, acc, name, desc, signature,
+                    exceptions);
+            LocalVariablesSorter sorter = new LocalVariablesSorter(acc, desc, mv2);
+            cloningMV.setLocalVariableSorter(sorter);
+            return sorter;
+        } else
+            return smv;
+    }
+
+    public HashSet<MethodCall> getLoggedMethodCalls() {
+        return loggedMethodCalls;
+    }
+
+    private HashSet<MethodCall> loggedMethodCalls = new HashSet<MethodCall>();
+
+    private HashMap<MethodCall, MethodInsnNode> captureMethodsToGenerate = new HashMap<MethodCall, MethodInsnNode>();
+
+    public void addFieldMarkup(Collection<MethodCall> calls) {
+        logger.debug("Received field markup from method visitor (" + calls.size() + ")");
+        loggedMethodCalls.addAll(calls);
+        // TODO also setup the new method to retrieve the list of replacements
+        // for the method
+    }
+
+    @Override
+    public void visitEnd() {
+        super.visitEnd();
+
+        for (MethodCall mc : captureMethodsToGenerate.keySet()) {
+            MethodInsnNode mi = captureMethodsToGenerate.get(mc);
+            String methodDesc = mi.desc;
+
+            String captureDesc = mi.desc;
+
+            int opcode = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
+            if (mi.getOpcode() == Opcodes.INVOKESPECIAL && !mi.name.equals("<init>"))
+                opcode = Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL;
+            else if (mi.getOpcode() != Opcodes.INVOKESTATIC) {
+                // Need to put owner of the method on the top of the args list
+                captureDesc = "(L" + mi.owner + ";";
+                for (Type t : Type.getArgumentTypes(mi.desc))
+                    captureDesc += t.getDescriptor();
+                captureDesc += ")" + Type.getReturnType(mi.desc).getDescriptor();
+            }
+            MethodVisitor mv = super.visitMethod(opcode, mc.getCapturePrefix() + "_capture",
+                    captureDesc, null, null);
+            CloningAdviceAdapter caa = new CloningAdviceAdapter(Opcodes.ASM4, mv, opcode,
+                    mc.getCapturePrefix() + "_capture", captureDesc, className);
+            LocalVariablesSorter lvs = new LocalVariablesSorter(opcode, captureDesc, caa);
+            caa.setLocalVariableSorter(lvs);
+            Type[] args = Type.getArgumentTypes(captureDesc);
+            if (mi.name.equals("<init>")) {
+                for (int i = 0; i < args.length; i++) {
+                    caa.loadArg(i);
+                }
+                lvs.visitMethodInsn(Opcodes.INVOKESPECIAL, mi.owner, mi.name, mi.desc);
+                caa.loadArg(0);
+            } else {
+                if ((opcode & Opcodes.ACC_STATIC) == 0)
+                    caa.loadThis();
+                for (int i = 0; i < args.length; i++) {
+                    caa.loadArg(i);
+                }
+                lvs.visitMethodInsn(mi.getOpcode(), mi.owner, mi.name, mi.desc);
+                for (int i = 0; i < args.length; i++) {
+                    if (args[i].getSort() == Type.ARRAY) {
+                        boolean minimalCopy = (Type.getReturnType(methodDesc).getSort() == Type.INT);
+                        if (minimalCopy) {
+                            caa.dup();
+                            Label isNegative = new Label();
+                            Label notNegative = new Label();
+                            caa.visitJumpInsn(Opcodes.IFLT, isNegative);
+                            caa.dup();
+                            caa.visitJumpInsn(Opcodes.GOTO, notNegative);
+                            caa.visitLabel(isNegative);
+                            caa.visitInsn(ICONST_0);
+                            caa.visitLabel(notNegative);
+                        }
+                        caa.loadArg(i);
+                        // - (mi.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1)
+                        caa.logValueAtTopOfStackToArray(MethodCall.getLogClassName(args[i]),
+                                "aLog", "[Ljava/lang/Object;", args[i], true, mi.owner + "."
+                                        + mi.name + "->_" + i + "\t" + args[i].getDescriptor()
+                                        + "\t\t" + className, minimalCopy, false);
+                        if (args[i].getSize() == 1)
+                            caa.pop();
+                        else
+                            caa.pop2();
+                    }
+                }
+            }
+            caa.returnValue();
+            caa.visitMaxs(0, 0);
+            caa.visitEnd();
+        }
+        if (isAClass) {
+            FieldNode fn = new FieldNode(Opcodes.ACC_PRIVATE, Instrumenter.FIELD_LOGICAL_CLOCK,
+                    "J", null, 0L);
+            fn.accept(this);
+        }
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void addCaptureMethodsToGenerate(
+            HashMap<MethodCall, MethodInsnNode> captureMethodsToGenerate) {
+        this.captureMethodsToGenerate.putAll(captureMethodsToGenerate);
+    }

 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingMethodVisitor.java
index afca16a..e724d2a 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingMethodVisitor.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/NonDeterministicLoggingMethodVisitor.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.visitor;

 import java.io.File;
@@ -20,218 +21,270 @@ import edu.columbia.cs.psl.chroniclerj.Constants;
 import edu.columbia.cs.psl.chroniclerj.Instrumenter;
 import edu.columbia.cs.psl.chroniclerj.MethodCall;
 import edu.columbia.cs.psl.chroniclerj.replay.NonDeterministicReplayMethodVisitor;
+import edu.columbia.cs.psl.chroniclerj.struct.AnnotatedMethod;

 public class NonDeterministicLoggingMethodVisitor extends CloningAdviceAdapter {
-	private static Logger			logger					= Logger.getLogger(NonDeterministicLoggingMethodVisitor.class);
-	private String					name;
-	private String					desc;
-	private String					classDesc;
-	private int						pc;
-	public static HashSet<String>	nonDeterministicMethods	= new HashSet<String>();
-	private boolean					isStatic;
-	private boolean					constructor;
-	private boolean					superInitialized;
-	private AnalyzerAdapter analyzer;
-	public static boolean isND(String owner, String name, String desc)
-	{
-		return nonDeterministicMethods.contains(owner + "." + name + ":" + desc);
-	}
-	public static void registerNDMethod(String owner, String name, String desc)
-	{
-		nonDeterministicMethods.add(owner + "." + name + ":" + desc);
-	}
-	static {
-		Scanner s;
-		try {
-			s = new Scanner(NonDeterministicReplayMethodVisitor.class.getClassLoader().getResourceAsStream("nondeterministic-methods.txt"));
-			while (s.hasNextLine())
-				nonDeterministicMethods.add(s.nextLine());
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-
-	@Override
-	public void visitCode() {
-		super.visitCode();
-		if (!constructor)
-			superInitialized = true;
-	}
-
-	private boolean	isFirstConstructor;
-
-	protected NonDeterministicLoggingMethodVisitor(int api, MethodVisitor mv, int access, String name, String desc, String classDesc,
-			boolean isFirstConstructor, AnalyzerAdapter analyzer) {
-		super(api, mv, access, name, desc,classDesc);
-		this.name = name;
-		this.desc = desc;
-		this.classDesc = classDesc;
-		this.isStatic = (access & Opcodes.ACC_STATIC) != 0;
-		this.constructor = "<init>".equals(name);
-		this.isFirstConstructor = isFirstConstructor;
-		this.analyzer = analyzer;
-	}
-
-	private NonDeterministicLoggingClassVisitor	parent;
-
-	public void setClassVisitor(NonDeterministicLoggingClassVisitor coaClassVisitor) {
-		this.parent = coaClassVisitor;
-	}
-
-
-	@Override
-	public void visitEnd() {
-//		System.out.println(classDesc + " " + name);
-		super.visitEnd();
-
-		parent.addFieldMarkup(methodCallsToClear);
-		parent.addCaptureMethodsToGenerate(captureMethodsToGenerate);
-	}
-
-	private int	lineNumber	= 0;
-
-	@Override
-	public void visitLineNumber(int line, Label start) {
-		super.visitLineNumber(line, start);
-		lineNumber = line;
-	}
-
-	private HashMap<MethodCall, MethodInsnNode> captureMethodsToGenerate = new HashMap<MethodCall, MethodInsnNode>();
-	@Override
-	public void visitMethodInsn(int opcode, String owner, String name, String desc) {
-		try {
-			if(Instrumenter.instrumentedClasses.get(classDesc) == null)
-			{
-				System.err.println("No class info for " + classDesc);
-			}
-			MethodCall m = new MethodCall(this.name, this.desc, this.classDesc, pc, lineNumber, owner, name, desc, isStatic);
-			Type returnType = Type.getMethodType(desc).getReturnType();
-			if ((!constructor || isFirstConstructor || superInitialized) && !returnType.equals(Type.VOID_TYPE)
-					&& nonDeterministicMethods.contains(owner + "." + name + ":" + desc)) {
-				logger.debug("Adding field in MV to list " + m.getLogFieldName());
-				methodCallsToClear.add(m);
-				Type[] args = Type.getArgumentTypes(desc);
-				boolean hasArray = false;
-				for(Type t : args)
-					if(t.getSort() == Type.ARRAY && !name.contains("write") && !name.contains("invoke"))
-						hasArray = true;
-
-				if(hasArray)
-				{	//TODO uncomment this block
-					captureMethodsToGenerate.put(m, new MethodInsnNode(opcode, owner, name, desc));
-					String captureDesc = desc;
-
-					int invokeOpcode = Opcodes.INVOKESTATIC;
-					if(opcode == Opcodes.INVOKESPECIAL && !name.equals("<init>"))
-					{
-						invokeOpcode = Opcodes.INVOKESPECIAL;
-					}
-					else if(opcode != Opcodes.INVOKESTATIC)
-					{
-						//Need to put owner of the method on the top of the args list
-						captureDesc = "(L" +  owner +";";
-						for(Type t : args)
-							captureDesc += t.getDescriptor();
-						captureDesc+=")"+Type.getReturnType(desc).getDescriptor();
-					}
-					mv.visitMethodInsn(invokeOpcode, classDesc, m.getCapturePrefix()+"_capture", captureDesc);
-					logValueAtTopOfStackToArray(m.getLogClassName(), m.getLogFieldName(), m.getLogFieldType().getDescriptor(), returnType, true,
-							owner+"."+name + "\t" + desc+"\t\t"+classDesc+"."+this.name,false,true);
-				}
-				else
-				{
-					mv.visitMethodInsn(opcode, owner, name, desc);
-					logValueAtTopOfStackToArray(m.getLogClassName(), m.getLogFieldName(), m.getLogFieldType().getDescriptor(), returnType, true,
-							owner+"."+name + "\t" + desc+"\t\t"+classDesc+"."+this.name,false,true);
-				}
-			}
-			else if(opcode == INVOKESPECIAL && name.equals("<init>") && nonDeterministicMethods.contains(owner + "." + name + ":" + desc) && !(owner.equals(Instrumenter.instrumentedClasses.get(classDesc).superName)
-					&& this.name.equals("<init>"))) {
-				super.visitMethodInsn(opcode, owner, name, desc);
-				if(analyzer.stack != null && analyzer.stack.size() > 0 && analyzer.stack.get(analyzer.stack.size()-1).equals(owner))
-					logValueAtTopOfStackToArray(MethodCall.getLogClassName(Type.getType("L"+owner+";")), "aLog", "[Ljava/lang/Object;", Type.getType("L"+owner+";"), true,
-							owner+"."+name + "\t" + desc+"\t\t"+classDesc+"."+this.name,false,true);
-
-			}
-			else
-				mv.visitMethodInsn(opcode, owner, name, desc);
-			pc++;
-		} catch (Exception ex) {
-			logger.error("Unable to instrument method call", ex);
-		}
-	}
-
-	private HashSet<MethodCall>	methodCallsToClear	= new HashSet<MethodCall>();
-
-	@Override
-	public void visitFieldInsn(int opcode, String owner, String name, String desc) {
-		super.visitFieldInsn(opcode, owner, name, desc);
-		pc++;
-	}
-
-	@Override
-	public void visitIincInsn(int var, int increment) {
-		super.visitIincInsn(var, increment);
-		pc++;
-	}
-
-	@Override
-	public void visitInsn(int opcode) {
-		super.visitInsn(opcode);
-		pc++;
-	}
-
-	@Override
-	public void visitIntInsn(int opcode, int operand) {
-		super.visitIntInsn(opcode, operand);
-		pc++;
-	}
-
-	@Override
-	public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
-		super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
-		pc++;
-	}
-
-	@Override
-	public void visitJumpInsn(int opcode, Label label) {
-		super.visitJumpInsn(opcode, label);
-		pc++;
-	}
-
-	@Override
-	public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
-		super.visitLookupSwitchInsn(dflt, keys, labels);
-		pc++;
-	}
-
-	@Override
-	public void visitMultiANewArrayInsn(String desc, int dims) {
-		super.visitMultiANewArrayInsn(desc, dims);
-		pc++;
-	}
-
-	@Override
-	public void visitTypeInsn(int opcode, String type) {
-		super.visitTypeInsn(opcode, type);
-		pc++;
-	}
-
-	@Override
-	public void visitVarInsn(int opcode, int var) {
-		super.visitVarInsn(opcode, var);
-		pc++;
-	}
-
-	@Override
-	public void visitLdcInsn(Object cst) {
-		super.visitLdcInsn(cst);
-		pc++;
-	}
-
-	@Override
-	public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
-		super.visitTableSwitchInsn(min, max, dflt, labels);
-		pc++;
-	}
+    private static Logger logger = Logger.getLogger(NonDeterministicLoggingMethodVisitor.class);
+
+    private String name;
+
+    private String desc;
+
+    private String classDesc;
+
+    private int pc;
+
+    public static HashSet<String> nonDeterministicMethods = new HashSet<String>();
+
+    private boolean isStatic;
+
+    private boolean constructor;
+
+    private boolean superInitialized;
+
+    private AnalyzerAdapter analyzer;
+
+    private static HashSet<String> ignoredNDMethods = new HashSet<String>();
+
+    public static boolean isND(String owner, String name, String desc) {
+        return nonDeterministicMethods.contains(owner + "." + name + ":" + desc);
+    }
+
+    public static void registerNDMethod(String owner, String name, String desc) {
+        nonDeterministicMethods.add(owner + "." + name + ":" + desc);
+    }
+
+    static {
+        Scanner s;
+        try {
+            s = new Scanner(NonDeterministicReplayMethodVisitor.class.getClassLoader()
+                    .getResourceAsStream("nondeterministic-methods.txt"));
+            while (s.hasNextLine())
+                nonDeterministicMethods.add(s.nextLine());
+            if (Instrumenter.IS_DACAPO) {
+                s = new Scanner(NonDeterministicLoggingMethodVisitor.class.getClassLoader()
+                        .getResourceAsStream("nd-geronimo-ignored"));
+                while (s.hasNextLine())
+                    nonDeterministicMethods.remove(s.nextLine());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        ignoredNDMethods
+                .add("java/util/Properties.keys()Ljava/util/Enumeration;org/apache/geronimo/axis/client/GenericServiceEndpoint.createCall");
+    }
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        if (!constructor)
+            superInitialized = true;
+    }
+
+    private boolean isFirstConstructor;
+
+    protected NonDeterministicLoggingMethodVisitor(int api, MethodVisitor mv, int access,
+            String name, String desc, String classDesc, boolean isFirstConstructor,
+            AnalyzerAdapter analyzer) {
+        super(api, mv, access, name, desc, classDesc);
+        this.name = name;
+        this.desc = desc;
+        this.classDesc = classDesc;
+        this.isStatic = (access & Opcodes.ACC_STATIC) != 0;
+        this.constructor = "<init>".equals(name);
+        this.isFirstConstructor = isFirstConstructor;
+        this.analyzer = analyzer;
+    }
+
+    private NonDeterministicLoggingClassVisitor parent;
+
+    public void setClassVisitor(NonDeterministicLoggingClassVisitor coaClassVisitor) {
+        this.parent = coaClassVisitor;
+    }
+
+    @Override
+    public void visitEnd() {
+        // System.out.println(classDesc + " " + name);
+        super.visitEnd();
+
+        parent.addFieldMarkup(methodCallsToClear);
+        parent.addCaptureMethodsToGenerate(captureMethodsToGenerate);
+    }
+
+    private int lineNumber = 0;
+
+    @Override
+    public void visitLineNumber(int line, Label start) {
+        super.visitLineNumber(line, start);
+        lineNumber = line;
+    }
+
+    private HashMap<MethodCall, MethodInsnNode> captureMethodsToGenerate = new HashMap<MethodCall, MethodInsnNode>();
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+        try {
+            if (Instrumenter.instrumentedClasses.get(classDesc) == null) {
+                System.err.println("No class info for " + classDesc);
+            }
+            MethodCall m = new MethodCall(this.name, this.desc, this.classDesc, pc, lineNumber,
+                    owner, name, desc, isStatic);
+            Type returnType = Type.getMethodType(desc).getReturnType();
+            if ((!constructor || isFirstConstructor || superInitialized)
+                    && !returnType.equals(Type.VOID_TYPE)
+                    && nonDeterministicMethods.contains(owner + "." + name + ":" + desc)
+                    && !ignoredNDMethods.contains(owner + "." + name + desc + this.classDesc + "."
+                            + this.name)) {
+                logger.debug("Adding field in MV to list " + m.getLogFieldName());
+                methodCallsToClear.add(m);
+                Type[] args = Type.getArgumentTypes(desc);
+                boolean hasArray = false;
+                for (Type t : args)
+                    if (t.getSort() == Type.ARRAY && !name.contains("write")
+                            && !name.contains("invoke"))
+                        hasArray = true;
+
+                if (hasArray) { // TODO uncomment this block
+                    captureMethodsToGenerate.put(m, new MethodInsnNode(opcode, owner, name, desc));
+                    String captureDesc = desc;
+
+                    int invokeOpcode = Opcodes.INVOKESTATIC;
+                    if (opcode == Opcodes.INVOKESPECIAL && !name.equals("<init>")) {
+                        invokeOpcode = Opcodes.INVOKESPECIAL;
+                    } else if (opcode != Opcodes.INVOKESTATIC) {
+                        // Need to put owner of the method on the top of the
+                        // args list
+                        captureDesc = "(L" + owner + ";";
+                        for (Type t : args)
+                            captureDesc += t.getDescriptor();
+                        captureDesc += ")" + Type.getReturnType(desc).getDescriptor();
+                    }
+                    mv.visitMethodInsn(invokeOpcode, classDesc, m.getCapturePrefix() + "_capture",
+                            captureDesc);
+                    logValueAtTopOfStackToArray(m.getLogClassName(), m.getLogFieldName(), m
+                            .getLogFieldType().getDescriptor(), returnType, true, owner + "."
+                            + name + "\t" + desc + "\t\t" + classDesc + "." + this.name, false,
+                            true);
+                } else {
+                    mv.visitMethodInsn(opcode, owner, name, desc);
+                    logValueAtTopOfStackToArray(m.getLogClassName(), m.getLogFieldName(), m
+                            .getLogFieldType().getDescriptor(), returnType, true, owner + "."
+                            + name + "\t" + desc + "\t\t" + classDesc + "." + this.name, false,
+                            true);
+                }
+            } else if (opcode == INVOKESPECIAL
+                    && name.equals("<init>")
+                    && nonDeterministicMethods.contains(owner + "." + name + ":" + desc)
+                    && !(owner.equals(Instrumenter.instrumentedClasses.get(classDesc).superName) && this.name
+                            .equals("<init>"))) {
+                super.visitMethodInsn(opcode, owner, name, desc);
+                if (analyzer.stack != null && analyzer.stack.size() > 0
+                        && analyzer.stack.get(analyzer.stack.size() - 1).equals(owner))
+                    logValueAtTopOfStackToArray(
+                            MethodCall.getLogClassName(Type.getType("L" + owner + ";")), "aLog",
+                            "[Ljava/lang/Object;", Type.getType("L" + owner + ";"), true, owner
+                                    + "." + name + "\t" + desc + "\t\t" + classDesc + "."
+                                    + this.name, false, true);
+
+            } else
+                mv.visitMethodInsn(opcode, owner, name, desc);
+
+            if (constructor && !init) {
+                init = true;
+                AnnotatedMethod am = Instrumenter.getAnnotatedMethod(this.classDesc, "finalize",
+                        "()V");
+                if (am != null && am.isCallsNDMethods()) {
+                    visitVarInsn(ALOAD, 0);
+                    visitFieldInsn(Opcodes.GETSTATIC, "edu/columbia/cs/psl/chroniclerj/Log",
+                            Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+                    visitInsn(DUP2_X1);
+                    visitFieldInsn(Opcodes.PUTFIELD, this.classDesc,
+                            Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+                    visitInsn(LCONST_1);
+                    visitInsn(LADD);
+                    visitFieldInsn(Opcodes.PUTSTATIC, "edu/columbia/cs/psl/chroniclerj/Log",
+                            Instrumenter.FIELD_LOGICAL_CLOCK, "J");
+                }
+            }
+            pc++;
+        } catch (Exception ex) {
+            logger.error("Unable to instrument method call", ex);
+        }
+    }
+
+    private boolean init = false;
+
+    private HashSet<MethodCall> methodCallsToClear = new HashSet<MethodCall>();
+
+    @Override
+    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+        super.visitFieldInsn(opcode, owner, name, desc);
+        pc++;
+    }
+
+    @Override
+    public void visitIincInsn(int var, int increment) {
+        super.visitIincInsn(var, increment);
+        pc++;
+    }
+
+    @Override
+    public void visitInsn(int opcode) {
+        super.visitInsn(opcode);
+        pc++;
+    }
+
+    @Override
+    public void visitIntInsn(int opcode, int operand) {
+        super.visitIntInsn(opcode, operand);
+        pc++;
+    }
+
+    @Override
+    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+        super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+        pc++;
+    }
+
+    @Override
+    public void visitJumpInsn(int opcode, Label label) {
+        super.visitJumpInsn(opcode, label);
+        pc++;
+    }
+
+    @Override
+    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+        super.visitLookupSwitchInsn(dflt, keys, labels);
+        pc++;
+    }
+
+    @Override
+    public void visitMultiANewArrayInsn(String desc, int dims) {
+        super.visitMultiANewArrayInsn(desc, dims);
+        pc++;
+    }
+
+    @Override
+    public void visitTypeInsn(int opcode, String type) {
+        super.visitTypeInsn(opcode, type);
+        pc++;
+    }
+
+    @Override
+    public void visitVarInsn(int opcode, int var) {
+        super.visitVarInsn(opcode, var);
+        pc++;
+    }
+
+    @Override
+    public void visitLdcInsn(Object cst) {
+        super.visitLdcInsn(cst);
+        pc++;
+    }
+
+    @Override
+    public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
+        super.visitTableSwitchInsn(min, max, dflt, labels);
+        pc++;
+    }
 }
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/ReflectionInterceptingMethodVisitor.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/ReflectionInterceptingMethodVisitor.java
new file mode 100644
index 0000000..3f934f4
--- /dev/null
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/visitor/ReflectionInterceptingMethodVisitor.java
@@ -0,0 +1,24 @@
+
+package edu.columbia.cs.psl.chroniclerj.visitor;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class ReflectionInterceptingMethodVisitor extends MethodVisitor {
+
+    public ReflectionInterceptingMethodVisitor(int api, MethodVisitor mv) {
+        super(api, mv);
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+        if (owner.equals("java/lang/reflect/Method") && name.equals("invoke")) {
+            opcode = Opcodes.INVOKESTATIC;
+            owner = "edu/columbia/cs/psl/chroniclerj/MethodInterceptor";
+            super.visitMethodInsn(Opcodes.INVOKESTATIC,
+                    "edu/columbia/cs/psl/chroniclerj/MethodInterceptor", "invoke",
+                    "(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
+        } else
+            super.visitMethodInsn(opcode, owner, name, desc);
+    }
+}
diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/CatchClassErrorFieldDictionary.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/CatchClassErrorFieldDictionary.java
index 2be436f..7b81237 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/CatchClassErrorFieldDictionary.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/CatchClassErrorFieldDictionary.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.xstream;

 import java.lang.reflect.Field;
@@ -22,7 +23,9 @@ import com.thoughtworks.xstream.core.util.OrderRetainingMap;

 public class CatchClassErrorFieldDictionary extends FieldDictionary {
     private transient Map keyedByFieldNameCache;
+
     private transient Map keyedByFieldKeyCache;
+
     private final FieldKeySorter sorter;

     public CatchClassErrorFieldDictionary() {
@@ -63,14 +66,16 @@ public class CatchClassErrorFieldDictionary extends FieldDictionary {
     }

     /**
-     * Returns an specific field of some class. If definedIn is null, it searches for the field
-     * named 'name' inside the class cls. If definedIn is different than null, tries to find the
-     * specified field name in the specified class cls which should be defined in class
-     * definedIn (either equals cls or a one of it's superclasses)
+     * Returns an specific field of some class. If definedIn is null, it
+     * searches for the field named 'name' inside the class cls. If definedIn is
+     * different than null, tries to find the specified field name in the
+     * specified class cls which should be defined in class definedIn (either
+     * equals cls or a one of it's superclasses)
      *
      * @param cls the class where the field is to be searched
      * @param name the field name
-     * @param definedIn the superclass (or the class itself) of cls where the field was defined
+     * @param definedIn the superclass (or the class itself) of cls where the
+     *            field was defined
      * @return the field itself
      * @throws ObjectAccessException if no field can be found
      */
@@ -84,44 +89,47 @@ public class CatchClassErrorFieldDictionary extends FieldDictionary {
     }

     /**
-     * Returns an specific field of some class. If definedIn is null, it searches for the field
-     * named 'name' inside the class cls. If definedIn is different than null, tries to find the
-     * specified field name in the specified class cls which should be defined in class
-     * definedIn (either equals cls or a one of it's superclasses)
+     * Returns an specific field of some class. If definedIn is null, it
+     * searches for the field named 'name' inside the class cls. If definedIn is
+     * different than null, tries to find the specified field name in the
+     * specified class cls which should be defined in class definedIn (either
+     * equals cls or a one of it's superclasses)
      *
      * @param cls the class where the field is to be searched
      * @param name the field name
-     * @param definedIn the superclass (or the class itself) of cls where the field was defined
+     * @param definedIn the superclass (or the class itself) of cls where the
+     *            field was defined
      * @return the field itself or <code>null</code>
      * @since 1.4
      */
     public Field fieldOrNull(Class cls, String name, Class definedIn) {
         Map fields = buildMap(cls, definedIn != null);
-        Field field = (Field)fields.get(definedIn != null
-            ? (Object)new FieldKey(name, definedIn, 0)
-            : (Object)name);
+        Field field = (Field) fields.get(definedIn != null ? (Object) new FieldKey(name, definedIn,
+                0) : (Object) name);
         return field;
     }

-    @SuppressWarnings({ "rawtypes", "unchecked" })
-	private Map buildMap(final Class type, boolean tupleKeyed) {
+    @SuppressWarnings({
+            "rawtypes", "unchecked"
+    })
+    private Map buildMap(final Class type, boolean tupleKeyed) {
         final Map result;
         Class cls = type;
-//        synchronized (this) {
-            if (!keyedByFieldNameCache.containsKey(type)) {
-                final List superClasses = new ArrayList();
-                while (!Object.class.equals(cls)) {
-                    superClasses.add(0, cls);
-                    cls = cls.getSuperclass();
-                }
-                Map lastKeyedByFieldName = Collections.EMPTY_MAP;
-                Map lastKeyedByFieldKey = Collections.EMPTY_MAP;
-                for (final Iterator iter = superClasses.iterator(); iter.hasNext();) {
-                    cls = (Class)iter.next();
-                    if (!keyedByFieldNameCache.containsKey(cls)) {
-                        final Map keyedByFieldName = new HashMap(lastKeyedByFieldName);
-                        final Map keyedByFieldKey = new OrderRetainingMap(lastKeyedByFieldKey);
-                        try{
+        // synchronized (this) {
+        if (!keyedByFieldNameCache.containsKey(type)) {
+            final List superClasses = new ArrayList();
+            while (!Object.class.equals(cls)) {
+                superClasses.add(0, cls);
+                cls = cls.getSuperclass();
+            }
+            Map lastKeyedByFieldName = Collections.EMPTY_MAP;
+            Map lastKeyedByFieldKey = Collections.EMPTY_MAP;
+            for (final Iterator iter = superClasses.iterator(); iter.hasNext();) {
+                cls = (Class) iter.next();
+                if (!keyedByFieldNameCache.containsKey(cls)) {
+                    final Map keyedByFieldName = new HashMap(lastKeyedByFieldName);
+                    final Map keyedByFieldKey = new OrderRetainingMap(lastKeyedByFieldKey);
+                    try {
                         Field[] fields = cls.getDeclaredFields();
                         if (JVM.reverseFieldDefinition()) {
                             for (int i = fields.length >> 1; i-- > 0;) {
@@ -131,45 +139,43 @@ public class CatchClassErrorFieldDictionary extends FieldDictionary {
                                 fields[idx] = field;
                             }
                         }
-                        for (int i = 0; i < fields.length; i++ ) {
+                        for (int i = 0; i < fields.length; i++) {
                             Field field = fields[i];
                             if (!field.isAccessible()) {
                                 field.setAccessible(true);
                             }
-                            FieldKey fieldKey = new FieldKey(
-                                field.getName(), field.getDeclaringClass(), i);
-                            Field existent = (Field)keyedByFieldName.get(field.getName());
+                            FieldKey fieldKey = new FieldKey(field.getName(),
+                                    field.getDeclaringClass(), i);
+                            Field existent = (Field) keyedByFieldName.get(field.getName());
                             if (existent == null
                             // do overwrite statics
-                                || ((existent.getModifiers() & Modifier.STATIC) != 0)
-                                // overwrite non-statics with non-statics only
-                                || (existent != null && ((field.getModifiers() & Modifier.STATIC) == 0))) {
+                                    || ((existent.getModifiers() & Modifier.STATIC) != 0)
+                                    // overwrite non-statics with non-statics
+                                    // only
+                                    || (existent != null && ((field.getModifiers() & Modifier.STATIC) == 0))) {
                                 keyedByFieldName.put(field.getName(), field);
                             }
                             keyedByFieldKey.put(fieldKey, field);
                         }
-                        }
-                        catch(NoClassDefFoundError ex)
-                        {
-                        	//do nothing!
-                        }
-                        final Map sortedFieldKeys = sorter.sort(type, keyedByFieldKey);
-                        keyedByFieldNameCache.put(cls, keyedByFieldName);
-                        keyedByFieldKeyCache.put(cls, sortedFieldKeys);
-                        lastKeyedByFieldName = keyedByFieldName;
-                        lastKeyedByFieldKey = sortedFieldKeys;
-                    } else {
-                        lastKeyedByFieldName = (Map)keyedByFieldNameCache.get(cls);
-                        lastKeyedByFieldKey = (Map)keyedByFieldKeyCache.get(cls);
+                    } catch (NoClassDefFoundError ex) {
+                        // do nothing!
                     }
+                    final Map sortedFieldKeys = sorter.sort(type, keyedByFieldKey);
+                    keyedByFieldNameCache.put(cls, keyedByFieldName);
+                    keyedByFieldKeyCache.put(cls, sortedFieldKeys);
+                    lastKeyedByFieldName = keyedByFieldName;
+                    lastKeyedByFieldKey = sortedFieldKeys;
+                } else {
+                    lastKeyedByFieldName = (Map) keyedByFieldNameCache.get(cls);
+                    lastKeyedByFieldKey = (Map) keyedByFieldKeyCache.get(cls);
                 }
-                result = tupleKeyed ? lastKeyedByFieldKey : lastKeyedByFieldName;
-            } else {
-                result = (Map)(tupleKeyed
-                    ? keyedByFieldKeyCache.get(type)
-                    : keyedByFieldNameCache.get(type));
             }
-//        }
+            result = tupleKeyed ? lastKeyedByFieldKey : lastKeyedByFieldName;
+        } else {
+            result = (Map) (tupleKeyed ? keyedByFieldKeyCache.get(type) : keyedByFieldNameCache
+                    .get(type));
+        }
+        // }
         return result;
     }

@@ -178,7 +184,7 @@ public class CatchClassErrorFieldDictionary extends FieldDictionary {
         keyedByFieldNameCache.keySet().retainAll(objectTypeSet);
         keyedByFieldKeyCache.keySet().retainAll(objectTypeSet);
         if (sorter instanceof Caching) {
-            ((Caching)sorter).flushCache();
+            ((Caching) sorter).flushCache();
         }
     }

diff --git a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/StaticReflectionProvider.java b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/StaticReflectionProvider.java
index 59fe6e4..4326b0f 100644
--- a/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/StaticReflectionProvider.java
+++ b/Code/ChroniclerJ/src/edu/columbia/cs/psl/chroniclerj/xstream/StaticReflectionProvider.java
@@ -1,3 +1,4 @@
+
 package edu.columbia.cs.psl.chroniclerj.xstream;

 import java.lang.reflect.Field;
@@ -8,56 +9,62 @@ import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
 import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;

 public class StaticReflectionProvider extends Sun14ReflectionProvider {
-	public void writeField(Object object, String fieldName, Object value, Class definedIn) {
-		if (!Modifier.isStatic(fieldDictionary.field(object.getClass(), fieldName, definedIn).getModifiers())) {
-			super.writeField(object, fieldName, value, definedIn);
-		} else {
-			try {
-				fieldDictionary.field(object.getClass(), fieldName, definedIn).set(null, value);
-			} catch (IllegalArgumentException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			} catch (IllegalAccessException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
-	}
-
-	public StaticReflectionProvider() {
-		super(new CatchClassErrorFieldDictionary());
-	}
-
-	@Override
-	public void visitSerializableFields(Object object, Visitor visitor) {
-		for (Iterator iterator = fieldDictionary.fieldsFor(object.getClass()); iterator.hasNext();) {
-			Field field = (Field) iterator.next();
-			if (!fieldModifiersSupported(field)) {
-				continue;
-			}
-			validateFieldAccess(field);
-			try {
-				Object value = field.get(object);
-				if (value != null)
-//					synchronized (value) {
-						visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
-//					}
-				else
-					visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
-
-			} catch (IllegalArgumentException e) {
-				throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
-			} catch (IllegalAccessException e) {
-				throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
-			} catch (SecurityException e) {
-				e.printStackTrace();
-			}
-		}
-	}
-
-	@Override
-	protected boolean fieldModifiersSupported(Field field) {
-		int modifiers = field.getModifiers();
-		return !(Modifier.isTransient(modifiers) || (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers) ));
-	}
+    public void writeField(Object object, String fieldName, Object value, Class definedIn) {
+        if (!Modifier.isStatic(fieldDictionary.field(object.getClass(), fieldName, definedIn)
+                .getModifiers())) {
+            super.writeField(object, fieldName, value, definedIn);
+        } else {
+            try {
+                fieldDictionary.field(object.getClass(), fieldName, definedIn).set(null, value);
+            } catch (IllegalArgumentException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public StaticReflectionProvider() {
+        super(new CatchClassErrorFieldDictionary());
+    }
+
+    @Override
+    public void visitSerializableFields(Object object, Visitor visitor) {
+        for (Iterator iterator = fieldDictionary.fieldsFor(object.getClass()); iterator.hasNext();) {
+            Field field = (Field) iterator.next();
+            if (!fieldModifiersSupported(field)) {
+                continue;
+            }
+            validateFieldAccess(field);
+            try {
+                Object value = field.get(object);
+                if (value != null)
+                    // synchronized (value) {
+                    visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(),
+                            value);
+                // }
+                else
+                    visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(),
+                            value);
+
+            } catch (IllegalArgumentException e) {
+                throw new ObjectAccessException("Could not get field " + field.getClass() + "."
+                        + field.getName(), e);
+            } catch (IllegalAccessException e) {
+                throw new ObjectAccessException("Could not get field " + field.getClass() + "."
+                        + field.getName(), e);
+            } catch (SecurityException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    protected boolean fieldModifiersSupported(Field field) {
+        int modifiers = field.getModifiers();
+        return !(Modifier.isTransient(modifiers) || (Modifier.isStatic(modifiers) && Modifier
+                .isFinal(modifiers)));
+    }
 }