You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2015/10/31 23:38:36 UTC

svn commit: r1711700 [2/2] - /uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java?rev=1711700&r1=1711699&r2=1711700&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java Sat Oct 31 22:38:36 2015
@@ -20,21 +20,14 @@
 package org.apache.uima.cas.impl;
 
 import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.net.MalformedURLException;
+import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.nio.ByteBuffer;
-import java.nio.DoubleBuffer;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.nio.LongBuffer;
-import java.nio.ShortBuffer;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -43,6 +36,7 @@ import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
@@ -54,6 +48,7 @@ import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.CasOwner;
+import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.ComponentInfo;
 import org.apache.uima.cas.ConstraintFactory;
 import org.apache.uima.cas.DoubleArrayFS;
@@ -69,7 +64,6 @@ import org.apache.uima.cas.FloatArrayFS;
 import org.apache.uima.cas.IntArrayFS;
 import org.apache.uima.cas.LongArrayFS;
 import org.apache.uima.cas.Marker;
-import org.apache.uima.cas.SerialFormat;
 import org.apache.uima.cas.ShortArrayFS;
 import org.apache.uima.cas.SofaFS;
 import org.apache.uima.cas.SofaID;
@@ -77,7 +71,6 @@ import org.apache.uima.cas.StringArrayFS
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.admin.CASAdminException;
-import org.apache.uima.cas.admin.CASFactory;
 import org.apache.uima.cas.admin.CASMgr;
 import org.apache.uima.cas.admin.FSIndexComparator;
 import org.apache.uima.cas.admin.FSIndexRepositoryMgr;
@@ -86,11 +79,25 @@ import org.apache.uima.cas.impl.FSsTobeA
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.cas.text.AnnotationIndex;
 import org.apache.uima.cas.text.Language;
-import org.apache.uima.internal.util.IntVector;
+import org.apache.uima.internal.util.PositiveIntSet;
 import org.apache.uima.internal.util.PositiveIntSet_impl;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.AnnotationBase;
+import org.apache.uima.jcas.cas.BooleanArray;
+import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.CommonArray;
+import org.apache.uima.jcas.cas.DoubleArray;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.FloatArray;
+import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.JavaObjectArray;
+import org.apache.uima.jcas.cas.LongArray;
+import org.apache.uima.jcas.cas.ShortArray;
+import org.apache.uima.jcas.cas.Sofa;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.impl.JCasImpl;
-import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.util.Level;
 import org.apache.uima.util.Misc;
 
@@ -122,15 +129,6 @@ public class CASImpl extends AbstractCas
 
   public static final int FALSE = 0;
 
-  private static final int[] INT0 = new int[0];
-  
-  public static final int DEFAULT_INITIAL_HEAP_SIZE = 500000;
-
-  public static final int DEFAULT_RESET_HEAP_SIZE = 5000000;
-//  no longer used 3/2015
-//  private static final int resetHeapSize = DEFAULT_RESET_HEAP_SIZE;
-
-
   /**
    * The UIMA framework detects (unless disabled, for high performance) updates to indexed FS which update
    * key values used as keys in indexes.  Normally the framework will protect against index corruption by 
@@ -178,21 +176,7 @@ public class CASImpl extends AbstractCas
       Misc.getNoValueSystemProperty(DISABLE_PROTECT_INDEXES) &&
       !IS_REPORT_FS_UPDATE_CORRUPTS_INDEX &&
       !IS_THROW_EXCEPTION_CORRUPT_INDEX;
-  
-  // The offset for the array length cell. An array consists of length+2
-  // number
-  // of cells, where the first cell contains the type, the second one the
-  // length,
-  // and the rest the actual content of the array.
-  private static final int arrayLengthFeatOffset = 1;
-
-  // The number of cells we need to skip to get to the array contents. That
-  // is,
-  // if we have an array starting at addr, the first cell is at
-  // addr+arrayContentOffset.
-  private static final int arrayContentOffset = 2;
-
-  private static final boolean DEFAULT_USE_FS_CACHE = false;
+    
 
   // this next seemingly non-sensical static block
   // is to force the classes needed by Eclipse debugging to load
@@ -203,33 +187,74 @@ public class CASImpl extends AbstractCas
     new DebugFSLogicalStructure();
   }
 
-  private static enum ModifiedHeap { FSHEAP, BYTEHEAP, SHORTHEAP, LONGHEAP };
   // Static classes representing shared instance data
   // - shared data is computed once for all views
+  
+  /**
+   * Journaling changes for computing delta cas.
+   * Each instance represents one or more changes for one feature structure
+   * A particular Feature Structure may have multiple FsChange instances
+   *   but we attempt to minimize this
+   */
+  private static class FsChange {
+    /** ref to the FS being modified */
+    final FeatureStructureImplC fs;
+    /**
+     * which feature (by offset) is modified
+     */
+    final boolean[] intData;
+    /**
+     * which feature (by offset) is modified
+     */
+    final boolean[] refData;
+
+    
+    final PositiveIntSet arrayUpdates; 
 
+    FsChange(FeatureStructureImplC fs) {
+      this.fs = fs;
+      TypeImpl ti = fs._typeImpl;
+      intData = (ti.highestIntOffset == 0) ? null : new boolean[ti.highestIntOffset];
+      refData = (ti.highestRefOffset == 0) ? null : new boolean[ti.highestRefOffset];
+      arrayUpdates = (ti.isArray()) ? new PositiveIntSet_impl() : null;
+    }
+    
+    void addIntData(int v) {
+      intData[v] = true;
+    }
+    
+    void addRefData(int v) {
+      refData[v] = true;
+    }
+    
+    void addArrayData(int v, int nbrOfConsecutive) {
+      for (int i = 0; i < nbrOfConsecutive; i++) {
+        arrayUpdates.add(v++);
+      }
+    }
+  }
+  
   // fields shared among all CASes belong to views of a common base CAS
   private static class SharedViewData {
-
-    final private Heap heap;
+    /**
+     * map from FS ids to FSs.  
+     */
+    final private Id2FS id2fs = new Id2FS();
 
     // private SymbolTable stringTable;
     // private ArrayList stringList;
-    final private StringHeap stringHeap = new StringHeap();
+//    final private StringHeap stringHeap = new StringHeap();
 
-    final private ByteHeap byteHeap = new ByteHeap(); // for storing 8 bit values
+//    final private ByteHeap byteHeap = new ByteHeap(); // for storing 8 bit values
 
-    final private ShortHeap shortHeap = new ShortHeap(); // for storing 16 bit values
+//    final private ShortHeap shortHeap = new ShortHeap(); // for storing 16 bit values
 
-    final private LongHeap longHeap = new LongHeap(); // for storing 64 bit values
-
-    // for efficiency in accessing the begin and end offsets of annotations
-    private int annotFeatOffset_begin;
-    private int annotFeatOffset_end;
+//    final private LongHeap longHeap = new LongHeap(); // for storing 64 bit values
     
     // Base CAS for all views
     final private CASImpl baseCAS;
 
-    private int cache_not_in_index = 0; // a one item cache of a FS not in the index
+    private FeatureStructure cache_not_in_index = null; // a one item cache of a FS guaranteed to not be in any index
     
     private final PositiveIntSet_impl featureCodesInIndexKeys = new PositiveIntSet_impl(); 
     
@@ -243,7 +268,9 @@ public class CASImpl extends AbstractCas
 //    private Map<Integer, CAS> sofaNbr2ViewMap;
     private ArrayList<CAS> sofaNbr2ViewMap;
 
-    // set of instantiated sofaNames
+    /**
+     * a set of instantiated sofaNames
+     */
     private Set<String> sofaNameSet;
 
     // Flag that initial Sofa has been created
@@ -264,28 +291,10 @@ public class CASImpl extends AbstractCas
     // often, the framework disables this before calling users code
     private boolean flushEnabled = true;
 
-    // controls whether Java cover objects for CAS objects,
-    // including JCas objects,
-    // are cached and reused.
-    // If set true, don't also cache the JCas ones - this will
-    // duplicate the space with no benefit
-    private final boolean useFSCache;
-
-    // this is the actual cache. It is simply an array of the same size
-    // as the heap, with the CAS object's addr slot filled with
-    // a (strong) ref to the Java object.
-    // This is a trade off verses using hash tables
-
-    // The actual cache.
-    // TODO implement the resizing algorithm used for the main heap, here too.
-    private FeatureStructure[] fsArray;
-
     // not final because set with reinit deserialization
-    private CASMetadata casMetadata;
+    private TypeSystemImpl tsi;
 
     private ComponentInfo componentInfo;
-
-    private FSGenerator<? extends FeatureStructure>[] localFsGenerators;
     
     /**
      * This tracks the changes for delta cas
@@ -297,19 +306,20 @@ public class CASImpl extends AbstractCas
      * Cas, to support switching from one tracking marker to 
      * another (currently not used, but designed to support
      * Component Journaling).
+     * 
+     * We track changes on a granularity of features
+     *   and for features which are arrays, which element of the array
+     *   (This last to enable efficient delta serializations of 
+     *      giant arrays of things, where you've only updated a few items)
+     *   
+     * The FsChange doesn't store the changed data, only stores the 
+     *   ref info needed to get to what was changed.  
      */
     private MarkerImpl trackingMark;
+   
     
-    private IntVector modifiedPreexistingFSs;
-    
-    private IntVector modifiedFSHeapCells;
-    
-    private IntVector modifiedByteHeapCells;
-    
-    private IntVector modifiedShortHeapCells;
-    
-    private IntVector modifiedLongHeapCells;
-    
+    private List<FsChange> modifiedPreexistingFSs;
+      
     /**
      * This list currently only contains at most 1 element.
      * If Journaling is implemented, it may contain an
@@ -332,16 +342,17 @@ public class CASImpl extends AbstractCas
      */
     private boolean fsTobeAddedbackSingleInUse = false;
     
+    // used to generate FSIDs, increments by 1 for each use.  First id == 1
+    private AtomicInteger fsIdGenerator = new AtomicInteger(0);
+
+    // mostly for debug - counts # times cas is reset
     private final AtomicInteger casResets = new AtomicInteger(0);
     
-    private final int casId;
+    // unique ID for a created CAS view, not updated if CAS is reset and reused
+    private final int casId = casIdProvider.incrementAndGet();
     
-    private SharedViewData(boolean useFSCache, Heap heap, CASImpl baseCAS, CASMetadata casMetadata) {
-      this.useFSCache = useFSCache;
-      this.heap = heap;
+    private SharedViewData(CASImpl baseCAS) {
       this.baseCAS = baseCAS;
-      this.casMetadata = casMetadata;
-      casId = casIdProvider.incrementAndGet();
     }
   }
   
@@ -352,8 +363,11 @@ public class CASImpl extends AbstractCas
   // package protected to let other things share this info
   final SharedViewData svd; // shared view data
   
-  void addbackSingle(int fsAddr) {
-    svd.fsTobeAddedbackSingle.addback(fsAddr);
+  // ----------------------------------------
+  //   accessors for data in SharedViewData
+  // ----------------------------------------
+  void addbackSingle(FeatureStructureImplC fs) {
+    svd.fsTobeAddedbackSingle.addback(fs);
     svd.fsTobeAddedbackSingleInUse = false;
   }
   
@@ -373,9 +387,9 @@ public class CASImpl extends AbstractCas
     svd.featureCodesInIndexKeys.add(featCode);
   }
   
-  void maybeClearCacheNotInIndex(int fsAddr) {
-    if (svd.cache_not_in_index == fsAddr) {
-      svd.cache_not_in_index = 0;
+  void maybeClearCacheNotInIndex(FeatureStructure fs) {
+    if (svd.cache_not_in_index == fs) {
+      svd.cache_not_in_index = null;
     }
   }
   
@@ -386,8 +400,8 @@ public class CASImpl extends AbstractCas
    * Internal use only
    * @param fsAddr the address of the feature structure
    */
-  public void setCacheNotInIndex(int fsAddr) {
-    svd.cache_not_in_index = fsAddr;
+  public void setCacheNotInIndex(FeatureStructure fs) {
+    svd.cache_not_in_index = fs;
   }
 
   // The index repository. Referenced by XmiCasSerializer
@@ -396,28 +410,24 @@ public class CASImpl extends AbstractCas
   // the sofaFS this view is based on
   // SofaFS mySofa;
   /**
-   * The heap address of the sofa FS for this view, or
-   * -1 if the sofa FS is for the initial view, or
-   * 0 if there is no sofa FS - for instance, in the "base cas"
+   * The Feature Structure for the sofa FS for this view, or
+   * null
+   * //-1 if the sofa FS is for the initial view, or
+   * // 0 if there is no sofa FS - for instance, in the "base cas"
    */
-  private int mySofaRef = 0;
+  private Sofa mySofaRef = null;
 
   private JCas jcas = null;
-  
-  private final boolean isUsedJcasCache;
-
-  private final ArrayList<String> getStringList() {
-    ArrayList<String> stringList = new ArrayList<String>();
-    stringList.add(null);
-    int pos = this.getStringHeap().getLeastStringCode();
-    final int end = this.getStringHeap().getLargestStringCode();
-    while (pos <= end) {
-      stringList.add(this.getStringHeap().getStringForCode(pos));
-      ++pos;
-    }
-    return stringList;
-  }
 
+  /**
+   * Copies of frequently accessed data pulled up for 
+   * locality of reference - only an optimization
+   *   - each value needs to be reset appropriately 
+   *   - getters check for null, and if null, do the get.
+   */
+  
+  private TypeSystemImpl tsi;
+  
   /*
    * (non-Javadoc)
    * 
@@ -425,13 +435,6 @@ public class CASImpl extends AbstractCas
    *      Internal use Never called Kept because it's in the interface.
    */
   public void setCAS(CAS cas) {
-
-    // this.indexRepository = ((CASImpl)cas).indexRepository; // only for test
-    // case, others override later
-    // this.svd.casMetadata.fsClassRegistry = casImpl.fsClassReg;
-
-    // initTypeCodeVars();
-    // this.jcas = in.jcas;
   }
 
   // CASImpl(TypeSystemImpl typeSystem) {
@@ -446,10 +449,6 @@ public class CASImpl extends AbstractCas
   // initTypeVariables();
   // }
 
-  public CASImpl(TypeSystemImpl typeSystem, int initialHeapSize, boolean useJcasCache) {
-    this(typeSystem, initialHeapSize, DEFAULT_USE_FS_CACHE, useJcasCache);
-  }
-
   /*
    * Configure a new (base view) CASImpl, **not a new view** typeSystem can be
    * null, in which case a new instance of TypeSystemImpl is set up, but not
@@ -458,9 +457,8 @@ public class CASImpl extends AbstractCas
    * by calling
    */
 
-  CASImpl(TypeSystemImpl typeSystem, int initialHeapSize, boolean useFSCache, boolean useJcasCache) {
+  public CASImpl(TypeSystemImpl typeSystem) {
     super();
-    this.isUsedJcasCache = useJcasCache;
     TypeSystemImpl ts;
     final boolean externalTypeSystem = (typeSystem != null);
 
@@ -471,7 +469,7 @@ public class CASImpl extends AbstractCas
       // FSClassRegistry instances
     }
 
-    this.svd = new SharedViewData(useFSCache, new Heap(initialHeapSize), this, ts.casMetadata);
+    this.svd = new SharedViewData(this);
 //    this.svd.baseCAS = this;
 
 //    this.svd.heap = new Heap(initialHeapSize);
@@ -479,7 +477,7 @@ public class CASImpl extends AbstractCas
     if (externalTypeSystem) {
       commitTypeSystem();
     }
-
+   
     this.svd.sofa2indexMap = new HashMap<Integer, FSIndexRepository>();
     this.svd.sofaNbr2ViewMap = new ArrayList<CAS>();
     this.svd.sofaNameSet = new HashSet<String>();
@@ -489,22 +487,14 @@ public class CASImpl extends AbstractCas
     clearTrackingMarks();
   }
 
-  /**
-   * Constructor. Use only if you want to use the low-level APIs.
-   */
   public CASImpl() {
-    this(DEFAULT_INITIAL_HEAP_SIZE, CASFactory.USE_JCAS_CACHE_DEFAULT);
-  }
-
-  public CASImpl(int initialHeapSize, boolean useJcasCache) {
-    this((TypeSystemImpl) null, initialHeapSize, useJcasCache);
+    this((TypeSystemImpl) null);
   }
 
   // In May 2007, appears to have 1 caller, createCASMgr in Serialization class,
-  // could have
-  // out-side the framework callers because it is public.
+  // could have out-side the framework callers because it is public.
   public CASImpl(CASMgrSerializer ser) {
-    this(ser.getTypeSystem(), DEFAULT_INITIAL_HEAP_SIZE, CASFactory.USE_JCAS_CACHE_DEFAULT);
+    this(ser.getTypeSystem());
     checkInternalCodes(ser);
     // assert(ts != null);
     // assert(getTypeSystem() != null);
@@ -512,34 +502,27 @@ public class CASImpl extends AbstractCas
   }
 
   // Use this when creating a CAS view
-  CASImpl(CASImpl cas, SofaFS aSofa, boolean useJcasCache) {
-    this.isUsedJcasCache = useJcasCache;
+  CASImpl(CASImpl cas, SofaFS aSofa) {
     
     // these next fields are final and must be set in the constructor
     this.svd = cas.svd;
 
-    // this.mySofa = aSofa;
-    if (aSofa != null) {
-      // save address of SofaFS
-      this.mySofaRef = ((FeatureStructureImpl) aSofa).getAddress();
-    } else {
-      // this is the InitialView
-      this.mySofaRef = -1;
-    }
+    this.mySofaRef = (Sofa) aSofa;
 
     // get the indexRepository for this Sofa
-    this.indexRepository = (this.mySofaRef == -1) ? 
+    this.indexRepository = (this.mySofaRef == null) ? 
         (FSIndexRepositoryImpl) cas.getSofaIndexRepository(1) : 
         (FSIndexRepositoryImpl) cas.getSofaIndexRepository(aSofa);
     if (null == this.indexRepository) {
       // create the indexRepository for this CAS
       // use the baseIR to create a lightweight IR copy
-      this.indexRepository = new FSIndexRepositoryImpl(
-                                    this, 
-                                    (FSIndexRepositoryImpl) cas.getBaseIndexRepository());
+      FSIndexRepositoryImpl baseIndexRepo = (FSIndexRepositoryImpl) cas.getBaseIndexRepository();
+      this.indexRepository = new FSIndexRepositoryImpl(this, baseIndexRepo);
+      // the index creation depends on "indexRepository" already being set
+      baseIndexRepo.name2indexMap.keySet().stream().forEach(key -> this.indexRepository.createIndex(baseIndexRepo, key));
       this.indexRepository.commit();
       // save new sofa index
-      if (this.mySofaRef == -1) {
+      if (this.mySofaRef == null) {
         cas.setSofaIndexRepository(1, this.indexRepository);
       } else {
         cas.setSofaIndexRepository(aSofa, this.indexRepository);
@@ -552,21 +535,24 @@ public class CASImpl extends AbstractCas
 
     if (aSofa != null) {
       // save address of SofaFS
-      this.mySofaRef = ((FeatureStructureImpl) aSofa).getAddress();
+      this.mySofaRef = (Sofa) aSofa;
     } else {
       // this is the InitialView
-      this.mySofaRef = -1;
+      this.mySofaRef = null;
     }
 
     // toss the JCas, if it exists
     this.jcas = null;
 
     // create the indexRepository for this Sofa
-    this.indexRepository = new FSIndexRepositoryImpl(this, (FSIndexRepositoryImpl) ((CASImpl) cas)
-        .getBaseIndexRepository());
+    final FSIndexRepositoryImpl baseIndexRepo = (FSIndexRepositoryImpl) ((CASImpl) cas).getBaseIndexRepository();
+    this.indexRepository = new FSIndexRepositoryImpl(this,baseIndexRepo);
+    // the index creation depends on "indexRepository" already being set
+    baseIndexRepo.name2indexMap.keySet().stream().forEach(key -> this.indexRepository.createIndex(baseIndexRepo, key));
+
     this.indexRepository.commit();
     // save new sofa index
-    if (this.mySofaRef == -1) {
+    if (this.mySofaRef == null) {
       ((CASImpl) cas).setSofaIndexRepository(1, this.indexRepository);
     } else {
       ((CASImpl) cas).setSofaIndexRepository(aSofa, this.indexRepository);
@@ -575,17 +561,20 @@ public class CASImpl extends AbstractCas
 
   private void checkInternalCodes(CASMgrSerializer ser) throws CASAdminException {
     if ((ser.topTypeCode > 0)
-        && (ser.topTypeCode != ((TypeImpl) this.svd.casMetadata.ts.getTopType()).getCode())) {
+        && (ser.topTypeCode != ((TypeImpl) getTypeSystemImpl().getTopType()).getCode())) {
       throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
     }
     if (ser.featureOffsets == null) {
       return;
     }
-    if (ser.featureOffsets.length != this.svd.casMetadata.featureOffset.length) {
-      throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
-    }
+//    if (ser.featureOffsets.length != this.svd.casMetadata.featureOffset.length) {
+//      throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
+//    }
+    TypeSystemImpl tsi = getTypeSystemImpl();
     for (int i = 1; i < ser.featureOffsets.length; i++) {
-      if (ser.featureOffsets[i] != this.svd.casMetadata.featureOffset[i]) {
+      FeatureImpl fi = (FeatureImpl) tsi.getFeatureForCode_checked(i);
+      int adjOffset = fi.isInInt ? 0 : fi.getRangeImpl().nbrOfUsedIntDataSlots;
+      if (ser.featureOffsets[i] != (fi.getOffset() + adjOffset)) {
         throw new CASAdminException(CASAdminException.DESERIALIZATION_ERROR);
       }
     }
@@ -596,79 +585,85 @@ public class CASImpl extends AbstractCas
   }
 
   public TypeSystem getTypeSystem() {
-    final TypeSystemImpl ts = this.svd.casMetadata.ts;
-    if (ts.isCommitted()) {
-      return ts;
-    }
-    throw new CASRuntimeException(CASRuntimeException.TYPESYSTEM_NOT_LOCKED);
+    return getTypeSystemImpl();
   }
 
+  public TypeSystemImpl getTypeSystemImpl() {
+    if (tsi == null) {
+      tsi = this.svd.tsi;
+    }
+    return this.tsi;
+  }
+  
   public ConstraintFactory getConstraintFactory() {
     return ConstraintFactory.instance();
   }
 
-  public <T extends FeatureStructure> T  createFS(Type type) {
-    final int typeCode = ((TypeImpl) type).getCode();
-    if (!isCreatableType(typeCode)) {
-      CASRuntimeException e = new CASRuntimeException(CASRuntimeException.NON_CREATABLE_TYPE,
-          new String[] { type.getName(), "CAS.createFS()" });
-      throw e;
+  /**
+   * Create the appropriate Feature Structure Java instance
+   *   - from whatever the generator for this type specifies.
+   *   
+   * @param type the type to create
+   * @return a Java object representing the FeatureStructure impl in Java.
+   */
+  public <T extends TOP> T createFS(Type type) {
+    final TypeImpl ti = (TypeImpl) type;
+    if (!ti.isCreatableAndNotBuiltinArray()) {
+      throw new CASRuntimeException(CASRuntimeException.NON_CREATABLE_TYPE, type.getName(), "CAS.createFS()");
     }
-    return ll_getFSForRef(ll_createFSAnnotCheck(typeCode));
+    return createFSAnnotCheck(ti);
   }
   
-  public int ll_createFSAnnotCheck(int typeCode) {
-    final int addr = ll_createFS(typeCode);
-    final TypeSystemImpl ts = this.svd.casMetadata.ts;
-    final boolean isAnnot = ts.subsumes(TypeSystemImpl.annotBaseTypeCode, typeCode);
-    if (isAnnot && (this == this.getBaseCAS())) {
-      CASRuntimeException e = new CASRuntimeException(
-          CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS,
-          new String[] { ts.ll_getTypeForCode(typeCode).getName() });
-      throw e;
-    }
-    if (isAnnot) {
-      this.setFeatureValueNotJournaled(addr,  TypeSystemImpl.annotSofaFeatCode, this.getSofaRef());
+  
+  private <T extends FeatureStructureImplC> T createFSAnnotCheck(TypeImpl ti) {
+    if (ti.isAnnotationBaseType() && this.isBaseCas()) {    
+        throw new CASRuntimeException(CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS, ti.getName());
     }
-    return addr;
+    T fs = (T) (((FsGenerator)getFsGenerator(ti.getCode())).createFS(ti, this));
+    svd.cache_not_in_index = fs;
+    return fs;
+  } 
+  
+  public int ll_createFSAnnotCheck(int typeCode) {
+    return createFSAnnotCheck(getTypeSystemImpl().getTypeForCode(typeCode))._id;
+  }
+  
+  public CommonArray createArray(int typeCode, int arrayLength) {
+    return   (CommonArray)   (((FsGeneratorArray)getFsGenerator(typeCode))
+        .createFS(getTypeSystemImpl().getTypeForCode(typeCode), this, arrayLength));
   }
-
-  // public FeatureStructure createPermFS(Type type) {
-  // final int addr = createPermFS(((TypeImpl) type).getCode());
-  // return getFSClassRegistry().createFS(addr, this);
-  // }
 
   public ArrayFS createArrayFS(int length) {
     checkArrayPreconditions(length);
-    final int addr = createTempArray(TypeSystemImpl.fsArrayTypeCode, length);
-    return (ArrayFS) createFS(addr);
+    return (ArrayFS)           (((FsGeneratorArray)getFsGenerator(TypeSystemImpl.fsArrayTypeCode))
+        .createFS(getTypeSystemImpl().fsArrayType, this, length));
   }
 
   public IntArrayFS createIntArrayFS(int length) {
     checkArrayPreconditions(length);
-    final int addr = createTempArray(TypeSystemImpl.intArrayTypeCode, length);
-    return (IntArrayFS) createFS(addr);
+    return (IntArrayFS)        (((FsGeneratorArray)getFsGenerator(TypeSystemImpl.intArrayTypeCode))
+        .createFS(getTypeSystemImpl().intArrayType, this, length));
   }
 
   public FloatArrayFS createFloatArrayFS(int length) {
     checkArrayPreconditions(length);
-    final int addr = createTempArray(TypeSystemImpl.floatArrayTypeCode, length);
-    return (FloatArrayFS) createFS(addr);
+    return (FloatArrayFS)      (((FsGeneratorArray)getFsGenerator(TypeSystemImpl.floatArrayTypeCode))
+        .createFS(getTypeSystemImpl().floatArrayType, this, length));
   }
 
   public StringArrayFS createStringArrayFS(int length) {
     checkArrayPreconditions(length);
-    final int addr = createTempArray(TypeSystemImpl.stringArrayTypeCode, length);
-    return (StringArrayFS) createFS(addr);
+    return (StringArrayFS)     (((FsGeneratorArray)getFsGenerator(TypeSystemImpl.stringArrayTypeCode))
+        .createFS(getTypeSystemImpl().stringArrayType, this, length));
   }
-
-  public final void checkArrayPreconditions(int len) throws CASRuntimeException {
-    // Check array size.
-    if (len < 0) {
-      throw new CASRuntimeException(CASRuntimeException.ILLEGAL_ARRAY_SIZE);
-    }
+  
+  public JavaObjectArray createJavaObjectArrayFS(int length) {
+    checkArrayPreconditions(length);
+    return (JavaObjectArray)   (((FsGeneratorArray)getFsGenerator(TypeSystemImpl.stringArrayTypeCode))
+        .createFS(getTypeSystemImpl().javaObjectArrayType, this, length));
   }
 
+
   // return true if only one sofa and it is the default text sofa
   public boolean isBackwardCompatibleCas() {
     // check that there is exactly one sofa
@@ -733,22 +728,33 @@ public class CASImpl extends AbstractCas
     return aSofa;
   }
 
-  SofaFS createSofa(String sofaName, String mimeType) {
-    final int addr = ll_createFS(TypeSystemImpl.sofaTypeCode);
-    final FeatureStructure sofa = ll_getFSForRef(addr);
-    addSofa(sofa, sofaName, mimeType);
-    return (SofaFS) sofa;
+  Sofa createSofa(String sofaName, String mimeType) {
+    return createSofa(++this.svd.viewCount, sofaName, mimeType);
+  }
+  
+  Sofa createSofa(int sofaNum, String sofaName, String mimeType) {  
+    if (this.svd.sofaNameSet.contains(sofaName)) {
+      throw new CASRuntimeException(CASRuntimeException.SOFANAME_ALREADY_EXISTS, sofaName);
+    }
+
+    Sofa sofa = new Sofa(
+        getTypeSystemImpl().sofaType, 
+        this, 
+        sofaNum,
+        sofaName,
+        mimeType);
+    
+    this.getBaseIndexRepository().addFS(sofa);
+    this.svd.sofaNameSet.add(sofaName);
+    return sofa;
   }
 
-  SofaFS createInitialSofa(String mimeType) {
-    final int addr = ll_createFS(TypeSystemImpl.sofaTypeCode);
-    final FeatureStructure sofa = ll_getFSForRef(addr);
-    // final int llsofa = ll_getFSRef(sofa);
-    ll_setIntValue(/* llsofa */addr, TypeSystemImpl.sofaNumFeatCode, 1);
-    addSofa(sofa, CAS.NAME_DEFAULT_SOFA, mimeType);
+  Sofa createInitialSofa(String mimeType) { 
+    Sofa sofa = createSofa(1, CAS.NAME_DEFAULT_SOFA, mimeType);
+
     registerInitialSofa();
-    this.mySofaRef = /* ((FeatureStructureImpl)sofa).getAddress() */addr;
-    return (SofaFS) sofa;
+    this.mySofaRef = sofa;
+    return sofa;
   }
 
   void registerInitialSofa() {
@@ -759,23 +765,6 @@ public class CASImpl extends AbstractCas
     return this.svd.initialSofaCreated;
   }
 
-  // Internal use only
-  public void addSofa(FeatureStructure sofa, String sofaName, String mimeType) {
-    if (this.svd.sofaNameSet.contains(sofaName)) {
-      CASRuntimeException e = new CASRuntimeException(CASRuntimeException.SOFANAME_ALREADY_EXISTS,
-          new String[] { sofaName });
-      throw e;
-    }
-    final int llsofa = ll_getFSRef(sofa);
-    if (0 == ll_getIntValue(llsofa, TypeSystemImpl.sofaNumFeatCode)) {
-      ll_setIntValue(llsofa, TypeSystemImpl.sofaNumFeatCode, ++this.svd.viewCount);
-    }
-    ll_setStringValue(llsofa, TypeSystemImpl.sofaIdFeatCode, sofaName);
-    ll_setStringValue(llsofa, TypeSystemImpl.sofaMimeFeatCode, mimeType);
-    this.getBaseIndexRepository().addFS(sofa);
-    this.svd.sofaNameSet.add(sofaName);
-  }
-
   /**
    * @deprecated
    */
@@ -787,17 +776,13 @@ public class CASImpl extends AbstractCas
 
   private SofaFS getSofa(String sofaName) {
     FSIterator<SofaFS> iterator = this.svd.baseCAS.getSofaIterator();
-    while (iterator.isValid()) {
-      SofaFS sofa = iterator.get();
-      if (sofaName.equals(getStringValue(((FeatureStructureImpl) sofa).getAddress(),
-          TypeSystemImpl.sofaIdFeatCode))) {
+    while (iterator.hasNext()) {
+      SofaFS sofa = iterator.next();
+      if (sofaName.equals(sofa.getSofaID())) {
         return sofa;
       }
-      iterator.moveToNext();
     }
-    CASRuntimeException e = new CASRuntimeException(CASRuntimeException.SOFANAME_NOT_FOUND,
-        new String[] { sofaName });
-    throw e;
+    throw new CASRuntimeException(CASRuntimeException.SOFANAME_NOT_FOUND, sofaName);
   }
 
   SofaFS getSofa(int sofaRef) {
@@ -827,129 +812,108 @@ public class CASImpl extends AbstractCas
 
   @SuppressWarnings("unchecked")
   public FSIterator<SofaFS> getSofaIterator() {
-    FSIndex<SofaFS> sofaIndex =  (FSIndex<SofaFS>) ( FSIndex<?>) this.svd.baseCAS.indexRepository.getIndex(CAS.SOFA_INDEX_NAME);
+    FSIndex<SofaFS> sofaIndex = this.svd.baseCAS.indexRepository.getIndex(CAS.SOFA_INDEX_NAME);
     return sofaIndex.iterator();
   }
 
   // For internal use only
-  public void setSofaFeat(int addr, int sofa) {
-    // never an index key
-    setFeatureValueNoIndexCorruptionCheck(addr, TypeSystemImpl.annotSofaFeatCode, sofa);
-  }
-
-  // For internal use only
-  public int getSofaFeat(int addr) {
-    return getFeatureValue(addr, TypeSystemImpl.annotSofaFeatCode);
-  }
-
-  // For internal use only
-  public int getSofaRef() {
-    if (this.mySofaRef == -1) {
+  public Sofa getSofaRef() {
+    if (this.mySofaRef == null) {
       // create the SofaFS for _InitialView ...
       // ... and reset mySofaRef to point to it
-      this.mySofaRef = this.createInitialSofa(null).hashCode();
+      this.mySofaRef = this.createInitialSofa(null);
     }
     return this.mySofaRef;
   }
 
   // For internal use only
   public InputStream getSofaDataStream(SofaFS aSofa) {
-    try {
+        
+    Sofa sofa = (Sofa) aSofa;    
+    String sd = sofa.getLocalStringData();
 
-      if (null != aSofa.getLocalStringData()) {
-        ByteArrayInputStream bis = new ByteArrayInputStream(aSofa.getLocalStringData().getBytes(
-            "UTF-8"));
-        return bis;
-      } else if (null != aSofa.getLocalFSData()) {
-        FeatureStructureImpl fs = (FeatureStructureImpl) aSofa.getLocalFSData();
-
-        int arrayStart = 0;
-        int arraySize = this.ll_getArraySize(fs.getAddress());
-        ByteBuffer buf = null;
-        Type type = fs.getType();
-        if (type.getName().equals(CAS.TYPE_NAME_STRING_ARRAY)) {
-          StringBuffer sb = new StringBuffer();
-          for (int i=0; i<((StringArrayFS)fs).size(); i++) {
-            if (i==0) {
-              sb.append( ((StringArrayFS)fs).get(i) );
-            } else {
-              sb.append( "\n" + ((StringArrayFS)fs).get(i) );
-            }
-          }
-          ByteArrayInputStream bis = new ByteArrayInputStream( sb.toString().getBytes("UTF-8") );
-          return bis;
-        } else if (type.getName().equals(CAS.TYPE_NAME_INTEGER_ARRAY)) {
-          arrayStart = getArrayStartAddress(fs.getAddress());
-          buf = ByteBuffer.allocate(arraySize * 4);
-          IntBuffer intbuf = buf.asIntBuffer();
-          intbuf.put(this.getHeap().heap, arrayStart, arraySize);
-          ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
-          return bis;
-        } else if (type.getName().equals(CAS.TYPE_NAME_FLOAT_ARRAY)) {
-          arrayStart = getArrayStartAddress(fs.getAddress());
-          buf = ByteBuffer.allocate(arraySize * 4);
-          FloatBuffer floatbuf = buf.asFloatBuffer();
-          float[] floatArray = new float[arraySize];
-          for (int i = arrayStart; i < arrayStart + arraySize; i++) {
-            floatArray[i - arrayStart] = Float.intBitsToFloat(this.getHeap().heap[i]);
-          }
-          floatbuf.put(floatArray);
-          ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
-          return bis;
-        } else if (type.getName().equals(CAS.TYPE_NAME_BOOLEAN_ARRAY)
-            || type.getName().equals(CAS.TYPE_NAME_BYTE_ARRAY)) {
-          arrayStart = this.getHeap().heap[getArrayStartAddress(fs.getAddress())];
-          buf = ByteBuffer.allocate(arraySize);
-          buf.put(this.getByteHeap().heap, arrayStart, arraySize);
-          ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
-          return bis;
-        } else if (type.getName().equals(CAS.TYPE_NAME_SHORT_ARRAY)) {
-          arrayStart = this.getHeap().heap[getArrayStartAddress(fs.getAddress())];
-          buf = ByteBuffer.allocate(arraySize * 2);
-          ShortBuffer shortbuf = buf.asShortBuffer();
-          shortbuf.put(this.getShortHeap().heap, arrayStart, arraySize);
-
-          ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
-          return bis;
-        } else if (type.getName().equals(CAS.TYPE_NAME_LONG_ARRAY)) {
-          arrayStart = this.getHeap().heap[getArrayStartAddress(fs.getAddress())];
-          buf = ByteBuffer.allocate(arraySize * 8);
-          LongBuffer longbuf = buf.asLongBuffer();
-          longbuf.put(this.getLongHeap().heap, arrayStart, arraySize);
-          ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
-          return bis;
-        } else if (type.getName().equals(CAS.TYPE_NAME_DOUBLE_ARRAY)) {
-          arrayStart = this.getHeap().heap[getArrayStartAddress(fs.getAddress())];
-          buf = ByteBuffer.allocate(arraySize * 8);
-          DoubleBuffer doublebuf = buf.asDoubleBuffer();
-          double[] doubleArray = new double[arraySize];
-          for (int i = arrayStart; i < arrayStart + arraySize; i++) {
-            doubleArray[i - arrayStart] = Double.longBitsToDouble(this.getLongHeap().heap[i]);
+    if (null != sd) {
+      ByteArrayInputStream bis;
+      try {
+        bis = new ByteArrayInputStream(sd.getBytes("UTF-8"));
+      } catch (UnsupportedEncodingException e) {
+        throw new RuntimeException(e);  // never happen 
+      }
+      return bis;
+      
+    } else if (null != aSofa.getLocalFSData()) {
+      TOP fs = (TOP) sofa.getLocalFSData();
+      ByteBuffer buf = null;
+      switch(fs._getTypeCode()) {
+      
+      case TypeSystemImpl.stringArrayTypeCode: {
+        StringBuilder sb = new StringBuilder();
+        final String[] theArray = ((StringArray) fs)._getTheArray();
+        
+        for (int i = 0; i < theArray.length; i++) {
+          if (i != 0) {
+            sb.append('\n');
           }
-          doublebuf.put(doubleArray);
-          ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
-          return bis;
+          sb.append(theArray[i]);
+        }
+        try {
+          return new ByteArrayInputStream(sb.toString().getBytes("UTF-8") );
+        } catch (UnsupportedEncodingException e) {
+          throw new RuntimeException(e);  // never happen 
         }
+      }
+      case TypeSystemImpl.intArrayTypeCode: {
+        final int[] theArray = ((IntegerArray) fs)._getTheArray();
+        (buf = ByteBuffer.allocate(theArray.length * 4)).asIntBuffer().put(theArray, 0, theArray.length);
+        break;
+      }
+        
+      case TypeSystemImpl.floatArrayTypeCode: {
+        final float[] theArray = ((FloatArray) fs)._getTheArray();
+        (buf = ByteBuffer.allocate(theArray.length * 4)).asFloatBuffer().put(theArray, 0, theArray.length);
+        break;
+      }
+        
+      case TypeSystemImpl.byteArrayTypeCode: {
+        final byte[] theArray = ((ByteArray) fs)._getTheArray();
+        buf = ByteBuffer.wrap(theArray);
+        break;
+      }
+
+      case TypeSystemImpl.shortArrayTypeCode: {
+        final short[] theArray = ((ShortArray) fs)._getTheArray();
+        (buf = ByteBuffer.allocate(theArray.length * 2)).asShortBuffer().put(theArray, 0, theArray.length);
+        break;
+      }
 
-      } else if (null != aSofa.getSofaURI()) {
-        URL url = new URL(aSofa.getSofaURI());
+      case TypeSystemImpl.longArrayTypeCode: {
+        final long[] theArray = ((LongArray) fs)._getTheArray();
+        (buf = ByteBuffer.allocate(theArray.length * 8)).asLongBuffer().put(theArray, 0, theArray.length);
+         break;
+      }
+         
+      case TypeSystemImpl.doubleArrayTypeCode: {
+        final double[] theArray = ((DoubleArray) fs)._getTheArray();
+        (buf = ByteBuffer.allocate(theArray.length * 8)).asDoubleBuffer().put(theArray, 0, theArray.length);
+        break;
+      }
+
+      default:
+        assert(false);
+      }
+      
+      ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
+      return bis;
+
+    } else if (null != aSofa.getSofaURI()) {
+      URL url;
+      try {
+        url = new URL(aSofa.getSofaURI());
         return url.openStream();
-      } else {
-        return null;
+      } catch (IOException exc) {
+        throw new CASRuntimeException(CASRuntimeException.SOFADATASTREAM_ERROR, exc.getMessage());
       }
-    } catch (MalformedURLException exc) {
-      CASRuntimeException e = new CASRuntimeException(CASRuntimeException.SOFADATASTREAM_ERROR,
-          new String[] { exc.getMessage() });
-      throw e;
-    } catch (CASRuntimeException exc) {
-      CASRuntimeException e = new CASRuntimeException(CASRuntimeException.SOFADATASTREAM_ERROR,
-          new String[] { exc.getMessage() });
-      throw e;
-    } catch (IOException exc) {
-      CASRuntimeException e = new CASRuntimeException(CASRuntimeException.SOFADATASTREAM_ERROR,
-          new String[] { exc.getMessage() });
-      throw e;
-    }
+    } 
     return null;
   }
 
@@ -959,7 +923,7 @@ public class CASImpl extends AbstractCas
   }
 
   public void commitTypeSystem() {
-    final TypeSystemImpl ts = this.svd.casMetadata.ts;
+    final TypeSystemImpl ts = getTypeSystemImpl();
     // For CAS pools, the type system could have already been committed
     // Skip the initFSClassReg if so, because it may have been updated to a JCas
     // version by another CAS processing in the pool
@@ -970,27 +934,10 @@ public class CASImpl extends AbstractCas
     // at the same time
     synchronized (ts) {
       if (!ts.isCommitted()) {
-        this.svd.casMetadata.ts.commit();
-        initFSClassRegistry();
-        FSClassRegistry fscr = getFSClassRegistry();
-        // save for the case of non=jcas pipeline with a jcas pear in the middle
-        // - this
-        // allows subsequent downstream annotators to run without jcas
-        fscr.saveGeneratorsForClassLoader(this.svd.previousJCasClassLoader, fscr
-            .getBaseGenerators());
+        ts.commit();
       }
-    }
-    setLocalFsGenerators(this.svd.casMetadata.fsClassRegistry.getBaseGenerators());
-    // After the type system has been committed, we can create the
-    // index repository.
+    }       
     createIndexRepository();
-    svd.annotFeatOffset_begin = getFeatureOffset(TypeSystemImpl.startFeatCode);
-    svd.annotFeatOffset_end   = getFeatureOffset(TypeSystemImpl.endFeatCode);
-  }
-
-  // internal use, public for cross class ref
-  public void setLocalFsGenerators(FSGenerator<? extends FeatureStructure>[] fsGenerators) {
-    this.svd.localFsGenerators = fsGenerators;
   }
 
   private void createIndexRepository() {
@@ -1026,7 +973,7 @@ public class CASImpl extends AbstractCas
    * @see org.apache.uima.cas.admin.CASMgr#getTypeSystemMgr()
    */
   public TypeSystemMgr getTypeSystemMgr() {
-    return this.svd.casMetadata.ts;
+    return getTypeSystemImpl();
   }
 
   public void reset() {
@@ -1067,16 +1014,17 @@ public class CASImpl extends AbstractCas
 
   public void resetNoQuestions() {
     svd.casResets.incrementAndGet();
+    svd.fsIdGenerator.set(0);
     if (trace) {
       System.out.println("CAS Reset in thread " + Thread.currentThread().getName() +
           " for CasId = " + getCasId() + ", new reset count = " + svd.casResets.get());
     }
     int numViews = this.getBaseSofaCount();
-    // Flush indexRepository for all Sofa
+    // Flush indexRepository for all views
     for (int view = 1; view <= numViews; view++) {
-      CAS tcas = (view == 1) ? getInitialView() : getView(view);
+      CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getView(view));
       if (tcas != null) {
-        ((CASImpl) tcas).resetView();
+        tcas.resetView();
 
         // mySofaRef = -1 is a flag in initial view that sofa has not been set.
         // For the initial view, it is possible to not have a sofa - it is set
@@ -1084,16 +1032,10 @@ public class CASImpl extends AbstractCas
         // all other views always have a sofa set. The sofaRef is set to 0,
         // but will be set to the actual sofa addr in the cas when the view is
         // initialized.
-        ((CASImpl) tcas).mySofaRef = (1 == view) ? -1 : 0;
+        
+        tcas.mySofaRef = null;  // was in v2: (1 == view) ? -1 : 0;
       }
     }
-    this.getHeap().reset(/*this.getHeap().getHeapSize() > CASImpl.resetHeapSize*/);
-
-    resetStringTable();
-
-    this.getByteHeap().reset();
-    this.getShortHeap().reset();
-    this.getLongHeap().reset();
 
     this.indexRepository.flush();  // for base view, other views flushed above
     this.svd.sofaNameSet = new HashSet<String>();
@@ -1101,16 +1043,11 @@ public class CASImpl extends AbstractCas
     // always an Initial View now!!!
     this.svd.viewCount = 1;
 
-    if (null != this.svd.casMetadata.fsClassRegistry) {
-      // needed only if caching non-JCas Java cover objects
-      // NOTE: This code may not work - has not been maintained
-      this.svd.casMetadata.fsClassRegistry.flush();
-    }
     if (this.jcas != null) {
       JCasImpl.clearData(this);
     }
     clearTrackingMarks();
-    this.svd.cache_not_in_index = 0;
+    this.svd.cache_not_in_index = null;
     this.svd.fssTobeAddedback.clear();
     this.svd.fssTobeAddedback.trimToSize();
   }
@@ -1145,19 +1082,10 @@ public class CASImpl extends AbstractCas
     this.svd.baseCAS.getBaseIndexRepository().addFS(sofa);
   }
 
-  void registerView(SofaFS aSofa) {
-    this.mySofaRef = ((FeatureStructureImpl) aSofa).getAddress();
+  void registerView(Sofa aSofa) {
+    this.mySofaRef = aSofa;
   }
 
-  public void reinit(CASSerializer ser) {
-    if (this != this.svd.baseCAS) {
-      this.svd.baseCAS.reinit(ser);
-      return;
-    }
-    this.resetNoQuestions();
-    reinit(ser.getHeapMetadata(), ser.getHeapArray(), ser.getStringTable(), ser.getFSIndex(), ser
-        .getByteArray(), ser.getShortArray(), ser.getLongArray());
-  }
 
   /**
    * @see org.apache.uima.cas.CAS#fs2listIterator(FSIterator)
@@ -1176,97 +1104,20 @@ public class CASImpl extends AbstractCas
     throw new CASAdminException(CASAdminException.MUST_COMMIT_INDEX_REPOSITORY);
   }
 
-  void resetStringTable() {
-    this.getStringHeap().reset();
-  }
-
   // public void setFSClassRegistry(FSClassRegistry fsClassReg) {
   // this.svd.casMetadata.fsClassRegistry = fsClassReg;
   // }
 
-  private void initFSClassRegistry() {
-    final TypeSystemImpl ts = this.svd.casMetadata.ts;
-    // System.out.println("Initializing FSClassRegistry");
-    this.svd.casMetadata.fsClassRegistry.initGeneratorArray();
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.fsArrayType, new ArrayFSGenerator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.intArrayType, IntArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.floatArrayType, FloatArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.stringArrayType, StringArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.sofaType, SofaFSImpl
-        .getSofaFSGenerator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.annotBaseType, AnnotationBaseImpl
-        .getAnnotationGenerator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.annotType, AnnotationImpl
-        .getAnnotationGenerator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.byteArrayType, ByteArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.booleanArrayType, BooleanArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.shortArrayType, ShortArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.longArrayType, LongArrayFSImpl
-        .generator());
-    this.svd.casMetadata.fsClassRegistry.addClassForType(ts.doubleArrayType, DoubleArrayFSImpl
-        .generator());
-
-    // assert(fsClassReg != null);
-  }
-
+  
   // JCasGen'd cover classes use this to add their generators to the class
   // registry
   // Note that this now (June 2007) a no-op for JCasGen'd generators
   // Also used in JCas initialization to copy-down super generators to subtypes
   // as needed
-  public FSClassRegistry getFSClassRegistry() // for JCas integration
-  {
-    return this.svd.casMetadata.fsClassRegistry;
+  public FSClassRegistry getFSClassRegistry() {
+    return getTypeSystemImpl().getFSClassRegistry();
   }
 
-  public void reinit(CASCompleteSerializer casCompSer) {
-    if (this != this.svd.baseCAS) {
-      this.svd.baseCAS.reinit(casCompSer);
-      return;
-    }
-    TypeSystemImpl ts = casCompSer.getCASMgrSerializer().getTypeSystem();
-    this.svd.casMetadata = ts.casMetadata;
-    commitTypeSystem();
-
-    // reset index repositories -- wipes out Sofa index
-    this.indexRepository = casCompSer.getCASMgrSerializer().getIndexRepository(this);
-    this.indexRepository.commit();
-
-    // get handle to existing initial View
-    CAS initialView = this.getInitialView();
-
-    // throw away all other View information as the CAS definition may have
-    // changed
-    this.svd.sofa2indexMap.clear();
-    this.svd.sofaNbr2ViewMap.clear();
-    this.svd.viewCount = 0;
-
-    // freshen the initial view
-    ((CASImpl) initialView).refreshView(this.svd.baseCAS, null);
-    setViewForSofaNbr(1, initialView);
-    this.svd.viewCount = 1;
-
-    // deserialize heap
-    CASSerializer casSer = casCompSer.getCASSerializer();
-    reinit(casSer.getHeapMetadata(), casSer.getHeapArray(), casSer.getStringTable(), casSer
-        .getFSIndex(), casSer.getByteArray(), casSer.getShortArray(), casSer.getLongArray());
-
-    // we also need to throw away the JCAS. A new JCAS will be created on
-    // the next
-    // call to getJCas(). As with the CAS, we are counting on the fact that
-    // this happens only in a service, where JCAS handles are not held on
-    // to.
-    this.jcas = null;
-    // this.sofa2jcasMap.clear();
-    
-    clearTrackingMarks();
-  }
   
   private void clearTrackingMarks() {
     // resets all markers that might be held by things outside the Cas
@@ -1280,1108 +1131,299 @@ public class CASImpl extends AbstractCas
 
     this.svd.trackingMark = null;
     this.svd.modifiedPreexistingFSs = null;
-    this.svd.modifiedFSHeapCells = null;
-    this.svd.modifiedByteHeapCells = null;
-    this.svd.modifiedShortHeapCells = null;
-    this.svd.modifiedLongHeapCells = null;
     this.svd.trackingMarkList = null;     
   }
 
-  void reinit(int[] heapMetadata, int[] heapArray, String[] stringTable, int[] fsIndex,
-      byte[] byteHeapArray, short[] shortHeapArray, long[] longHeapArray) {
-    createStringTableFromArray(stringTable);
-    this.getHeap().reinit(heapMetadata, heapArray);
-    if (byteHeapArray != null) {
-      this.getByteHeap().reinit(byteHeapArray);
-    }
-    if (shortHeapArray != null) {
-      this.getShortHeap().reinit(shortHeapArray);
-    }
-    if (longHeapArray != null) {
-      this.getLongHeap().reinit(longHeapArray);
+  /**
+   * 
+   * @param fs the Feature Structure being updated
+   * @param fi the Feature of fs being updated, or null if fs is an array 
+   * @param arrayIndexStart
+   * @param nbrOfConsecutive
+   */
+  private void logFSUpdate(FeatureStructureImplC fs, FeatureImpl fi, int arrayIndexStart, int nbrOfConsecutive) {
+    if (this.svd.trackingMark != null && !this.svd.trackingMark.isNew(fs.get_id())) {
+      //log the FS
+      
+      //create or use last FsChange element
+      FsChange change = null;
+
+      final List<FsChange> changes = this.svd.modifiedPreexistingFSs;
+      final int nbrOfChanges = changes.size(); 
+      if (nbrOfChanges > 0) {
+        change =  changes.get(nbrOfChanges - 1); // get last element
+      }
+
+      // only create a new FsChange element if needed
+      if (change.fs != fs) {
+        this.svd.modifiedPreexistingFSs.add(change = new FsChange(fs));
+      }
+            
+      if (fi == null) {
+        if (arrayIndexStart < 0) {
+          throw new UIMARuntimeException(UIMARuntimeException.INTERNAL_ERROR);
+        }
+        change.addArrayData(arrayIndexStart, nbrOfConsecutive);
+      } else {
+        if (fi.isInInt) {
+          change.addIntData(fi.getOffset());  
+        } else {
+          change.addRefData(fi.getOffset());
+        }
+      }
     }
+  }
+    
+  private void logFSUpdate(FeatureStructureImplC fs, FeatureImpl fi) {
+    logFSUpdate(fs, fi, -1, -1); // indicate non-array call
+  }
 
-    reinitIndexedFSs(fsIndex);
+  
+  /**
+   * This is your link from the low-level API to the high-level API. Use this
+   * method to create a FeatureStructure object from an address. Note that the
+   * reverse is not supported by public APIs (i.e., there is currently no way to
+   * get at the address of a FeatureStructure. Maybe we will need to change
+   * that.
+   * 
+   * The "create" in "createFS" is a misnomer - the FS must already be created.
+   * 
+   * @param id The id of the feature structure to be created.
+   * @param <T> The Java class associated with this feature structure
+   * @return A FeatureStructure object.
+   */
+  public <T extends TOP> T createFS(int id) {
+    return getFsFromId_checked(id);
+  }
+  
+  public int getArraySize(CommonArrayFS fs) {
+    return fs.size();
+  }
+  
+  public int ll_getArraySize(int id) {
+    return getArraySize(getFsFromId_checked(id));
+  }
+      
+  /*
+   * Support code for JCas setters
+   */
+   
+  public void setWithCheckAndJournal(FeatureStructureImplC fs, int featCode, Runnable setter) {
+    boolean wasRemoved = checkForInvalidFeatureSetting(fs, featCode);
+    setter.run();
+    if (wasRemoved) {
+      maybeAddback(fs);
+    }
+    maybeLogUpdate(fs, featCode);
   }
   
+//  public void setWithCheck(FeatureStructureImplC fs, FeatureImpl feat, Runnable setter) {
+//    boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat);
+//    setter.run();
+//    if (wasRemoved) {
+//      maybeAddback(fs);
+//    }
+//  }
   
+  public void setWithJournal(FeatureStructureImplC fs, FeatureImpl fi, Runnable setter) {
+    setter.run();
+    maybeLogUpdate(fs, fi);
+  }
+
   /**
-   * Binary Deserializaion Support
-   * An instance of this class is made for every reinit operation 
-   *
+   * 
+   * @param fs the Feature Structure being updated
+   * @param feat the feature of fs being updated, or null if fs is a primitive array
+   * @param i the index being updated
    */
-  private class BinDeserSupport {
-    
-    private int fsStartAddr;
-    private int fsEndAddr;
-    /**
-     * An array of all the starting indexes of the FSs on the old/prev heap
-     * (below the mark, for delta CAS, plus one last one (one beyond the end)
-     */
-    private int[] fssAddrArray;
-    private int fssIndex;
-    private int lastRemovedFsAddr;
-    // feature codes - there are exactly the same number as their are features
-    private int[] featCodes;
-    private FSsTobeAddedback tobeAddedback = FSsTobeAddedback.createSingle();
+  public void maybeLogArrayUpdate(FeatureStructureImplC fs, FeatureImpl feat, int i) {
+    if (this.svd.trackingMark != null) {
+      this.logFSUpdate(fs, feat, 1, 1);
+    }    
+  }
+  
+  public void maybeLogUpdate(FeatureStructureImplC fs, FeatureImpl feat) {
+    if (this.svd.trackingMark != null) {
+      this.logFSUpdate(fs, feat);
+    }
+  }
+
+  public void maybeLogUpdate(FeatureStructureImplC fs, int featCode) {
+    if (this.svd.trackingMark != null) {
+      this.logFSUpdate(fs, getTypeSystemImpl().getFeatureForCode(featCode));
+    }
   }
     
   /**
-   * --------------------------------------------------------------------- see
-   * Blob Format in CASSerializer
+   * Common setter code for features in Feature Structures
    * 
-   * This reads in and deserializes CAS data from a stream. Byte swapping may be
-   * needed if the blob is from C++ -- C++ blob serialization writes data in
-   * native byte order.
-   * 
-   * @param istream -
-   * @return -
-   * @throws CASRuntimeException wraps IOException
+   * These come in two styles:  one with int values, one with Object values
+   */
+  
+  /**
+   * This is the common point where all operations to set features come through
+   * It implements the check for invalid feature setting and potentially the addback.
+   *  
+   * @param fs      the feature structure
+   * @param feat    the feature to set
+   * @param value -
    */
+  
+  public void setFeatureValue(FeatureStructureImplC fs, FeatureImpl feat, int value) {
+    boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat.getCode());
+    fs._intData[feat.getAdjustedOffset()] = value;
+    if (wasRemoved) {
+      maybeAddback(fs);
+    }
+    maybeLogUpdate(fs, feat);
+  }
 
-  public SerialFormat reinit(InputStream istream) throws CASRuntimeException {
-    if (this != this.svd.baseCAS) {
-      return this.svd.baseCAS.reinit(istream);
+  /**
+   * version for longs, uses two slots
+   * @param fs      the feature structure
+   * @param feat    the feature to set
+   * @param value -
+   */
+  public void setFeatureValue(FeatureStructureImplC fs, FeatureImpl feat, int v1, int v2) {
+    boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat.getCode());
+    int offset = feat.getAdjustedOffset();
+    fs._intData[offset] = v1;
+    fs._intData[offset + 1] = v2;
+    if (wasRemoved) {
+      maybeAddback(fs);
     }
-   
-    final DataInputStream dis = (istream instanceof DataInputStream) ?  
-       (DataInputStream) istream : new DataInputStream(istream);
-
-    final BinDeserSupport bds = new BinDeserSupport();
-    try {
-      // key
-      // determine if byte swap if needed based on key
-      byte[] bytebuf = new byte[4];
-      bytebuf[0] = dis.readByte(); // U
-      bytebuf[1] = dis.readByte(); // I
-      bytebuf[2] = dis.readByte(); // M
-      bytebuf[3] = dis.readByte(); // A
-
-      final boolean swap = (bytebuf[0] != 85);
-
-      // version      
-      // version bit in 2's place indicates this is in delta format.
-      final int version = readInt(dis, swap);      
-      final boolean delta = ((version & 2) == 2);
-      
-      if (!delta) {
-        this.resetNoQuestions();
-      }
-      
-      if (0 != (version & 4)) {
-        final int compressedVersion = readInt(dis, swap);
-        if (compressedVersion == 0) {
-          (new BinaryCasSerDes4(this.getTypeSystemImpl(), false)).deserialize(this, dis, delta);
-          return SerialFormat.COMPRESSED;
-        } else {
-//          throw new CASRuntimeException(CASRuntimeException.DESERIALIZING_COMPRESSED_BINARY_UNSUPPORTED);
-          // Only works for cases where the type systems match, and delta is false.
-          try {
-            (new BinaryCasSerDes6(this)).deserializeAfterVersion(dis, delta, AllowPreexistingFS.allow);
-          } catch (ResourceInitializationException e) {
-            throw new CASRuntimeException(CASRuntimeException.DESERIALIZING_COMPRESSED_BINARY_UNSUPPORTED, null, e);
-          }
-          return SerialFormat.COMPRESSED_FILTERED;
-        }
-      }
-      
-      // main fsheap
-      final int fsheapsz = readInt(dis, swap);
-      
-      int startPos = 0;
-      if (!delta) {
-        this.getHeap().reinitSizeOnly(fsheapsz);
-      } else {
-    	startPos = this.getHeap().getNextId();
-    	this.getHeap().grow(fsheapsz);
-      }
-            
-      // add new heap slots
-      for (int i = startPos; i < fsheapsz+startPos; i++) {
-        this.getHeap().heap[i] = readInt(dis, swap);
-      }
-      
-      // string heap
-      int stringheapsz = readInt(dis, swap);
-
-      final StringHeapDeserializationHelper shdh = new StringHeapDeserializationHelper();
-      
-      shdh.charHeap = new char[stringheapsz];
-      for (int i = 0; i < stringheapsz; i++) {
-        shdh.charHeap[i] = (char) readShort(dis, swap);
-      }
-      shdh.charHeapPos = stringheapsz;
-
-      // word alignment
-      if (stringheapsz % 2 != 0) {
-        dis.readChar();
-      }
-
-      // string ref heap
-      int refheapsz = readInt(dis, swap);
-
-      refheapsz--;
-      refheapsz = refheapsz / 2;
-      refheapsz = refheapsz * 3;
-
-      // read back into references consisting to three ints
-      // --stringheap offset,length, stringlist offset
-      shdh.refHeap = new int[StringHeapDeserializationHelper.FIRST_CELL_REF + refheapsz];
-
-      dis.readInt(); // 0
-      for (int i = shdh.refHeapPos; i < shdh.refHeap.length; i += StringHeapDeserializationHelper.REF_HEAP_CELL_SIZE) {
-        shdh.refHeap[i + StringHeapDeserializationHelper.CHAR_HEAP_POINTER_OFFSET] = readInt(dis, swap);
-        shdh.refHeap[i + StringHeapDeserializationHelper.CHAR_HEAP_STRLEN_OFFSET] = readInt(dis, swap);
-        shdh.refHeap[i + StringHeapDeserializationHelper.STRING_LIST_ADDR_OFFSET] = 0;
-      }
-      shdh.refHeapPos = refheapsz + StringHeapDeserializationHelper.FIRST_CELL_REF;
-      
-      this.getStringHeap().reinit(shdh, delta);
-      
-      //if delta, handle modified fs heap cells
-      if (delta) {
-        
-        final int heapsize = this.getHeap().getNextId();
-        
-        // compute table of ints which correspond to FSs in the existing heap
-        // we need this because the list of modifications is just arbitrary single words on the heap
-        //   at arbitrary boundaries
-        IntVector fss = new IntVector(Math.max(128, heapsize >> 6));
-        int fsAddr;
-        for (fsAddr = 1; fsAddr < heapsize; fsAddr = getNextFsHeapAddr(fsAddr)) {          
-          fss.add(fsAddr);
-        }
-        fss.add(fsAddr);  // add trailing value
-        bds.fssAddrArray = fss.toArray();
-        
-        int fsmodssz = readInt(dis, swap);
-        bds.fsStartAddr = -1;        
-        
-        // loop over all heap modifications to existing FSs
-        
-        // first disable auto addbacks for index corruption - this routine is handling that
-        svd.fsTobeAddedbackSingleInUse = true;  // sorry, a bad hack...
-        try {
-          for (int i = 0; i < fsmodssz; i++) {
-            final int heapAddrBeingModified = readInt(dis, swap);
-            maybeAddBackAndRemoveFs(heapAddrBeingModified, bds);       
-            this.getHeap().heap[heapAddrBeingModified] = readInt(dis, swap);
-          }
-          bds.tobeAddedback.addback(bds.lastRemovedFsAddr);
-          bds.fssAddrArray = null;  // free storage
-        } finally {
-          svd.fsTobeAddedbackSingleInUse = false;
-        }
-      }
-
-      // indexed FSs
-      int fsindexsz = readInt(dis, swap);
-      int[] fsindexes = new int[fsindexsz];
-      for (int i = 0; i < fsindexsz; i++) {
-        fsindexes[i] = readInt(dis, swap);
-      }
-
-      // build the index
-      if (delta) {
-    	reinitDeltaIndexedFSs(fsindexes);  
-      } else {
-        reinitIndexedFSs(fsindexes);
-      }
-      
-      // byte heap
-      int heapsz = readInt(dis, swap);
-
-      if (!delta) {
-        this.getByteHeap().heap = new byte[Math.max(16, heapsz)]; // must be > 0
-        dis.readFully(this.getByteHeap().heap, 0, heapsz);
-        this.getByteHeap().heapPos = heapsz;
-      }  else {
-        for (int i=0; i < heapsz; i++) {
-      	  this.getByteHeap().addByte(dis.readByte());
-        }
-      }
-      // word alignment
-      int align = (4 - (heapsz % 4)) % 4;
-      BinaryCasSerDes6.skipBytes(dis, align);
-
-      // short heap
-      heapsz = readInt(dis, swap);
-      
-      if (!delta) {
-        this.getShortHeap().heap = new short[Math.max(16, heapsz)]; // must be > 0
-        for (int i = 0; i < heapsz; i++) {
-          this.getShortHeap().heap[i] = readShort(dis, swap);
-        }
-        this.getShortHeap().heapPos = heapsz;
-      } else {
-      	for (int i = 0; i < heapsz; i++) {
-      	  this.getShortHeap().addShort(readShort(dis, swap));
-        }
-      }
-      // word alignment
-      if (heapsz % 2 != 0) {
-        dis.readShort();
-      }
-
-      // long heap
-      heapsz = readInt(dis, swap);
-      
-      if (!delta) {
-        this.getLongHeap().heap = new long[Math.max(16, heapsz)]; // must be > 0
-        for (int i = 0; i < heapsz; i++) {
-          this.getLongHeap().heap[i] = readLong(dis, swap);
-        }
-        this.getLongHeap().heapPos = heapsz;
-      } else {
-      	for (int i = 0; i < heapsz; i++) {
-      	  this.getLongHeap().addLong(readLong(dis, swap));
-        }
-      }
-      
-      if (delta)  {
-          //modified Byte Heap
-        heapsz = readInt(dis, swap);
-      	if (heapsz > 0) {
-      	  int[] heapAddrs = new int[heapsz];
-      	  for (int i = 0; i < heapsz; i++) {
-      	    heapAddrs[i] = readInt(dis, swap);
-      	  }
-      	  for (int i = 0; i < heapsz; i++) {
-      	    this.getByteHeap().heap[heapAddrs[i]] = dis.readByte();
-      	  }
-      	}
-      	// word alignment
-        align = (4 - (heapsz % 4)) % 4;
-        BinaryCasSerDes6.skipBytes(dis, align);
-        
-        //modified Short Heap
-        heapsz = readInt(dis, swap);
-        if (heapsz > 0) {
-          int[] heapAddrs = new int[heapsz];
-      	  for (int i = 0; i < heapsz; i++) {
-            heapAddrs[i] = readInt(dis, swap);
-          }
-          for (int i = 0; i < heapsz; i++) {
-            this.getShortHeap().heap[heapAddrs[i]] = readShort(dis, swap);
-       	  }
-      	}
-      	
-        // word alignment
-        if (heapsz % 2 != 0) {
-          dis.readShort();
-        }
-      
-        //modified Long Heap
-        heapsz = readInt(dis, swap);
-        if (heapsz > 0) {
-          int[] heapAddrs = new int[heapsz];
-          for (int i = 0; i < heapsz; i++) {
-            heapAddrs[i] = readInt(dis, swap);
-          }
-          for (int i = 0; i < heapsz; i++) {
-            this.getLongHeap().heap[heapAddrs[i]] = readLong(dis, swap);
-          }
-        }
-      } // of delta - modified processing
-    } catch (IOException e) {
-      String msg = e.getMessage();
-      if (msg == null) {
-        msg = e.toString();
-      }
-      CASRuntimeException exception = new CASRuntimeException(
-          CASRuntimeException.BLOB_DESERIALIZATION, new String[] { msg });
-      throw exception;
-    }
-    return SerialFormat.BINARY;
-  }
-  
-  /**
-   * for Deserialization of Delta, when updating existing FSs,
-   * If the heap addr is for the next FS, re-add the previous one to those indexes where it was removed,
-   * and then maybe remove the new one (and remember which views to re-add to).
-   * @param heapAddr
-   */
-  private void maybeAddBackAndRemoveFs(int heapAddr, final BinDeserSupport bds) {
-    if (bds.fsStartAddr == -1) {
-      bds.fssIndex = -1;
-      bds.lastRemovedFsAddr = -1;
-      bds.tobeAddedback.clear();
-    }
-    findCorrespondingFs(heapAddr, bds); // sets fsStartAddr, end addr
-    if (bds.lastRemovedFsAddr != bds.fsStartAddr) {
-      bds.tobeAddedback.addback(bds.lastRemovedFsAddr);
-      if (bds.featCodes.length == 0) {
-        // is array
-        final int typeCode = getTypeCode(bds.fsStartAddr);
-        assert(getTypeSystemImpl().ll_isArrayType(typeCode));
-      } else {
-        int featCode = bds.featCodes[heapAddr - (bds.fsStartAddr + 1)];
-        removeFromCorruptableIndexAnyView(bds.lastRemovedFsAddr = bds.fsStartAddr, bds.tobeAddedback, featCode);
-      }
-    }
-  }
-    
-  private void findCorrespondingFs(int heapAddr, final BinDeserSupport bds) {
-    if (bds.fsStartAddr < heapAddr && heapAddr < bds.fsEndAddr) {
-      return;
-    }
-    
-    // search forward by 1 before doing binary search
-    bds.fssIndex ++;  // incrementing dense index into fssAddrArray for start addrs
-    bds.fsStartAddr = bds.fssAddrArray[bds.fssIndex];  // must exist
-    if (bds.fssIndex + 1 < bds.fssAddrArray.length) { // handle edge case where prev was at the end
-      bds.fsEndAddr = bds.fssAddrArray[bds.fssIndex + 1];  // must exist
-      if (bds.fsStartAddr < heapAddr && heapAddr < bds.fsEndAddr) {
-        bds.featCodes = getTypeSystemImpl().ll_getAppropriateFeatures(getTypeCode(bds.fsStartAddr));
-        return;
-      }
-    }
-    
-    int result;
-    if (heapAddr > bds.fsEndAddr) {
-      // item is higher
-      result = Arrays.binarySearch(bds.fssAddrArray, bds.fssIndex + 1, bds.fssAddrArray.length, heapAddr);
-    } else {
-      result = Arrays.binarySearch(bds.fssAddrArray,  0, bds.fssIndex - 1, heapAddr);
-    }
-    
-    // result must be negative - should never modify a type code slot
-    assert (result < 0);
-    bds.fssIndex = (-result) - 2;
-    bds.fsStartAddr = bds.fssAddrArray[bds.fssIndex];
-    bds.fsEndAddr = bds.fssAddrArray[bds.fssIndex + 1];
-    bds.featCodes = getTypeSystemImpl().ll_getAppropriateFeatures(getTypeCode(bds.fsStartAddr));  
-    assert(bds.fsStartAddr < heapAddr && heapAddr < bds.fsEndAddr);
-  }
-  
-  private int getNextFsHeapAddr(int fsAddr) {
-    final TypeSystemImpl tsi = getTypeSystemImpl();
-    final int typeCode = getTypeCode(fsAddr);
-    final Type type = tsi.ll_getTypeForCode(typeCode);
-    //debug
-//    if (tsi.ll_getTypeForCode(typeCode) == null) {
-//      System.out.println("debug, typeCode = "+ typeCode);
-//    }
-    final boolean isHeapStoredArray = (typeCode == TypeSystemImpl.intArrayTypeCode) || (typeCode == TypeSystemImpl.floatArrayTypeCode)
-        || (typeCode == TypeSystemImpl.fsArrayTypeCode) || (typeCode == TypeSystemImpl.stringArrayTypeCode)
-        || (TypeSystemImpl.isArrayTypeNameButNotBuiltIn(type.getName()));
-    if (isHeapStoredArray) {
-      return fsAddr + 2 + getHeapValue(fsAddr + 1);
-    } else if (type.isArray()) {
-      return fsAddr + 3;  // for the aux ref and the length
-    } else {
-      return fsAddr + this.svd.casMetadata.fsSpaceReq[typeCode];
-    }    
-  }
-  
-  private long readLong(DataInputStream dis, boolean swap) throws IOException {
-    long v = dis.readLong();
-    return swap ? Long.reverseBytes(v) : v;
-  }
-  
-  private int readInt(DataInputStream dis, boolean swap) throws IOException {
-    int v = dis.readInt();
-    return swap ? Integer.reverseBytes(v) : v;
-  }
-  
-  private short readShort(DataInputStream dis, boolean swap) throws IOException {
-    short v = dis.readShort();
-    return swap ? Short.reverseBytes(v) : v;
-  }
-
-//  private long swap8(DataInputStream dis, byte[] buf) throws IOException {
-//
-//    buf[7] = dis.readByte();
-//    buf[6] = dis.readByte();
-//    buf[5] = dis.readByte();
-//    buf[4] = dis.readByte();
-//    buf[3] = dis.readByte();
-//    buf[2] = dis.readByte();
-//    buf[1] = dis.readByte();
-//    buf[0] = dis.readByte();
-//    ByteBuffer bb = ByteBuffer.wrap(buf);
-//    return bb.getLong();
-//  }
-//
-//  private int swap4(DataInputStream dis, byte[] buf) throws IOException {
-//    buf[3] = dis.readByte();
-//    buf[2] = dis.readByte();
-//    buf[1] = dis.readByte();
-//    buf[0] = dis.readByte();
-//    ByteBuffer bb = ByteBuffer.wrap(buf);
-//    return bb.getInt();
-//  }
-//
-//  private char swap2(DataInputStream dis, byte[] buf) throws IOException {
-//    buf[1] = dis.readByte();
-//    buf[0] = dis.readByte();
-//    ByteBuffer bb = ByteBuffer.wrap(buf, 0, 2);
-//    return bb.getChar();
-//  }
-
-  // assumes:
-  // indexes are empty on entry
-  //   
-  void reinitIndexedFSs(int[] fsIndex) {
-    // Add FSs to index repository for base CAS
-    int numViews = fsIndex[0];
-    int loopLen = fsIndex[1]; // number of sofas, not necessarily the same as
-    // number of views
-    // because the initial view may not have a sofa
-    for (int i = 2; i < loopLen + 2; i++) { // iterate over all the sofas,
-      this.indexRepository.addFS(fsIndex[i]); // add to base index
-    }
-    int loopStart = loopLen + 2;
-
-    FSIterator<SofaFS> iterator = this.svd.baseCAS.getSofaIterator();
-    final Feature idFeat = getTypeSystem().getFeatureByFullName(CAS.FEATURE_FULL_NAME_SOFAID);
-    // Add FSs to index repository for each View
-    while (iterator.isValid()) {
-      SofaFS sofa = iterator.get();
-      String id = ll_getStringValue(((FeatureStructureImpl) sofa).getAddress(),
-          ((FeatureImpl) idFeat).getCode());
-      if (CAS.NAME_DEFAULT_SOFA.equals(id)) {
-        this.registerInitialSofa();
-        this.svd.sofaNameSet.add(id);
-      }
-      // next line the getView as a side effect
-      // checks for dupl sofa name, and if not,
-      // adds the name to the sofaNameSet
-      ((CASImpl) this.getView(sofa)).registerView(sofa);
-
-      iterator.moveToNext();
-    }
-    getInitialView();  // done for side effect of creating the initial view.
-    // must be done before the next line, because it sets the
-    // viewCount to 1.
-    this.svd.viewCount = numViews; // total number of views
-    
-    for (int viewNbr = 1; viewNbr <= numViews; viewNbr++) {
-      CAS view = (viewNbr == 1) ? getInitialView() : getView(viewNbr);
-      if (view != null) {
-        FSIndexRepositoryImpl loopIndexRep = (FSIndexRepositoryImpl) getSofaIndexRepository(viewNbr);
-        loopLen = fsIndex[loopStart];
-        for (int i = loopStart + 1; i < loopStart + 1 + loopLen; i++) {
-          loopIndexRep.addFS(fsIndex[i]);
-        }
-        loopStart += loopLen + 1;
-          ((CASImpl) view).updateDocumentAnnotation();
-      } else {
-        loopStart += 1;
-      }
-    }
-  }
-  
-  /**
-   * Adds the SofaFSs to the base view
-   * Assumes "cas" refers to the base cas
-   *
-   * Processes "adds", "removes" and "reindexes" for all views
-   *
-   * @param fsIndex - array of fsRefs and counts, for sofas, and all views
-   */
-  void reinitDeltaIndexedFSs(int[] fsIndex) {
-    assert(this.svd.baseCAS == this);  
-    // Add Sofa FSs to index repository for base CAS
-    int numViews = fsIndex[0]; // total number of views
-    int loopLen = fsIndex[1]; // number of sofas, not necessarily the same as number of views (initial view could be missing a Sofa)
-    // add Sofa FSs to base view number of views. Should only contain new Sofas.
-    for (int i = 2; i < loopLen + 2; i++) { // iterate over all the sofas,
-      this.indexRepository.addFS(fsIndex[i]); // add to base index
-    }
-    int loopStart = loopLen + 2;
-
-    FSIterator<SofaFS> iterator = this.getSofaIterator();
-    final int idFeatCode = ((FeatureImpl)getTypeSystem().getFeatureByFullName(CAS.FEATURE_FULL_NAME_SOFAID)).getCode();
-    
-    // Register all Sofas
-    while (iterator.isValid()) {
-      SofaFS sofa = iterator.get();
-      String id = ll_getStringValue(((FeatureStructureImpl) sofa).getAddress(), idFeatCode);
-      if (CAS.NAME_DEFAULT_SOFA.equals(id)) {
-        this.registerInitialSofa();
-        this.svd.sofaNameSet.add(id);
-      }
-      // next line the getView as a side effect
-      // checks for dupl sofa name, and if not,
-      // adds the name to the sofaNameSet
-      ((CASImpl) this.getView(sofa)).registerView(sofa);
-
-      iterator.moveToNext();
-    }
-    
-    this.svd.viewCount = numViews; // total number of views
-
-    for (int viewNbr = 1; viewNbr <= numViews; viewNbr++) {
-      CAS view = (viewNbr == 1) ? getInitialView() : getView(viewNbr);
-      if (view != null) {
-        
-        // for all views
-        
-        FSIndexRepositoryImpl loopIndexRep = (FSIndexRepositoryImpl) getSofaIndexRepository(viewNbr);
-        loopLen = fsIndex[loopStart];
-        
-        // add FSs to index
-        
-        for (int i = loopStart + 1; i < loopStart + 1 + loopLen; i++) {
-          loopIndexRep.addFS(fsIndex[i]);
-        }
-        
-        // remove FSs from indexes
-        
-        loopStart += loopLen + 1;
-        loopLen = fsIndex[loopStart];
-        for (int i = loopStart + 1; i < loopStart + 1 + loopLen; i++) {
-          loopIndexRep.removeFS(fsIndex[i]);
-        }
-        
-        // skip the reindex - this isn't done here https://issues.apache.org/jira/browse/UIMA-4100
-        // but we need to run the loop to read over the items in the input stream
-        loopStart += loopLen + 1;
-        loopLen = fsIndex[loopStart];
-//        for (int i = loopStart + 1; i < loopStart + 1 + loopLen; i++) {
-//          loopIndexRep.removeFS(fsIndex[i]);
-//          loopIndexRep.addFS(fsIndex[i]);
-//        }
-        loopStart += loopLen + 1;
-        ((CASImpl) view).updateDocumentAnnotation();
-      } else {
-        loopStart += 1;
-      }
-    }
-  }
-
-  // IndexedFSs format:
-  // number of views
-  // number of sofas
-  // [sofa-1 ... sofa-n]
-  // number of FS indexed in View1
-  // [FS-1 ... FS-n]
-  // etc.
-  int[] getIndexedFSs() {
-    IntVector v = new IntVector();
-    int[] fsLoopIndex;
-
-    int numViews = getBaseSofaCount();
-    v.add(numViews);
-
-    // Get indexes for base CAS
-    fsLoopIndex = this.svd.baseCAS.indexRepository.getIndexedFSs();
-    v.add(fsLoopIndex.length);
-    v.add(fsLoopIndex, 0, fsLoopIndex.length);
-//    for (int k = 0; k < fsLoopIndex.length; k++) {
-//      v.add(fsLoopIndex[k]);
-//    }
-
-    // Get indexes for each SofaFS in the CAS
-    for (int sofaNum = 1; sofaNum <= numViews; sofaNum++) {
-      FSIndexRepositoryImpl loopIndexRep = (FSIndexRepositoryImpl) this.svd.baseCAS
-          .getSofaIndexRepository(sofaNum);
-      if (loopIndexRep != null) {
-        fsLoopIndex = loopIndexRep.getIndexedFSs();
-      } else {
-        fsLoopIndex = INT0;
-      }
-      v.add(fsLoopIndex.length);
-      for (int k = 0; k < fsLoopIndex.length; k++) {
-        v.add(fsLoopIndex[k]);
-      }
-    }
-    return v.toArray();
-  }
-  
- 
-  
-  //Delta IndexedFSs format:
-  // number of views
-  // number of sofas - new
-  // [sofa-1 ... sofa-n]
-  // number of new FS add in View1
-  // [FS-1 ... FS-n]
-  // number of  FS removed from View1
-  // [FS-1 ... FS-n]
-  //number of  FS reindexed in View1
-  // [FS-1 ... FS-n]
-  // etc.
-  int[] getDeltaIndexedFSs(MarkerImpl mark) {
-    IntVector v = new IntVector();
-    int[] fsLoopIndex;
-    int[] fsDeletedFromIndex;
-    int[] fsReindexed;
-
-    int numViews = getBaseSofaCount();
-    v.add(numViews);
-
-    // Get indexes for base CAS
-    fsLoopIndex = this.svd.baseCAS.indexRepository.getIndexedFSs();
-    // Get the new Sofa FS
-    IntVector newSofas = new IntVector();
-    for (int k = 0; k < fsLoopIndex.length; k++) {
-      if ( mark.isNew(fsLoopIndex[k]) ) {
-        newSofas.add(fsLoopIndex[k]);
-      }
-    }
-    
-    v.add(newSofas.size());
-    v.add(newSofas.getArray(), 0, newSofas.size());
-//    for (int k = 0; k < newSofas.size(); k++) {
-//      v.add(newSofas.get(k));
-//    }
-
-    // Get indexes for each view in the CAS
-    for (int sofaNum = 1; sofaNum <= numViews; sofaNum++) {
-      FSIndexRepositoryImpl loopIndexRep = (FSIndexRepositoryImpl) this.svd.baseCAS
-          .getSofaIndexRepository(sofaNum);
-      if (loopIndexRep != null) {
-        fsLoopIndex = loopIndexRep.getAddedFSs();
-        fsDeletedFromIndex = loopIndexRep.getDeletedFSs();
-        fsReindexed = loopIndexRep.getReindexedFSs();
-      } else {
-        fsLoopIndex = INT0;
-        fsDeletedFromIndex = INT0;
-        fsReindexed = INT0;
-      }
-      v.add(fsLoopIndex.length);
-      v.add(fsLoopIndex, 0, fsLoopIndex.length);
-//      for (int k = 0; k < fsLoopIndex.length; k++) {
-//        v.add(fsLoopIndex[k]);
-//      }
-      v.add(fsDeletedFromIndex.length);
-      v.add(fsDeletedFromIndex, 0, fsDeletedFromIndex.length);
-//      for (int k = 0; k < fsDeletedFromIndex.length; k++) {
-//        v.add(fsDeletedFromIndex[k]);
-//      }
-      v.add(fsReindexed.length);
-      v.add(fsReindexed, 0, fsReindexed.length);
-//      for (int k = 0; k < fsReindexed.length; k++) {
-//        v.add(fsReindexed[k]);
-//      }
-    }
-    return v.toArray();
-  }
-
-  void createStringTableFromArray(String[] stringTable) {
-    // why a new heap instead of reseting the old one???
-    // this.stringHeap = new StringHeap();
-    this.getStringHeap().reset();
-    for (int i = 1; i < stringTable.length; i++) {
-      this.getStringHeap().addString(stringTable[i]);
-    }
-  }
-
-  static String mapName(String name, HashMap<String, String> map) {
-    String out = map.get(name);
-    if (out != null) {
-      return out;
-    }
-    return name;
-  }
-
-  /**
-   * This is your link from the low-level API to the high-level API. Use this
-   * method to create a FeatureStructure object from an address. Not that the
-   * reverse is not supported by public APIs (i.e., there is currently no way to
-   * get at the address of a FeatureStructure. Maybe we will need to change
-   * that.
-   * 
-   * @param addr
-   *                The address of the feature structure to be created.
-   * @param <T> The Java class associated with this feature structure
-   * @return A FeatureStructure object. Note that no checking whatsoever is done
-   *         on the input address. There is really no way of finding out which
-   *         addresses in the valid address space actually represent feature
-   *         structures, and which don't.
-   */
-  public <T extends FeatureStructure> T createFS(int addr) {
-    return ll_getFSForRef(addr);
-  }
-
-  public int ll_getArraySize(int arrayFsRef) {
-    return this.getHeap().heap[arrayFsRef + arrayLengthFeatOffset];
-  }
-
-  /**
-   * Get the heap address of the first cell of this array.
-   * 
-   * @param addr
-   *                The address of the array.
-   * @return The address where the first cell of the array is located.
-   */
-  public final int getArrayStartAddress(int addr) {
-    return addr + arrayContentOffset;
-  }
-
-  /**
-   * Get a specific value out of an array.
-   * 
-   * @param addr
-   *                The address of the array.
-   * @param index
-   *                The index of the value we're interested in.
-   * @return The value at <code>index</code>.
-   * @exception ArrayIndexOutOfBoundsException -
-   */
-  public int getArrayValue(int addr, int index) {
-    checkArrayBounds(addr, index);
-    return this.getHeap().heap[addr + arrayContentOffset + index];
-  }
-
-  /**
-   * Set an array value.
-   * 
-   * @param addr
-   *                The address of the array.
-   * @param index
-   *                The index we want to set.
-   * @param value
-   *                The value we want to set.
-   * @exception ArrayIndexOutOfBoundsException
-   */
-  void setArrayValue(final int addr, final int index, final int value)
-      throws ArrayIndexOutOfBoundsException {
-    // Get the length of this array.
-    final int arraySize = this.getHeap().heap[addr + arrayLengthFeatOffset];
-    // Check for boundary violation.
-    if ((index < 0) || (index >= arraySize)) {
-      throw new ArrayIndexOutOfBoundsException();
-    }
-    this.getHeap().heap[addr + arrayContentOffset + index] = value;
-    if (this.svd.trackingMark != null) {
-    	this.logFSUpdate(addr, addr+arrayContentOffset+index, ModifiedHeap.FSHEAP, 1);
-    }
-  }
-
-  void setArrayValueFromString(final int addr, final int index, final String value) {
-    int arrayType = this.getHeap().heap[addr];
-
-    if (arrayType == TypeSystemImpl.intArrayTypeCode) {
-      setArrayValue(addr, index, Integer.parseInt(value));
-    } else if (arrayType == TypeSystemImpl.floatArrayTypeCode) {
-      setArrayValue(addr, index, CASImpl.float2int(Float.parseFloat(value)));
-    } else if (arrayType == TypeSystemImpl.stringArrayTypeCode) {
-      setArrayValue(addr, index, addString(value));
-    } else if (arrayType == TypeSystemImpl.booleanArrayTypeCode) {
-      ll_setBooleanArrayValue(addr, index, Boolean.valueOf(value).booleanValue());
-    } else if (arrayType == TypeSystemImpl.byteArrayTypeCode) {
-      ll_setByteArrayValue(addr, index, Byte.parseByte(value));
-    } else if (arrayType == TypeSystemImpl.shortArrayTypeCode) {
-      ll_setShortArrayValue(addr, index, Short.parseShort(value));
-    } else if (arrayType == TypeSystemImpl.longArrayTypeCode) {
-      ll_setLongArrayValue(addr, index, Long.parseLong(value));
-    } else if (arrayType == TypeSystemImpl.doubleArrayTypeCode) {
-      ll_setDoubleArrayValue(addr, index, Double.parseDouble(value));
-    } else if (arrayType == TypeSystemImpl.fsArrayTypeCode) {
-      setArrayValue(addr, index, Integer.parseInt(value));
-    }
-  }
-
-  /**
-   * Copy the contents of an array to an externally provided array.
-   * 
-   * @param addr
-   *                The address of the source array.
-   * @param sourceOffset
-   *                The offset we want to start copying at.
-   * @param dest
-   *                The destination array.
-   * @param destOffset
-   *                An offset into the destination array.
-   * @param length
-   *                The number of items to copy.
-   */
-  void copyToArray(int addr, int sourceOffset, int[] dest, int destOffset, int length) {
-    // Get the length of this array.
-    final int arraySize = this.getHeap().heap[addr + arrayLengthFeatOffset];
-    // Check boundary conditions for source array. We can rely on Java to
-    // complain about boundary violations for the destination array.
-    if ((sourceOffset < 0) || ((length + sourceOffset) > arraySize)) {
-      throw new ArrayIndexOutOfBoundsException();
-    }
-    // Compute the offset into the heap where the array starts.
-    final int offset = addr + arrayContentOffset;
-    System.arraycopy(this.getHeap().heap, offset + sourceOffset, dest, destOffset, length);
-  }
+    maybeLogUpdate(fs, feat);
+  }
+  
+  /**
+   * This is the common point where all operations to set features come through
+   * It implements the check for invalid feature setting and potentially the addback.
+   *   (String objects may be in keys) 
+   * @param fs      the feature structure
+   * @param feat    the feature to set
+   * @param value -
+   */
+  
+  public void setFeatureValue(FeatureStructureImplC fs, FeatureImpl feat, Object value) {
+    boolean wasRemoved = checkForInvalidFeatureSetting(fs, feat.getCode());
+    fs._refData[feat.getAdjustedOffset()] = value;
+    if (wasRemoved) {
+      maybeAddback(fs);
+    }
+    maybeLogUpdate(fs, feat);
+  }
 
   /**
-   * Copy the contents of an input array into a CAS array.
-   * 
-   * @param src
-   *                The array to copy from.
-   * @param srcOffset
-   *                An offset into the source from where to start copying.
-   * @param addr
-   *                The address of the array we're copying to.
-   * @param destOffset
-   *                Where to start copying into the destination array.
-   * @param length
-   *                How many elements to copy.
-   */
-  void copyFromArray(int[] src, int srcOffset, int addr, int destOffset, int length) {
-    // Get the length of this array.
-    final int arraySize = this.getHeap().heap[addr + arrayLengthFeatOffset];
-    // Check boundary conditions for destination array. We can rely on Java
-    // to
-    // complain about boundary violations for the source array.
-    if ((destOffset < 0) || ((length + destOffset) > arraySize)) {
-      throw new ArrayIndexOutOfBoundsException();
-    }
-    // Compute the offset into the heap where the array starts.
-    final int offset = addr + arrayContentOffset;
-    System.arraycopy(src, srcOffset, this.getHeap().heap, offset + destOffset, length);
-    if (this.svd.trackingMark != null) {
-    	this.logFSUpdate(addr, offset + destOffset, ModifiedHeap.FSHEAP, length);
-    }
-  }
-
-  public int getTypeCode(int fsAddr) {
-    return getHeapValue(fsAddr);
-  }
-  
-  // not journaled, this is for a new FS only
-  void copyFeatures(int trgAddr, int srcAddr) throws CASRuntimeException {
-    int typeCode = getHeapValue(trgAddr);
-    if (typeCode != getHeapValue(srcAddr)) {
-      CASRuntimeException e = new CASRuntimeException(CASRuntimeException.INAPPROP_TYPE);
-      // What's that supposed to mean? Internationalized, my foot.
-      // TODO: fix exception argument.
-      // e.addArgument("Type of source and target feature structures do not
-      // match");
-      throw (e);
-    }
-    // get features to copy
-    int[] featcodes = getTypeSystem().getLowLevelTypeSystem().ll_getAppropriateFeatures(typeCode);
-    for (int i = 0; i < featcodes.length; i++) {
-
-      // get range type of this feature
-      Feature feature = getTypeSystem().getLowLevelTypeSystem().ll_getFeatureForCode(featcodes[i]);
-      Type rangeType = feature.getRange();
-      // get feature code
-      int featCode = ((FeatureImpl) feature).getCode();
-      // get the value for this feature offset in src fs
-      int val = getHeapValue(srcAddr + this.svd.casMetadata.featureOffset[featCode]);
-      // if this is a string, create a new reference in the string
-      // reference heap
-      // and point to the same string as the string feature in src fs.
-      setFeatureValueNotJournaled(trgAddr,  featCode, isStringType(rangeType) ? 
-            this.getStringHeap().cloneStringReference(val)  : 
-            getHeapValue(srcAddr + this.svd.casMetadata.featureOffset[featCode]));
-    }
-  }
-
-  /**
-   * Get the value of an address on the heap.
+   * Set the value of a feature of a FS without checking for index corruption
+   * (typically because the feature isn't one that can be used as a key, or
+   * the context is one where the FS is being created, and is guaranteed not to be in any index (yet))
    * 
-   * @param addr
-   *                The target address.
-   * @return The value at the address.
-   */
-  public int getHeapValue(int addr) {
-    return this.getHeap().heap[addr];
+   * @param fs      The FS.
+   * @param feat    The feature.
+   * @param value     The new value for the feature.
+   */
+  void setFeatureValueNoIndexCorruptionCheck(FeatureStructureImplC fs, FeatureImpl feat, int value) {
+    fs._intData[feat.getAdjustedOffset()] = value;   
+    maybeLogUpdate(fs, feat);
   }
 
   /**
-   * This is the common point where all sets of values in the heap come through
-   * It implements the check for invalid feature setting and potentially the addback.
-   * 
-   * Set the value of a feature of a FS.
-   * 
-   * @param addr
-   *                The address of the FS.
-   * @param feat
-   *                The code of the feature.
-   * @param val
-   *                The new value for the feature.
-   * @exception ArrayIndexOutOfBoundsException
-   *                    If the feature is not a legal feature, or it is not
-   *                    appropriate for the type at the address.
-   */
-  public void setFeatureValue(int addr, int feat, int val) {
-    boolean wasRemoved = checkForInvalidFeatureSetting(addr, feat);
-    setFeatureValueNotJournaled(addr, feat, val);
-    if (wasRemoved) {
-      maybeAddback(addr);
-    }
-    if (this.svd.trackingMark != null) {
-    	this.logFSUpdate(addr, addr + this.svd.casMetadata.featureOffset[feat], 

[... 2995 lines stripped ...]