Merge branch '2.6'

Conflicts:
	pom.xml
	release-notes/VERSION
diff --git a/README.md b/README.md
index b76d839..69eae2a 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,6 @@
 * Project  [Wiki](../../wiki) has JavaDocs and links to downloadable artifacts
 * [Jackson Github Hub](https://github.com/FasterXML/jackson) has links to all official Jackson components
 * [Jackson Github Doc](https://github.com/FasterXML/jackson-docs) is the hub for official Jackson documentation
-* [FasterXML Jackson Project Wiki](http://wiki.fasterxml.com/JacksonHome) has additional documentation (especailly for older Jackson versions)
+* [FasterXML Jackson Project Wiki](http://wiki.fasterxml.com/JacksonHome) has additional documentation (especially for older Jackson versions)
 * Commercial support (including alternative licensing arrangements) is available by [FasterXML.com](http://fasterxml.com)
 
diff --git a/pom.xml b/pom.xml
index 8a79b7a..759ecec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,13 +3,13 @@
   <parent>
     <groupId>com.fasterxml.jackson</groupId>
     <artifactId>jackson-parent</artifactId>
-    <version>2.6.2</version>
+    <version>2.7</version>
   </parent>
 
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <name>Jackson-core</name>
-  <version>2.6.5-SNAPSHOT</version>
+  <version>2.7.0-rc3-SNAPSHOT</version>
   <packaging>bundle</packaging>
   <description>Core Jackson abstractions, basic JSON streaming API implementation</description>
   <inceptionYear>2008</inceptionYear>
@@ -23,6 +23,10 @@
   </scm>
 
   <properties>
+    <!-- 02-Oct-2015, tatu: Retain Java6/JDK1.6 compatibility for streaming for Jackson 2.7 -->
+    <javac.src.version>1.6</javac.src.version>
+    <javac.target.version>1.6</javac.target.version>
+
     <osgi.export>com.fasterxml.jackson.core;version=${project.version},
 com.fasterxml.jackson.core.*;version=${project.version}
     </osgi.export>
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index 4e01f69..f07310b 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -70,3 +70,8 @@
 Iskren Ivov Chernev (ichernev@github)
   * Reported #213: Parser is sometimes wrong when using CANONICALIZE_FIELD_NAMES
    (2.6.2)
+
+Michael Lehenbauer (mikelehen@github)
+  * Reported #37: JsonParser.getTokenLocation() doesn't update after field names
+   (2.7.0)
+
diff --git a/release-notes/VERSION b/release-notes/VERSION
index a8a79f6..04d1ef2 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -14,6 +14,18 @@
 === Releases ===
 ------------------------------------------------------------------------
 
+2.7.0 (not yet released)
+
+#37: JsonParser.getTokenLocation() doesn't update after field names
+ (reported by Michael L)
+#198: Add back-references to `JsonParser` / `JsonGenerator` for low-level parsing issues
+ (via `JsonParseException`, `JsonGenerationException`)
+#211: Typo of function name com.fasterxml.jackson.core.Version.isUknownVersion()
+ (reported by timray@github)
+#229: Array element and field token spans include previous comma.
+- Implemented `ReaderBasedJsonParser.nextFieldName(SerializableString)`
+  (to improved Afterburner performance over String/char[] sources)
+
 2.6.4 (07-Dec-2015)
 
 No changes since 2.6.3.
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
index 08037aa..b052507 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
@@ -205,16 +205,6 @@
      */
     protected final transient ByteQuadsCanonicalizer _byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot();
 
-    /**
-     * Earlier byte-based symbol table; replaced with 2.6 with a new implementation.
-     * Left in for version 2.6.0: will be removed in 2.7 or later.
-     *
-     * @deprecated Since 2.6.0, only use {@link #_byteSymbolCanonicalizer}
-     */
-    @Deprecated
-    protected final transient com.fasterxml.jackson.core.sym.BytesToNameCanonicalizer _rootByteSymbols
-        = com.fasterxml.jackson.core.sym.BytesToNameCanonicalizer.createRoot();
-
     /*
     /**********************************************************
     /* Configuration
@@ -739,9 +729,15 @@
 
     /**
      * Method for constructing JSON parser instance to parse
-     * contents of specified file. Encoding is auto-detected
-     * from contents according to JSON specification recommended
-     * mechanism.
+     * contents of specified file.
+     *
+     *<p>
+     * Encoding is auto-detected from contents according to JSON
+     * specification recommended mechanism. Json specification
+     * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+     * so auto-detection implemented only for this charsets.
+     * For other charsets use {@link #createParser(java.io.Reader)}.
+     *
      *<p>
      * Underlying input stream (needed for reading contents)
      * will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -761,9 +757,14 @@
     /**
      * Method for constructing JSON parser instance to parse
      * contents of resource reference by given URL.
-     * Encoding is auto-detected
-     * from contents according to JSON specification recommended
-     * mechanism.
+     *
+     *<p>
+     * Encoding is auto-detected from contents according to JSON
+     * specification recommended mechanism. Json specification
+     * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+     * so auto-detection implemented only for this charsets.
+     * For other charsets use {@link #createParser(java.io.Reader)}.
+     *
      *<p>
      * Underlying input stream (needed for reading contents)
      * will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -790,8 +791,12 @@
      * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
      * is enabled.
      *<p>
+     *
      * Note: no encoding argument is taken since it can always be
-     * auto-detected as suggested by JSON RFC.
+     * auto-detected as suggested by JSON RFC. Json specification
+     * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+     * so auto-detection implemented only for this charsets.
+     * For other charsets use {@link #createParser(java.io.Reader)}.
      *
      * @param in InputStream to use for reading JSON content to parse
      * 
@@ -907,15 +912,20 @@
 
     /*
     /**********************************************************
-    /* Parser factories (old ones, as per [Issue-25])
+    /* Parser factories (old ones, pre-2.2)
     /**********************************************************
      */
 
     /**
      * Method for constructing JSON parser instance to parse
-     * contents of specified file. Encoding is auto-detected
-     * from contents according to JSON specification recommended
-     * mechanism.
+     * contents of specified file.
+     *<p>
+     * Encoding is auto-detected from contents according to JSON
+     * specification recommended mechanism. Json specification
+     * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+     * so auto-detection implemented only for this charsets.
+     * For other charsets use {@link #createParser(java.io.Reader)}.
+     *
      *<p>
      * Underlying input stream (needed for reading contents)
      * will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -933,9 +943,14 @@
     /**
      * Method for constructing JSON parser instance to parse
      * contents of resource reference by given URL.
-     * Encoding is auto-detected
-     * from contents according to JSON specification recommended
-     * mechanism.
+     *
+     *<p>
+     * Encoding is auto-detected from contents according to JSON
+     * specification recommended mechanism. Json specification
+     * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+     * so auto-detection implemented only for this charsets.
+     * For other charsets use {@link #createParser(java.io.Reader)}.
+     *
      *<p>
      * Underlying input stream (needed for reading contents)
      * will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -960,8 +975,12 @@
      * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
      * is enabled.
      *<p>
+     *
      * Note: no encoding argument is taken since it can always be
-     * auto-detected as suggested by JSON RFC.
+     * auto-detected as suggested by JSON RFC. Json specification
+     * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+     * so auto-detection implemented only for this charsets.
+     * For other charsets use {@link #createParser(java.io.Reader)}.
      *
      * @param in InputStream to use for reading JSON content to parse
      * 
@@ -1131,7 +1150,7 @@
 
     /*
     /**********************************************************
-    /* Generator factories, old (as per [Issue-25]
+    /* Generator factories, old (pre-2.2)
     /**********************************************************
      */
 
@@ -1194,27 +1213,6 @@
     public JsonGenerator createJsonGenerator(OutputStream out) throws IOException {
         return createGenerator(out, JsonEncoding.UTF8);
     }
-    
-    /**
-     * Method for constructing JSON generator for writing JSON content
-     * to specified file, overwriting contents it might have (or creating
-     * it if such file does not yet exist).
-     * Encoding to use must be specified, and needs to be one of available
-     * types (as per JSON specification).
-     *<p>
-     * Underlying stream <b>is owned</b> by the generator constructed,
-     * i.e. generator will handle closing of file when
-     * {@link JsonGenerator#close} is called.
-     *
-     * @param f File to write contents to
-     * @param enc Character encoding to use
-     * 
-     * @deprecated Since 2.2, use {@link #createGenerator(File,JsonEncoding)} instead.
-     */
-    @Deprecated
-    public JsonGenerator createJsonGenerator(File f, JsonEncoding enc) throws IOException {
-        return createGenerator(f, enc);
-    }
 
     /*
     /**********************************************************
@@ -1443,7 +1441,7 @@
         }
         return br;
     }
-    
+
     /**
      * Overridable factory method that actually instantiates desired
      * context object.
@@ -1451,7 +1449,7 @@
     protected IOContext _createContext(Object srcRef, boolean resourceManaged) {
         return new IOContext(_getBufferRecycler(), srcRef, resourceManaged);
     }
-    
+
     /**
      * Helper methods used for constructing an optimal stream for
      * parsers to use, when input is to be read from an URL.
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java
index 5a9d181..69d825b 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java
@@ -14,19 +14,59 @@
     extends JsonProcessingException
 {
     private final static long serialVersionUID = 123; // Stupid eclipse...
-    
-    public JsonGenerationException(Throwable rootCause)
-    {
+
+    protected JsonGenerator _processor;
+
+    @Deprecated // since 2.7
+    public JsonGenerationException(Throwable rootCause) {
         super(rootCause);
     }
 
-    public JsonGenerationException(String msg)
-    {
+    @Deprecated // since 2.7
+    public JsonGenerationException(String msg) {
         super(msg, (JsonLocation)null);
     }
 
-    public JsonGenerationException(String msg, Throwable rootCause)
-    {
+    @Deprecated // since 2.7
+    public JsonGenerationException(String msg, Throwable rootCause) {
         super(msg, null, rootCause);
     }
+
+    /**
+     * @since 2.7
+     */
+    public JsonGenerationException(Throwable rootCause, JsonGenerator g) {
+        super(rootCause);
+        _processor = g;
+    }
+
+    /**
+     * @since 2.7
+     */
+    public JsonGenerationException(String msg, JsonGenerator g) {
+        super(msg, (JsonLocation) null);
+        _processor = g;
+    }
+    
+    /**
+     * @since 2.7
+     */
+    public JsonGenerationException(String msg, Throwable rootCause, JsonGenerator g) {
+        super(msg, null, rootCause);
+        _processor = g;
+    }
+
+    /**
+     * Fluent method that may be used to assign originating {@link JsonGenerator},
+     * to be accessed using {@link #getProcessor()}.
+     *
+     * @since 2.7
+     */
+    public JsonGenerationException withGenerator(JsonGenerator g) {
+        _processor = g;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator getProcessor() { return _processor; }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
index 7d57513..9be3f84 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
@@ -146,6 +146,30 @@
          */
         ESCAPE_NON_ASCII(false),
 
+// 23-Nov-2015, tatu: for [core#223], if and when it gets implemented
+        /**
+         * Feature that specifies handling of UTF-8 content that contains
+         * characters beyond BMP (Basic Multilingual Plane), which are
+         * represented in UCS-2 (Java internal character encoding) as two
+         * "surrogate" characters. If feature is enabled, these surrogate
+         * pairs are separately escaped using backslash escapes; if disabled,
+         * native output (4-byte UTF-8 sequence, or, with char-backed output
+         * targets, writing of surrogates as is which is typically converted
+         * by {@link java.io.Writer} into 4-byte UTF-8 sequence eventually)
+         * is used.
+         *<p>
+         * Note that the original JSON specification suggests use of escaping;
+         * but that this is not correct from standard UTF-8 handling perspective.
+         * Because of two competing goals, this feature was added to allow either
+         * behavior to be used, but defaulting to UTF-8 specification compliant
+         * mode.
+         *<p>
+         * Feature is disabled by default.
+         *
+         * @since 2.7
+         */
+//        ESCAPE_UTF8_SURROGATES(false),
+        
         // // Schema/Validity support features
 
         /**
@@ -253,7 +277,7 @@
 
     /**
      * Method for accessing the object used for writing Java
-     * object as Json content
+     * object as JSON content
      * (using method {@link #writeObject}).
      */
     public abstract ObjectCodec getCodec();
@@ -303,7 +327,6 @@
      */
     public abstract boolean isEnabled(Feature f);
 
-
     /**
      * Bulk access method for getting state of all standard (non-dataformat-specific)
      * {@link JsonGenerator.Feature}s.
@@ -323,7 +346,10 @@
      *    and which disabled
      *
      * @return This parser object, to allow chaining of calls
+     *
+     * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
      */
+    @Deprecated
     public abstract JsonGenerator setFeatureMask(int values);
 
     /**
@@ -334,6 +360,7 @@
      *    int newState = (oldState &amp; ~mask) | (values &amp; mask);
      *    setFeatureMask(newState);
      *</code>
+     * but preferred as this lets caller more efficiently specify actual changes made.
      * 
      * @param values Bit mask of set/clear state for features to change
      * @param mask Bit mask of features to change
@@ -953,7 +980,7 @@
      * encoded, as a complete String value (surrounded by double quotes).
      * This method defaults
      *<p>
-     * Note: because Json Strings can not contain unescaped linefeeds,
+     * Note: because JSON Strings can not contain unescaped linefeeds,
      * if linefeeds are included (as per last argument), they must be
      * escaped. This adds overhead for decoding without improving
      * readability.
@@ -1142,7 +1169,7 @@
     public abstract void writeNumber(String encodedValue) throws IOException;
 
     /**
-     * Method for outputting literal Json boolean value (one of
+     * Method for outputting literal JSON boolean value (one of
      * Strings 'true' and 'false').
      * Can be called in any context where a value is expected
      * (Array value, Object field value, root-level value).
@@ -1152,7 +1179,7 @@
     public abstract void writeBoolean(boolean state) throws IOException;
 
     /**
-     * Method for outputting literal Json null value.
+     * Method for outputting literal JSON null value.
      * Can be called in any context where a value is expected
      * (Array value, Object field value, root-level value).
      * Additional white space may be added around the value
@@ -1178,7 +1205,7 @@
      * @since 2.3
      */
     public void writeObjectId(Object id) throws IOException {
-        throw new JsonGenerationException("No native support for writing Object Ids");
+        throw new JsonGenerationException("No native support for writing Object Ids", this);
     }
 
     /**
@@ -1191,7 +1218,7 @@
      * a {@link JsonGenerationException} will be thrown.
      */
     public void writeObjectRef(Object id) throws IOException {
-        throw new JsonGenerationException("No native support for writing Object Ids");
+        throw new JsonGenerationException("No native support for writing Object Ids", this);
     }
     
     /**
@@ -1206,9 +1233,9 @@
      * @since 2.3
      */
     public void writeTypeId(Object id) throws IOException {
-        throw new JsonGenerationException("No native support for writing Type Ids");
+        throw new JsonGenerationException("No native support for writing Type Ids", this);
     }
-    
+
     /*
     /**********************************************************
     /* Public API, write methods, serializing Java objects
@@ -1219,8 +1246,8 @@
      * Method for writing given Java object (POJO) as Json.
      * Exactly how the object gets written depends on object
      * in question (ad on codec, its configuration); for most
-     * beans it will result in Json object, but for others Json
-     * array, or String or numeric value (and for nulls, Json
+     * beans it will result in JSON Object, but for others JSON
+     * Array, or String or numeric value (and for nulls, JSON
      * null literal.
      * <b>NOTE</b>: generator must have its <b>object codec</b>
      * set to non-null value; for generators created by a mapping
@@ -1436,7 +1463,7 @@
      * Method for copying contents of the current event that
      * the given parser instance points to.
      * Note that the method <b>will not</b> copy any other events,
-     * such as events contained within Json Array or Object structures.
+     * such as events contained within JSON Array or Object structures.
      *<p>
      * Calling this method will not advance the given
      * parser, although it may cause parser to internally process
@@ -1534,7 +1561,7 @@
      *  </li>
      * <li>{@link JsonToken#FIELD_NAME} the logical value (which
      *   can consist of a single scalar value; or a sequence of related
-     *   events for structured types (Json Arrays, Objects)) will
+     *   events for structured types (JSON Arrays, Objects)) will
      *   be copied along with the name itself. So essentially the
      *   whole <b>field entry</b> (name and value) will be copied.
      *  </li>
@@ -1646,7 +1673,7 @@
      * or use a {@link JsonGenerationException} sub-class.
      */
     protected void _reportError(String msg) throws JsonGenerationException {
-        throw new JsonGenerationException(msg);
+        throw new JsonGenerationException(msg, this);
     }
 
     protected final void _throwInternal() { VersionUtil.throwInternal(); }
@@ -1654,7 +1681,7 @@
     protected void _reportUnsupportedOperation() {
         throw new UnsupportedOperationException("Operation not supported by generator of type "+getClass().getName());
     }
-    
+
     /**
      * Helper method to try to call appropriate write method for given
      * untyped Object. At this point, no structural conversions should be done,
@@ -1702,9 +1729,8 @@
             } else if (n instanceof BigDecimal) {
                 writeNumber((BigDecimal) n);
                 return;
-                
+
             // then Atomic types
-                
             } else if (n instanceof AtomicInteger) {
                 writeNumber(((AtomicInteger) n).get());
                 return;
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
index 926f709..17116e3 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
@@ -11,13 +11,69 @@
  * is encountered.
  */
 public class JsonParseException extends JsonProcessingException {
-    private static final long serialVersionUID = 1L;
-    
+    private static final long serialVersionUID = 2L; // 2.7
+
+    protected JsonParser _processor;
+
+    @Deprecated // since 2.7
     public JsonParseException(String msg, JsonLocation loc) {
         super(msg, loc);
     }
 
+    @Deprecated // since 2.7
     public JsonParseException(String msg, JsonLocation loc, Throwable root) {
         super(msg, loc, root);
     }
+
+    /**
+     * Constructor that uses current parsing location as location, and
+     * sets processor (accessible via {@link #getProcessor()}) to
+     * specified parser.
+     *
+     * @since 2.7
+     */
+    public JsonParseException(JsonParser p, String msg) {
+        super(msg, (p == null) ? null : p.getCurrentLocation());
+        _processor = p;
+    }
+
+    /**
+     * @since 2.7
+     */
+    public JsonParseException(JsonParser p, String msg, Throwable root) {
+        super(msg, (p == null) ? null : p.getCurrentLocation(), root);
+        _processor = p;
+    }
+    
+    /**
+     * @since 2.7
+     */
+    public JsonParseException(JsonParser p, String msg, JsonLocation loc) {
+        super(msg, loc);
+        _processor = p;
+    }
+
+    /**
+     * @since 2.7
+     */
+    public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable root) {
+        super(msg, loc, root);
+        _processor = p;
+    }
+
+    /**
+     * Fluent method that may be used to assign originating {@link JsonParser},
+     * to be accessed using {@link #getProcessor()}.
+     *
+     * @since 2.7
+     */
+    public JsonParseException withParser(JsonParser p) {
+        _processor = p;
+        return this;
+    }
+
+    @Override
+    public JsonParser getProcessor() {
+        return _processor;
+    }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
index 0af1d43..b24b660 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
@@ -103,7 +103,7 @@
          * Feature that determines whether parser will allow use
          * of single quotes (apostrophe, character '\'') for
          * quoting Strings (names and String values). If so,
-         * this is in addition to other acceptabl markers.
+         * this is in addition to other acceptable markers.
          * but not by JSON specification).
          *<p>
          * Since JSON specification requires use of double quotes for
@@ -529,7 +529,10 @@
      * @return This parser object, to allow chaining of calls
      * 
      * @since 2.3
+     * 
+     * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
      */
+    @Deprecated
     public JsonParser setFeatureMask(int mask) {
         _features = mask;
         return this;
@@ -543,6 +546,7 @@
      *    int newState = (oldState &amp; ~mask) | (values &amp; mask);
      *    setFeatureMask(newState);
      *</code>
+     * but preferred as this lets caller more efficiently specify actual changes made.
      * 
      * @param values Bit mask of set/clear state for features to change
      * @param mask Bit mask of features to change
@@ -550,8 +554,8 @@
      * @since 2.6
      */
     public JsonParser overrideStdFeatures(int values, int mask) {
-        _features = (_features & ~mask) | (values & mask);
-        return this;
+        int newState = (_features & ~mask) | (values & mask);
+        return setFeatureMask(newState);
     }
 
     /**
@@ -1172,7 +1176,8 @@
         JsonToken t = getCurrentToken();
         if (t == JsonToken.VALUE_TRUE) return true;
         if (t == JsonToken.VALUE_FALSE) return false;
-        throw new JsonParseException("Current token ("+t+") not of boolean type", getCurrentLocation());
+        throw new JsonParseException(this,
+                String.format("Current token (%s) not of boolean type", t));
     }
 
     /**
@@ -1578,7 +1583,7 @@
      * based on current state of the parser
      */
     protected JsonParseException _constructError(String msg) {
-        return new JsonParseException(msg, getCurrentLocation());
+        return new JsonParseException(this, msg);
     }
 
     /**
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
index ddbab6d..f927336 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
@@ -59,7 +59,7 @@
 
     /*
     /**********************************************************
-    /* Cosntruction
+    /* Construction
     /**********************************************************
      */
     
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java b/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
index 4cca715..44be053 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
@@ -45,14 +45,14 @@
         this(null, null, rootCause);
     }
 
-    public JsonLocation getLocation() { return _location; }
-
     /*
     /**********************************************************
     /* Extended API
     /**********************************************************
      */
 
+    public JsonLocation getLocation() { return _location; }
+    
     /**
      * Method that allows accessing the original "message" argument,
      * without additional decorations (like location information)
@@ -62,6 +62,22 @@
      */
     public String getOriginalMessage() { return super.getMessage(); }
 
+    /**
+     * Method that allows accessing underlying processor that triggered
+     * this exception; typically either {@link JsonParser} or {@link JsonGenerator}
+     * for exceptions that originate from streaming API.
+     * Note that it is possible that `null` may be returned if code throwing
+     * exception either has no access to processor; or has not been retrofitted
+     * to set it; this means that caller needs to take care to check for nulls.
+     * Subtypes override this method with co-variant return type, for more
+     * type-safe access.
+     * 
+     * @return Originating processor, if available; null if not.
+     *
+     * @since 2.7
+     */
+    public Object getProcessor() { return null; }
+
     /*
     /**********************************************************
     /* Methods for sub-classes to use, override
diff --git a/src/main/java/com/fasterxml/jackson/core/TreeCodec.java b/src/main/java/com/fasterxml/jackson/core/TreeCodec.java
index b1037b6..9aa1232 100644
--- a/src/main/java/com/fasterxml/jackson/core/TreeCodec.java
+++ b/src/main/java/com/fasterxml/jackson/core/TreeCodec.java
@@ -10,8 +10,8 @@
  */
 public abstract class TreeCodec
 {
-    public abstract <T extends TreeNode> T readTree(JsonParser jp) throws IOException, JsonProcessingException;
-    public abstract void writeTree(JsonGenerator jg, TreeNode tree) throws IOException, JsonProcessingException;
+    public abstract <T extends TreeNode> T readTree(JsonParser p) throws IOException, JsonProcessingException;
+    public abstract void writeTree(JsonGenerator g, TreeNode tree) throws IOException, JsonProcessingException;
     public abstract TreeNode createArrayNode();
     public abstract TreeNode createObjectNode();
     public abstract JsonParser treeAsTokens(TreeNode node);
diff --git a/src/main/java/com/fasterxml/jackson/core/Version.java b/src/main/java/com/fasterxml/jackson/core/Version.java
index 48b9163..e43a684 100644
--- a/src/main/java/com/fasterxml/jackson/core/Version.java
+++ b/src/main/java/com/fasterxml/jackson/core/Version.java
@@ -19,7 +19,7 @@
     private static final long serialVersionUID = 1L;
 
     private final static Version UNKNOWN_VERSION = new Version(0, 0, 0, null, null, null);
-    
+
     protected final int _majorVersion;
 
     protected final int _minorVersion;
@@ -27,9 +27,9 @@
     protected final int _patchLevel;
 
     protected final String _groupId;
-    
+
     protected final String _artifactId;
-    
+
     /**
      * Additional information for snapshot versions; null for non-snapshot
      * (release) versions.
@@ -46,7 +46,7 @@
     {
         this(major, minor, patchLevel, snapshotInfo, null, null);
     }
-    
+
     public Version(int major, int minor, int patchLevel, String snapshotInfo,
             String groupId, String artifactId)
     {
@@ -64,20 +64,29 @@
      */
     public static Version unknownVersion() { return UNKNOWN_VERSION; }
 
-    public boolean isUknownVersion() { return (this == UNKNOWN_VERSION); }
+    /**
+     * @since 2.7 to replace misspelled {@link #isUknownVersion()}
+     */
+    public boolean isUnknownVersion() { return (this == UNKNOWN_VERSION); }
     public boolean isSnapshot() { return (_snapshotInfo != null && _snapshotInfo.length() > 0); }
-    
+
+    /**
+     * @deprecated Since 2.7 use correctly spelled method {@link #isUnknownVersion()}
+     */
+    @Deprecated
+    public boolean isUknownVersion() { return isUnknownVersion(); }
+
     public int getMajorVersion() { return _majorVersion; }
     public int getMinorVersion() { return _minorVersion; }
     public int getPatchLevel() { return _patchLevel; }
 
     public String getGroupId() { return _groupId; }
     public String getArtifactId() { return _artifactId; }
-    
+
     public String toFullString() {
         return _groupId + '/' + _artifactId + '/' + toString();
     }
-    
+
     @Override public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append(_majorVersion).append('.');
diff --git a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
index f806bdf..38302b5 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
@@ -171,35 +171,64 @@
         return this;
     }
 
-    @Override public JsonGenerator setFeatureMask(int newMask) {
+    @Override
+    @Deprecated
+    public JsonGenerator setFeatureMask(int newMask) {
         int changed = newMask ^ _features;
         _features = newMask;
-        if ((changed & DERIVED_FEATURES_MASK) != 0) {
-            _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(newMask);
-            if (Feature.ESCAPE_NON_ASCII.enabledIn(changed)) {
-                if (Feature.ESCAPE_NON_ASCII.enabledIn(newMask)) {
-                    setHighestNonEscapedChar(127);
-                } else {
-                    setHighestNonEscapedChar(0);
-                }
-            }
-            if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(changed)) {
-                if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newMask)) { // enabling
-                    if (_writeContext.getDupDetector() == null) { // but only if disabled currently
-                        _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this));
-                    }
-                } else { // disabling
-                    _writeContext = _writeContext.withDupDetector(null);
-                }
-            }
+        if (changed != 0) {
+            _checkStdFeatureChanges(newMask, changed);
         }
         return this;
     }
+
+    @Override // since 2.7
+    public JsonGenerator overrideStdFeatures(int values, int mask) {
+        int oldState = _features;
+        int newState = (oldState & ~mask) | (values & mask);
+        int changed = oldState ^ newState;
+        if (changed != 0) {
+            _features = newState;
+            _checkStdFeatureChanges(newState, changed);
+        }
+        return this;
+    }
+
+    /**
+     * Helper method called to verify changes to standard features.
+     *
+     * @param newFeatureFlags Bitflag of standard features after they were changed
+     * @param changedFeatures Bitflag of standard features for which setting
+     *    did change
+     *
+     * @since 2.7
+     */
+    protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
+    {
+        if ((changedFeatures & DERIVED_FEATURES_MASK) == 0) {
+            return;
+        }
+        _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(newFeatureFlags);
+        if (Feature.ESCAPE_NON_ASCII.enabledIn(changedFeatures)) {
+            if (Feature.ESCAPE_NON_ASCII.enabledIn(newFeatureFlags)) {
+                setHighestNonEscapedChar(127);
+            } else {
+                setHighestNonEscapedChar(0);
+            }
+        }
+        if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(changedFeatures)) {
+            if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newFeatureFlags)) { // enabling
+                if (_writeContext.getDupDetector() == null) { // but only if disabled currently
+                    _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this));
+                }
+            } else { // disabling
+                _writeContext = _writeContext.withDupDetector(null);
+            }
+        }
+    }
     
     @Override public JsonGenerator useDefaultPrettyPrinter() {
-        /* 28-Sep-2012, tatu: As per [Issue#84], should not override a
-         *  pretty printer if one already assigned.
-         */
+        // Should not override a pretty printer if one already assigned.
         if (getPrettyPrinter() != null) {
             return this;
         }
diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
index 7c97e2a..2d9ac42 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
@@ -50,12 +50,12 @@
     /**
      * Pointer to next available character in buffer
      */
-    protected int _inputPtr = 0;
+    protected int _inputPtr;
 
     /**
      * Index of character after last available one in the buffer.
      */
-    protected int _inputEnd = 0;
+    protected int _inputEnd;
 
     /*
     /**********************************************************
@@ -67,7 +67,7 @@
      * Number of characters/bytes that were contained in previous blocks
      * (blocks that were already processed prior to the current buffer).
      */
-    protected long _currInputProcessed = 0L;
+    protected long _currInputProcessed;
 
     /**
      * Current row location of current point in input buffer, starting
@@ -81,7 +81,7 @@
      * of not having column itself is that this only has to be updated
      * once per line.
      */
-    protected int _currInputRowStart = 0;
+    protected int _currInputRowStart;
 
     /*
     /**********************************************************
@@ -97,7 +97,7 @@
      * For big (gigabyte-sized) sizes are possible, needs to be long,
      * unlike pointers and sizes related to in-memory buffers.
      */
-    protected long _tokenInputTotal = 0; 
+    protected long _tokenInputTotal;
 
     /**
      * Input row on which current token starts, 1-based
@@ -108,7 +108,7 @@
      * Column on input row that current token starts; 0-based (although
      * in the end it'll be converted to 1-based)
      */
-    protected int _tokenInputCol = 0;
+    protected int _tokenInputCol;
 
     /*
     /**********************************************************
@@ -147,20 +147,20 @@
      * using {@link #getTextCharacters} method (instead of String
      * returning alternatives)
      */
-    protected char[] _nameCopyBuffer = null;
+    protected char[] _nameCopyBuffer;
 
     /**
      * Flag set to indicate whether the field name is available
      * from the name copy buffer or not (in addition to its String
      * representation  being available via read context)
      */
-    protected boolean _nameCopied = false;
+    protected boolean _nameCopied;
 
     /**
      * ByteArrayBuilder is needed if 'getBinaryValue' is called. If so,
      * we better reuse it for remainder of content.
      */
-    protected ByteArrayBuilder _byteArrayBuilder = null;
+    protected ByteArrayBuilder _byteArrayBuilder;
 
     /**
      * We will hold on to decoded binary data, for duration of
@@ -326,23 +326,54 @@
         }
         return this;
     }
-    
+
     @Override
+    @Deprecated
     public JsonParser setFeatureMask(int newMask) {
         int changes = (_features ^ newMask);
         if (changes != 0) {
             _features = newMask;
-            if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newMask)) { // enabling
-                if (_parsingContext.getDupDetector() == null) { // but only if disabled currently
-                    _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this));
-                }
-            } else { // disabling
-                _parsingContext = _parsingContext.withDupDetector(null);
-            }
+            _checkStdFeatureChanges(newMask, changes);
         }
         return this;
     }
-    
+
+    @Override // since 2.7
+    public JsonParser overrideStdFeatures(int values, int mask) {
+        int oldState = _features;
+        int newState = (oldState & ~mask) | (values & mask);
+        int changed = oldState ^ newState;
+        if (changed != 0) {
+            _features = newState;
+            _checkStdFeatureChanges(newState, changed);
+        }
+        return this;
+    }
+
+    /**
+     * Helper method called to verify changes to standard features.
+     *
+     * @param newFeatureFlags Bitflag of standard features after they were changed
+     * @param changedFeatures Bitflag of standard features for which setting
+     *    did change
+     *
+     * @since 2.7
+     */
+    protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
+    {
+        int f = Feature.STRICT_DUPLICATE_DETECTION.getMask();
+        
+        if ((changedFeatures & f) != 0) {
+            if ((newFeatureFlags & f) != 0) {
+                if (_parsingContext.getDupDetector() == null) {
+                    _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this));
+                } else { // disabling
+                    _parsingContext = _parsingContext.withDupDetector(null);
+                }
+            }
+        }
+    }
+
     /*
     /**********************************************************
     /* JsonParser impl
@@ -356,7 +387,7 @@
     @Override public String getCurrentName() throws IOException {
         // [JACKSON-395]: start markers require information from parent
         if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
-            JsonReadContext parent = _parsingContext.getParent();
+            JsonReadContext parent = _parsingContext.clearAndGetParent();
             return parent.getCurrentName();
         }
         return _parsingContext.getCurrentName();
diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
index 310ee4e..b6810a9 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
@@ -265,10 +265,7 @@
     public int getValueAsInt() throws IOException
     {
         JsonToken t = _currToken;
-        if (t == JsonToken.VALUE_NUMBER_INT) {
-            return getIntValue();
-        }
-        if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+        if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
             return getIntValue();
         }
         return getValueAsInt(0);
@@ -278,10 +275,7 @@
     public int getValueAsInt(int defaultValue) throws IOException
     {
         JsonToken t = _currToken;
-        if (t == JsonToken.VALUE_NUMBER_INT) {
-            return getIntValue();
-        }
-        if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+        if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
             return getIntValue();
         }
         if (t != null) {
@@ -312,10 +306,7 @@
     public long getValueAsLong() throws IOException
     {
         JsonToken t = _currToken;
-        if (t == JsonToken.VALUE_NUMBER_INT) {
-            return getLongValue();
-        }
-        if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+        if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
             return getLongValue();
         }
         return getValueAsLong(0L);
@@ -325,10 +316,7 @@
     public long getValueAsLong(long defaultValue) throws IOException
     {
         JsonToken t = _currToken;
-        if (t == JsonToken.VALUE_NUMBER_INT) {
-            return getLongValue();
-        }
-        if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+        if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
             return getLongValue();
         }
         if (t != null) {
@@ -542,7 +530,7 @@
     }
 
     protected final JsonParseException _constructError(String msg, Throwable t) {
-        return new JsonParseException(msg, getCurrentLocation(), t);
+        return new JsonParseException(this, msg, t);
     }
 
     protected static byte[] _asciiBytes(String str) {
@@ -552,7 +540,7 @@
         }
         return b;
     }
-    
+
     protected static String _ascii(byte[] b) {
         try {
             return new String(b, "US-ASCII");
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
index 8468a37..1c7bed3 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
@@ -55,7 +55,7 @@
      * Marked as deprecated since its status is uncertain.
      */
     @Deprecated
-    protected boolean _includeImmediateParent = false;
+    protected boolean _includeImmediateParent;
 
     /*
     /**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
index 0d65bff..7900229 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
@@ -57,7 +57,7 @@
      * Marked as deprecated since its status is uncertain.
      */
     @Deprecated
-    protected boolean _includeImmediateParent = false;
+    protected boolean _includeImmediateParent;
     
     /*
     /**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java
index fcca317..14848bb 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java
@@ -25,7 +25,7 @@
     /**********************************************************
      */
 
-    protected TokenFilterContext _child = null;
+    protected TokenFilterContext _child;
 
     /*
     /**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
index 0216fe0..4c616fc 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
@@ -19,7 +19,7 @@
      * Lookup table used for determining which input characters
      * need special handling when contained in text segment.
      */
-    final static int[] sInputCodes;
+    private final static int[] sInputCodes;
     static {
         /* 96 would do for most cases (backslash is ASCII 94)
          * but if we want to do lookups by raw bytes it's better
@@ -40,7 +40,7 @@
      * Additionally we can combine UTF-8 decoding info into similar
      * data table.
      */
-    final static int[] sInputCodesUTF8;
+    private final static int[] sInputCodesUTF8;
     static {
         final int[] table = new int[sInputCodes.length];
         System.arraycopy(sInputCodes, 0, table, 0, table.length);
@@ -70,7 +70,7 @@
      * Basically this is list of 8-bit ASCII characters that are legal
      * as part of Javascript identifier
      */
-    final static int[] sInputCodesJsNames;
+    private final static int[] sInputCodesJsNames;
     static {
         final int[] table = new int[256];
         // Default is "not a name char", mark ones that are
@@ -97,7 +97,7 @@
      * code as ok. They will be validated at a later point, when decoding
      * name
      */
-    final static int[] sInputCodesUtf8JsNames;
+    private final static int[] sInputCodesUtf8JsNames;
     static {
         final int[] table = new int[256];
         // start with 8-bit JS names
@@ -110,7 +110,7 @@
      * Decoding table used to quickly determine characters that are
      * relevant within comment content.
      */
-    final static int[] sInputCodesComment;
+    private final static int[] sInputCodesComment;
     static {
         final int[] buf = new int[256];
         // but first: let's start with UTF-8 multi-byte markers:
@@ -130,7 +130,7 @@
      * 
      * @since 2.3
      */
-    final static int[] sInputCodesWS;
+    private final static int[] sInputCodesWS;
     static {
         // but first: let's start with UTF-8 multi-byte markers:
         final int[] buf = new int[256];
@@ -153,7 +153,7 @@
      * Lookup table used for determining which output characters in
      * 7-bit ASCII range need to be quoted.
      */
-    final static int[] sOutputEscapes128;
+    private final static int[] sOutputEscapes128;
     static {
         int[] table = new int[128];
         // Control chars need generic escape sequence
@@ -180,7 +180,7 @@
      * range. For actual hex digits, contains corresponding value;
      * for others -1.
      */
-    final static int[] sHexValues = new int[128];
+    private final static int[] sHexValues = new int[128];
     static {
         Arrays.fill(sHexValues, -1);
         for (int i = 0; i < 10; ++i) {
diff --git a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
index 84fefc1..a4675be 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
@@ -56,33 +56,33 @@
      * Reference to the allocated I/O buffer for low-level input reading,
      * if any allocated.
      */
-    protected byte[] _readIOBuffer = null;
+    protected byte[] _readIOBuffer;
 
     /**
      * Reference to the allocated I/O buffer used for low-level
      * encoding-related buffering.
      */
-    protected byte[] _writeEncodingBuffer = null;
+    protected byte[] _writeEncodingBuffer;
     
     /**
      * Reference to the buffer allocated for temporary use with
      * base64 encoding or decoding.
      */
-    protected byte[] _base64Buffer = null;
+    protected byte[] _base64Buffer;
 
     /**
      * Reference to the buffer allocated for tokenization purposes,
      * in which character input is read, and from which it can be
      * further returned.
      */
-    protected char[] _tokenCBuffer = null;
+    protected char[] _tokenCBuffer;
 
     /**
      * Reference to the buffer allocated for buffering it for
      * output, before being encoded: generally this means concatenating
      * output, then encoding when buffer fills up.
      */
-    protected char[] _concatCBuffer = null;
+    protected char[] _concatCBuffer;
 
     /**
      * Reference temporary buffer Parser instances need if calling
@@ -90,7 +90,7 @@
      * Regular text buffer can not be used as it may contain textual
      * representation of the value token.
      */
-    protected char[] _nameCopyBuffer = null;
+    protected char[] _nameCopyBuffer;
 
     /*
     /**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
index 523c401..0cdf8c7 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
@@ -14,8 +14,8 @@
 
     final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE);
 
-    final static char[] LEAD_3 = new char[4000];
-    final static char[] FULL_3 = new char[4000];
+    private final static char[] LEAD_3 = new char[4000];
+    private final static char[] FULL_3 = new char[4000];
     static {
         /* Let's fill it with NULLs for ignorable leading digits,
          * and digit chars for others
@@ -42,17 +42,17 @@
         }
     }
 
-    final static byte[] FULL_TRIPLETS_B = new byte[4000];
+    private final static byte[] FULL_TRIPLETS_B = new byte[4000];
     static {
         for (int i = 0; i < 4000; ++i) {
             FULL_TRIPLETS_B[i] = (byte) FULL_3[i];
         }
     }
     
-    final static String[] sSmallIntStrs = new String[] {
+    private final static String[] sSmallIntStrs = new String[] {
         "0","1","2","3","4","5","6","7","8","9","10"
     };
-    final static String[] sSmallIntStrs2 = new String[] {
+    private final static String[] sSmallIntStrs2 = new String[] {
         "-1","-2","-3","-4","-5","-6","-7","-8","-9","-10"
     };
 
diff --git a/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java b/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java
index 787b3ad..34b126c 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java
@@ -39,12 +39,12 @@
     /**
      * Total read character count; used for error reporting purposes
      */
-    protected int _charCount = 0;
+    protected int _charCount;
 
     /**
      * Total read byte count; used for error reporting purposes
      */
-    protected int _byteCount = 0;
+    protected int _byteCount;
 
     protected final boolean _managedBuffers;
     
@@ -81,7 +81,7 @@
         }
     }
 
-    protected char[] _tmpBuf = null;
+    protected char[] _tmpBuf;
 
     /**
      * Although this method is implemented by the base class, AND it should
diff --git a/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java b/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
index ab358d9..3672f88 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
@@ -24,7 +24,7 @@
      * To do this, both pairs must be known first; and since it is possible
      * pairs may be split, we need temporary storage for the first half
      */
-    private int _surrogate = 0;
+    private int _surrogate;
 
     public UTF8Writer(IOContext ctxt, OutputStream out)
     {
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
index f59e032..d37079b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
@@ -73,7 +73,7 @@
 
     protected boolean _bigEndian = true;
 
-    protected int _bytesPerChar = 0; // 0 means "dunno yet"
+    protected int _bytesPerChar; // 0 means "dunno yet"
 
     /*
     /**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java b/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
index 628556b..e02150c 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
@@ -20,7 +20,7 @@
 public class DupDetector
 {
     /**
-     * We need to store a back-reference here to parser/generator, unfortunately.
+     * We need to store a back-reference here to parser/generator.
      */
     protected final Object _source;
 
@@ -63,7 +63,14 @@
         // do generators have a way to provide Location? Apparently not...
         return null;
     }
-    
+
+    /**
+     * @since 2.7
+     */
+    public Object getSource() {
+        return _source;
+    }
+
     public boolean isDup(String name) throws JsonParseException
     {
         if (_firstName == null) {
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
index 9ce93e4..c09d2cf 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
@@ -95,7 +95,8 @@
         super(features, codec);
         _ioContext = ctxt;
         if (isEnabled(Feature.ESCAPE_NON_ASCII)) {
-            setHighestNonEscapedChar(127);
+            // inlined `setHighestNonEscapedChar()`
+            _maximumNonEscapedChar = 127;
         }
     }
 
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java b/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
index 333d3ca..3520b2b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
@@ -30,7 +30,7 @@
     /**********************************************************
      */
 
-    protected JsonReadContext _child = null;
+    protected JsonReadContext _child;
 
     /*
     /**********************************************************
@@ -103,20 +103,10 @@
     /**********************************************************
      */
 
-    @Deprecated // since 2.3, use variant that takes dup detector
-    public static JsonReadContext createRootContext(int lineNr, int colNr) {
-        return createRootContext(lineNr, colNr, null);
-    }
-
     public static JsonReadContext createRootContext(int lineNr, int colNr, DupDetector dups) {
         return new JsonReadContext(null, dups, TYPE_ROOT, lineNr, colNr);
     }
 
-    @Deprecated // since 2.3, use variant that takes dup detector
-    public static JsonReadContext createRootContext() {
-        return createRootContext(null);
-    }
-
     public static JsonReadContext createRootContext(DupDetector dups) {
         return new JsonReadContext(null, dups, TYPE_ROOT, 1, 0);
     }
@@ -152,6 +142,22 @@
     @Override public String getCurrentName() { return _currentName; }
     @Override public JsonReadContext getParent() { return _parent; }
 
+    /**
+     * Method that can be used to both clear the accumulated references
+     * (specifically value set with {@link #setCurrentValue(Object)})
+     * that should not be retained, and returns parent (as would
+     * {@link #getParent()} do). Typically called when closing the active
+     * context when encountering {@link JsonToken#END_ARRAY} or
+     * {@link JsonToken#END_OBJECT}.
+     *
+     * @since 2.7
+     */
+    public JsonReadContext clearAndGetParent() {
+        _currentValue = null;
+        // could also clear the current name, but seems cheap enough to leave?
+        return _parent;
+    }
+
     /*
     /**********************************************************
     /* Extended API
@@ -194,10 +200,12 @@
 
     private void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
         if (dd.isDup(name)) {
-            throw new JsonParseException("Duplicate field '"+name+"'", dd.findLocation());
+            Object src = dd.getSource();
+            throw new JsonParseException(((src instanceof JsonGenerator) ? ((JsonParser) src) : null),
+                    "Duplicate field '"+name+"'");
         }
     }
-    
+
     /*
     /**********************************************************
     /* Overridden standard methods
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
index f15bd54..a9c863e 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
@@ -35,7 +35,7 @@
     /**********************************************************
      */
 
-    protected JsonWriteContext _child = null;
+    protected JsonWriteContext _child;
 
     /*
     /**********************************************************
@@ -136,6 +136,22 @@
     @Override public final JsonWriteContext getParent() { return _parent; }
     @Override public final String getCurrentName() { return _currentName; }
 
+    /**
+     * Method that can be used to both clear the accumulated references
+     * (specifically value set with {@link #setCurrentValue(Object)})
+     * that should not be retained, and returns parent (as would
+     * {@link #getParent()} do). Typically called when closing the active
+     * context when encountering {@link JsonToken#END_ARRAY} or
+     * {@link JsonToken#END_OBJECT}.
+     *
+     * @since 2.7
+     */
+    public JsonWriteContext clearAndGetParent() {
+        _currentValue = null;
+        // could also clear the current name, but seems cheap enough to leave?
+        return _parent;
+    }
+    
     public DupDetector getDupDetector() {
         return _dups;
     }
@@ -156,7 +172,11 @@
     }
 
     private final void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
-        if (dd.isDup(name)) { throw new JsonGenerationException("Duplicate field '"+name+"'"); }
+        if (dd.isDup(name)) {
+            Object src = dd.getSource();
+            throw new JsonGenerationException("Duplicate field '"+name+"'",
+                    ((src instanceof JsonGenerator) ? ((JsonGenerator) src) : null));
+        }
     }
     
     public int writeValue() {
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
index 1bc9d34..bb211ba 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
@@ -50,7 +50,7 @@
      * buffer.
      */
     protected boolean _bufferRecyclable;
-    
+
     /*
     /**********************************************************
     /* Configuration
@@ -60,7 +60,7 @@
     protected ObjectCodec _objectCodec;
 
     final protected CharsToNameCanonicalizer _symbols;
-    
+
     final protected int _hashSeed;
 
     /*
@@ -68,13 +68,33 @@
     /* Parsing state
     /**********************************************************
      */
-    
+
     /**
      * Flag that indicates that the current token has not yet
      * been fully processed, and needs to be finished for
      * some access (or skipped to obtain the next token)
      */
-    protected boolean _tokenIncomplete = false;
+    protected boolean _tokenIncomplete;
+
+    /**
+     * Value of {@link #_inputPtr} at the time when the first character of
+     * name token was read. Used for calculating token location when requested;
+     * combined with {@link #_currInputProcessed}, may be updated appropriately
+     * as needed.
+     *
+     * @since 2.7
+     */
+    protected long _nameStartOffset;
+
+    /**
+     * @since 2.7
+     */
+    protected int _nameStartRow;
+
+    /**
+     * @since 2.7
+     */
+    protected int _nameStartCol;
 
     /*
     /**********************************************************
@@ -85,7 +105,7 @@
     /**
      * Method called when caller wants to provide input buffer directly,
      * and it may or may not be recyclable use standard recycle context.
-     * 
+     *
      * @since 2.4
      */
     public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
@@ -130,7 +150,7 @@
 
     @Override public ObjectCodec getCodec() { return _objectCodec; }
     @Override public void setCodec(ObjectCodec c) { _objectCodec = c; }
-    
+
     @Override
     public int releaseBuffered(Writer w) throws IOException {
         int count = _inputEnd - _inputPtr;
@@ -146,8 +166,15 @@
     @Override
     protected boolean loadMore() throws IOException
     {
-        _currInputProcessed += _inputEnd;
-        _currInputRowStart -= _inputEnd;
+        final int bufSize = _inputEnd;
+
+        _currInputProcessed += bufSize;
+        _currInputRowStart -= bufSize;
+
+        // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+        //   this increase to avoid "moving" name-offset, resulting most likely
+        //   in negative value, which is fine as combine value remains unchanged.
+        _nameStartOffset -= bufSize;
 
         if (_reader != null) {
             int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
@@ -210,13 +237,13 @@
             }
         }
     }
-    
+
     /*
     /**********************************************************
     /* Public API, data access
     /**********************************************************
      */
-    
+
     /**
      * Method for accessing textual representation of the current event;
      * if no current event (before first call to {@link #nextToken}, or
@@ -238,7 +265,7 @@
     }
 
     // // // Let's override default impls for improved performance
-    
+
     // @since 2.1
     @Override
     public final String getValueAsString() throws IOException
@@ -255,7 +282,7 @@
         }
         return super.getValueAsString(null);
     }
-    
+
     // @since 2.1
     @Override
     public final String getValueAsString(String defValue) throws IOException {
@@ -308,7 +335,6 @@
                     _nameCopied = true;
                 }
                 return _nameCopyBuffer;
-    
             case ID_STRING:
                 if (_tokenIncomplete) {
                     _tokenIncomplete = false;
@@ -318,7 +344,6 @@
             case ID_NUMBER_INT:
             case ID_NUMBER_FLOAT:
                 return _textBuffer.getTextBuffer();
-                
             default:
                 return _currToken.asCharArray();
             }
@@ -331,7 +356,6 @@
     {
         if (_currToken != null) { // null only before/after document
             switch (_currToken.id()) {
-                
             case ID_FIELD_NAME:
                 return _parsingContext.getCurrentName().length();
             case ID_STRING:
@@ -343,7 +367,6 @@
             case ID_NUMBER_INT:
             case ID_NUMBER_FLOAT:
                 return _textBuffer.size();
-                
             default:
                 return _currToken.asCharArray().length;
             }
@@ -404,7 +427,7 @@
         }
         return _binaryValue;
     }
-    
+
     @Override
     public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
     {
@@ -562,8 +585,6 @@
     @Override
     public final JsonToken nextToken() throws IOException
     {
-        _numTypesValid = NR_UNKNOWN;
-
         /* First: field names are special -- we will always tokenize
          * (part of) value along with field name to simplify
          * state handling. If so, can and need to use secondary token:
@@ -571,6 +592,9 @@
         if (_currToken == JsonToken.FIELD_NAME) {
             return _nextAfterName();
         }
+        // But if we didn't already have a name, and (partially?) decode number,
+        // need to ensure no numeric information is leaked
+        _numTypesValid = NR_UNKNOWN;
         if (_tokenIncomplete) {
             _skipString(); // only strings can be partial
         }
@@ -582,30 +606,24 @@
             close();
             return (_currToken = null);
         }
-
-        /* First, need to ensure we know the starting location of token
-         * after skipping leading white space
-         */
-        _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
-        _tokenInputRow = _currInputRow;
-        _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
-        // finally: clear any data retained so far
+        // clear any data retained so far
         _binaryValue = null;
 
         // Closing scope?
         if (i == INT_RBRACKET) {
+            _updateLocation();
             if (!_parsingContext.inArray()) {
                 _reportMismatchedEndMarker(i, '}');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             return (_currToken = JsonToken.END_ARRAY);
         }
         if (i == INT_RCURLY) {
+            _updateLocation();
             if (!_parsingContext.inObject()) {
                 _reportMismatchedEndMarker(i, ']');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             return (_currToken = JsonToken.END_OBJECT);
         }
 
@@ -614,18 +632,19 @@
             i = _skipComma(i);
         }
 
-        /* And should we now have a name? Always true for
-         * Object contexts, since the intermediate 'expect-value'
-         * state is never retained.
+        /* And should we now have a name? Always true for Object contexts, since
+         * the intermediate 'expect-value' state is never retained.
          */
         boolean inObject = _parsingContext.inObject();
         if (inObject) {
-           // First, field name itself:
+            // First, field name itself:
+            _updateNameLocation();
             String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
             _parsingContext.setCurrentName(name);
             _currToken = JsonToken.FIELD_NAME;
             i = _skipColon();
         }
+        _updateLocation();
 
         // Ok: we must have a value... what is it?
 
@@ -703,6 +722,9 @@
         _nameCopied = false; // need to invalidate if it was copied
         JsonToken t = _nextToken;
         _nextToken = null;
+
+// !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
+        
         // Also: may need to start new context?
         if (t == JsonToken.START_ARRAY) {
             _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
@@ -718,14 +740,86 @@
     /**********************************************************
      */
 
-    /*
+    // Implemented since 2.7
     @Override
-    public boolean nextFieldName(SerializableString str)
-        throws IOException
+    public boolean nextFieldName(SerializableString sstr) throws IOException
     {
-    
+        // // // Note: most of code below is copied from nextToken()
+
+        _numTypesValid = NR_UNKNOWN;
+        if (_currToken == JsonToken.FIELD_NAME) {
+            _nextAfterName();
+            return false;
+        }
+        if (_tokenIncomplete) {
+            _skipString();
+        }
+        int i = _skipWSOrEnd();
+        if (i < 0) {
+            close();
+            _currToken = null;
+            return false;
+        }
+        _binaryValue = null;
+
+        if (i == INT_RBRACKET) {
+            _updateLocation();
+            if (!_parsingContext.inArray()) {
+                _reportMismatchedEndMarker(i, '}');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_ARRAY;
+            return false;
+        }
+        if (i == INT_RCURLY) {
+            _updateLocation();
+            if (!_parsingContext.inObject()) {
+                _reportMismatchedEndMarker(i, ']');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_OBJECT;
+            return false;
+        }
+        if (_parsingContext.expectComma()) {
+            i = _skipComma(i);
+        }
+
+        if (!_parsingContext.inObject()) {
+            _updateLocation();
+            _nextTokenNotInObject(i);
+            return false;
+        }
+
+        _updateNameLocation();
+        if (i == INT_QUOTE) {
+            // when doing literal match, must consider escaping:
+            char[] nameChars = sstr.asQuotedChars();
+            final int len = nameChars.length;
+
+            // Require 4 more bytes for faster skipping of colon that follows name
+            if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
+                // first check length match by
+                final int end = _inputPtr+len;
+                if (_inputBuffer[end] == '"') {
+                    int offset = 0;
+                    int ptr = _inputPtr;
+                    while (true) {
+                        if (ptr == end) { // yes, match!
+                            _parsingContext.setCurrentName(sstr.getValue());
+                            _isNextTokenNameYes(_skipColonFast(ptr+1));
+                            return true;
+                        }
+                        if (nameChars[offset] != _inputBuffer[ptr]) {
+                            break;
+                        }
+                        ++offset;
+                        ++ptr;
+                    }
+                }
+            }
+        }
+        return _isNextTokenNameMaybe(i, sstr.getValue());
     }
-    */
 
     @Override
     public String nextFieldName() throws IOException
@@ -746,40 +840,41 @@
             _currToken = null;
             return null;
         }
-        _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
-        _tokenInputRow = _currInputRow;
-        _tokenInputCol = _inputPtr - _currInputRowStart - 1;
         _binaryValue = null;
         if (i == INT_RBRACKET) {
+            _updateLocation();
             if (!_parsingContext.inArray()) {
                 _reportMismatchedEndMarker(i, '}');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             _currToken = JsonToken.END_ARRAY;
             return null;
         }
         if (i == INT_RCURLY) {
+            _updateLocation();
             if (!_parsingContext.inObject()) {
                 _reportMismatchedEndMarker(i, ']');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             _currToken = JsonToken.END_OBJECT;
             return null;
         }
         if (_parsingContext.expectComma()) {
             i = _skipComma(i);
         }
-
         if (!_parsingContext.inObject()) {
+            _updateLocation();
             _nextTokenNotInObject(i);
             return null;
         }
 
+        _updateNameLocation();
         String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
         _parsingContext.setCurrentName(name);
         _currToken = JsonToken.FIELD_NAME;
         i = _skipColon();
 
+        _updateLocation();
         if (i == INT_QUOTE) {
             _tokenIncomplete = true;
             _nextToken = JsonToken.VALUE_STRING;
@@ -832,6 +927,110 @@
         return name;
     }
 
+    private final void _isNextTokenNameYes(int i) throws IOException
+    {
+        _currToken = JsonToken.FIELD_NAME;
+        _updateLocation();
+
+        switch (i) {
+        case '"':
+            _tokenIncomplete = true;
+            _nextToken = JsonToken.VALUE_STRING;
+            return;
+        case '[':
+            _nextToken = JsonToken.START_ARRAY;
+            return;
+        case '{':
+            _nextToken = JsonToken.START_OBJECT;
+            return;
+        case 't':
+            _matchToken("true", 1);
+            _nextToken = JsonToken.VALUE_TRUE;
+            return;
+        case 'f':
+            _matchToken("false", 1);
+            _nextToken = JsonToken.VALUE_FALSE;
+            return;
+        case 'n':
+            _matchToken("null", 1);
+            _nextToken = JsonToken.VALUE_NULL;
+            return;
+        case '-':
+            _nextToken = _parseNegNumber();
+            return;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            _nextToken = _parsePosNumber(i);
+            return;
+        }
+        _nextToken = _handleOddValue(i);
+    }
+
+    protected boolean _isNextTokenNameMaybe(int i, String nameToMatch) throws IOException
+    {
+        // // // and this is back to standard nextToken()
+        String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
+        _parsingContext.setCurrentName(name);
+        _currToken = JsonToken.FIELD_NAME;
+        i = _skipColon();
+        _updateLocation();
+        if (i == INT_QUOTE) {
+            _tokenIncomplete = true;
+            _nextToken = JsonToken.VALUE_STRING;
+            return nameToMatch.equals(name);
+        }
+        // Ok: we must have a value... what is it?
+        JsonToken t;
+        switch (i) {
+        case '-':
+            t = _parseNegNumber();
+            break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            t = _parsePosNumber(i);
+            break;
+        case 'f':
+            _matchFalse();
+            t = JsonToken.VALUE_FALSE;
+            break;
+        case 'n':
+            _matchNull();
+            t = JsonToken.VALUE_NULL;
+            break;
+        case 't':
+            _matchTrue();
+            t = JsonToken.VALUE_TRUE;
+            break;
+        case '[':
+            t = JsonToken.START_ARRAY;
+            break;
+        case '{':
+            t = JsonToken.START_OBJECT;
+            break;
+        default:
+            t = _handleOddValue(i);
+            break;
+        }
+        _nextToken = t;
+        return nameToMatch.equals(name);
+    }
+
     private final JsonToken _nextTokenNotInObject(int i) throws IOException
     {
         if (i == INT_QUOTE) {
@@ -874,7 +1073,7 @@
         }
         return (_currToken = _handleOddValue(i));
     }
-    
+
     // note: identical to one in UTF8StreamJsonParser
     @Override
     public final String nextTextValue() throws IOException
@@ -1015,15 +1214,15 @@
         if (ch == INT_0) {
             return _parseNumber2(false, startPtr);
         }
-            
+
         /* First, let's see if the whole number is contained within
          * the input buffer unsplit. This should be the common case;
          * and to simplify processing, we will just reparse contents
          * in the alternative case (number split on buffer boundary)
          */
-        
+
         int intLen = 1; // already got one
-        
+
         // First let's get the obligatory integer part:
         int_loop:
         while (true) {
@@ -1137,7 +1336,7 @@
             return _parseNumber2(true, startPtr);
         }
         int intLen = 1; // already got one
-        
+
         // First let's get the obligatory integer part:
         int_loop:
         while (true) {
@@ -1312,7 +1511,7 @@
         // and offline the less common case
         return _verifyNLZ2();
     }
-        
+
     private char _verifyNLZ2() throws IOException
     {
         if (_inputPtr >= _inputEnd && !loadMore()) {
@@ -1334,7 +1533,7 @@
                     return '0';
                 }
                 ++_inputPtr; // skip previous zero
-                if (ch != '0') { // followed by other number; return 
+                if (ch != '0') { // followed by other number; return
                     break;
                 }
             }
@@ -1398,7 +1597,7 @@
         }
         _reportMissingRootWS(ch);
     }
-    
+
     /*
     /**********************************************************
     /* Internal methods, secondary parsing
@@ -1624,7 +1823,7 @@
         _reportUnexpectedChar(i, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
         return null;
     }
-    
+
     protected JsonToken _handleApos() throws IOException
     {
         char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
@@ -1665,7 +1864,7 @@
         _textBuffer.setCurrentLength(outPtr);
         return JsonToken.VALUE_STRING;
     }
-    
+
     private String _handleOddName2(int startPtr, int hash, int[] codes) throws IOException
     {
         _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
@@ -1709,7 +1908,7 @@
             return _symbols.findSymbol(buf, start, len, hash);
         }
     }
-  
+
     @Override
     protected final void _finishString() throws IOException
     {
@@ -1839,7 +2038,7 @@
     /* Internal methods, other parsing
     /**********************************************************
      */
-    
+
     /**
      * We actually need to check the character value here
      * (to see if we have \n following \r).
@@ -1853,7 +2052,7 @@
         ++_currInputRow;
         _currInputRowStart = _inputPtr;
     }
-    
+
     private final int _skipColon() throws IOException
     {
         if ((_inputPtr + 4) >= _inputEnd) {
@@ -1875,7 +2074,7 @@
                     if (i == INT_SLASH || i == INT_HASH) {
                         return _skipColon2(true);
                     }
-                    ++_inputPtr;                    
+                    ++_inputPtr;
                     return i;
                 }
             }
@@ -1949,7 +2148,55 @@
             }
         }
     }
- 
+
+    // Variant called when we know there's at least 4 more bytes available
+    private final int _skipColonFast(int ptr) throws IOException
+    {
+        int i = (int) _inputBuffer[ptr++];
+        if (i == INT_COLON) { // common case, no leading space
+            i = _inputBuffer[ptr++];
+            if (i > INT_SPACE) { // nor trailing
+                if (i != INT_SLASH && i != INT_HASH) {
+                    _inputPtr = ptr;
+                    return i;
+                }
+            } else if (i == INT_SPACE || i == INT_TAB) {
+                i = (int) _inputBuffer[ptr++];
+                if (i > INT_SPACE) {
+                    if (i != INT_SLASH && i != INT_HASH) {
+                        _inputPtr = ptr;
+                        return i;
+                    }
+                }
+            }
+            _inputPtr = ptr-1;
+            return _skipColon2(true); // true -> skipped colon
+        }
+        if (i == INT_SPACE || i == INT_TAB) {
+            i = _inputBuffer[ptr++];
+        }
+        boolean gotColon = (i == INT_COLON);
+        if (gotColon) {
+            i = _inputBuffer[ptr++];
+            if (i > INT_SPACE) {
+                if (i != INT_SLASH && i != INT_HASH) {
+                    _inputPtr = ptr;
+                    return i;
+                }
+            } else if (i == INT_SPACE || i == INT_TAB) {
+                i = (int) _inputBuffer[ptr++];
+                if (i > INT_SPACE) {
+                    if (i != INT_SLASH && i != INT_HASH) {
+                        _inputPtr = ptr;
+                        return i;
+                    }
+                }
+            }
+        }
+        _inputPtr = ptr-1;
+        return _skipColon2(gotColon);
+    }
+
     // Primary loop: no reloading, comment handling
     private final int _skipComma(int i) throws IOException
     {
@@ -2008,7 +2255,7 @@
         }
         throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
     }
-    
+
     private final int _skipWSOrEnd() throws IOException
     {
         // Let's handle first character separately since it is likely that
@@ -2036,7 +2283,7 @@
                 _throwInvalidSpace(i);
             }
         }
-        
+
         while (_inputPtr < _inputEnd) {
             i = (int) _inputBuffer[_inputPtr++];
             if (i > INT_SPACE) {
@@ -2092,7 +2339,7 @@
             }
         }
     }
-    
+
     private void _skipComment() throws IOException
     {
         if (!isEnabled(Feature.ALLOW_COMMENTS)) {
@@ -2151,7 +2398,7 @@
         _skipLine();
         return true;
     }
-    
+
     private void _skipLine() throws IOException
     {
         // Ok: need to find EOF or linefeed
@@ -2225,7 +2472,7 @@
         }
         return (char) value;
     }
-    
+
     private final void _matchTrue() throws IOException {
         int ptr = _inputPtr;
         if ((ptr + 3) < _inputEnd) {
@@ -2346,9 +2593,9 @@
                 }
             }
             int decodedData = bits;
-            
+
             // then second base64 char; can't get padding yet, nor ws
-            
+
             if (_inputPtr >= _inputEnd) {
                 loadMoreGuaranteed();
             }
@@ -2358,7 +2605,7 @@
                 bits = _decodeBase64Escape(b64variant, ch, 1);
             }
             decodedData = (decodedData << 6) | bits;
-            
+
             // third base64 char; can be padding, but not ws
             if (_inputPtr >= _inputEnd) {
                 loadMoreGuaranteed();
@@ -2431,6 +2678,51 @@
 
     /*
     /**********************************************************
+    /* Internal methods, location updating (refactored in 2.7)
+    /**********************************************************
+     */
+
+    @Override
+    public JsonLocation getTokenLocation()
+    {
+        final Object src = _ioContext.getSourceReference();
+        if (_currToken == JsonToken.FIELD_NAME) {
+            long total = _currInputProcessed + (_nameStartOffset-1);
+            return new JsonLocation(src,
+                    -1L, total, _nameStartRow, _nameStartCol);
+        }
+        return new JsonLocation(src,
+                -1L, _tokenInputTotal-1, _tokenInputRow, _tokenInputCol);
+    }
+
+    @Override
+    public JsonLocation getCurrentLocation() {
+        int col = _inputPtr - _currInputRowStart + 1; // 1-based
+        return new JsonLocation(_ioContext.getSourceReference(),
+                -1L, _currInputProcessed + _inputPtr,
+                _currInputRow, col);
+    }
+
+    // @since 2.7
+    private final void _updateLocation()
+    {
+        int ptr = _inputPtr;
+        _tokenInputTotal = _currInputProcessed + ptr;
+        _tokenInputRow = _currInputRow;
+        _tokenInputCol = ptr - _currInputRowStart;
+    }
+
+    // @since 2.7
+    private final void _updateNameLocation()
+    {
+        int ptr = _inputPtr;
+        _nameStartOffset = ptr;
+        _nameStartRow = _currInputRow;
+        _nameStartCol = ptr - _currInputRowStart;
+    }
+
+    /*
+    /**********************************************************
     /* Error reporting
     /**********************************************************
      */
@@ -2438,7 +2730,7 @@
     protected void _reportInvalidToken(String matchedPart) throws IOException {
         _reportInvalidToken(matchedPart, "'null', 'true', 'false' or NaN");
     }
-    
+
     protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
     {
         StringBuilder sb = new StringBuilder(matchedPart);
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
index 6d32010..84a6af2 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
@@ -27,7 +27,7 @@
     // intermediate copies only made up to certain length...
     private final static int MAX_BYTES_TO_BUFFER = 512;
 
-    final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
+    private final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
 
     private final static byte[] NULL_BYTES = { 'n', 'u', 'l', 'l' };
     private final static byte[] TRUE_BYTES = { 't', 'r', 'u', 'e' };
@@ -54,7 +54,7 @@
      * Pointer to the position right beyond the last character to output
      * (end marker; may be past the buffer)
      */
-    protected int _outputTail = 0;
+    protected int _outputTail;
 
     /**
      * End marker of the output buffer; one past the last valid position
@@ -305,7 +305,7 @@
             }
             _outputBuffer[_outputTail++] = BYTE_RBRACKET;
         }
-        _writeContext = _writeContext.getParent();
+        _writeContext = _writeContext.clearAndGetParent();
     }
 
     @Override
@@ -337,7 +337,7 @@
             }
             _outputBuffer[_outputTail++] = BYTE_RCURLY;
         }
-        _writeContext = _writeContext.getParent();
+        _writeContext = _writeContext.clearAndGetParent();
     }
 
     /**
@@ -747,8 +747,7 @@
      */
 
     @Override
-    public void writeNumber(short s)
-        throws IOException, JsonGenerationException
+    public void writeNumber(short s) throws IOException
     {
         _verifyValueWrite(WRITE_NUMBER);
         // up to 5 digits and possible minus sign
@@ -772,8 +771,7 @@
     } 
     
     @Override
-    public void writeNumber(int i)
-        throws IOException, JsonGenerationException
+    public void writeNumber(int i) throws IOException
     {
         _verifyValueWrite(WRITE_NUMBER);
         // up to 10 digits and possible minus sign
@@ -798,8 +796,7 @@
     }    
 
     @Override
-    public void writeNumber(long l)
-        throws IOException, JsonGenerationException
+    public void writeNumber(long l) throws IOException
     {
         _verifyValueWrite(WRITE_NUMBER);
         if (_cfgNumbersAsStrings) {
@@ -824,8 +821,7 @@
     }
 
     @Override
-    public void writeNumber(BigInteger value)
-        throws IOException, JsonGenerationException
+    public void writeNumber(BigInteger value) throws IOException
     {
         _verifyValueWrite(WRITE_NUMBER);
         if (value == null) {
@@ -839,13 +835,11 @@
 
     
     @Override
-    public void writeNumber(double d)
-        throws IOException, JsonGenerationException
+    public void writeNumber(double d) throws IOException
     {
         if (_cfgNumbersAsStrings ||
-            // [JACKSON-139]
             (((Double.isNaN(d) || Double.isInfinite(d))
-                && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) {
+                && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
             writeString(String.valueOf(d));
             return;
         }
@@ -855,13 +849,12 @@
     }
 
     @Override
-    public void writeNumber(float f)
-        throws IOException, JsonGenerationException
+    public void writeNumber(float f) throws IOException
     {
         if (_cfgNumbersAsStrings ||
             // [JACKSON-139]
             (((Float.isNaN(f) || Float.isInfinite(f))
-                && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) {
+                && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
             writeString(String.valueOf(f));
             return;
         }
@@ -871,17 +864,17 @@
     }
 
     @Override
-    public void writeNumber(BigDecimal value)
-        throws IOException, JsonGenerationException
+    public void writeNumber(BigDecimal value) throws IOException
     {
         // Don't really know max length for big decimal, no point checking
         _verifyValueWrite(WRITE_NUMBER);
         if (value == null) {
             _writeNull();
         } else if (_cfgNumbersAsStrings) {
-            String raw = isEnabled(Feature.WRITE_BIGDECIMAL_AS_PLAIN) ? value.toPlainString() : value.toString();
+            String raw = Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)
+                    ? value.toPlainString() : value.toString();
             _writeQuotedRaw(raw);
-        } else if (isEnabled(Feature.WRITE_BIGDECIMAL_AS_PLAIN)) {
+        } else if (Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)) {
             writeRaw(value.toPlainString());
         } else {
             writeRaw(value.toString());
@@ -889,8 +882,7 @@
     }
 
     @Override
-    public void writeNumber(String encodedValue)
-        throws IOException, JsonGenerationException
+    public void writeNumber(String encodedValue) throws IOException
     {
         _verifyValueWrite(WRITE_NUMBER);
         if (_cfgNumbersAsStrings) {
@@ -914,8 +906,7 @@
     }
     
     @Override
-    public void writeBoolean(boolean state)
-        throws IOException, JsonGenerationException
+    public void writeBoolean(boolean state) throws IOException
     {
         _verifyValueWrite(WRITE_BOOLEAN);
         if ((_outputTail + 5) >= _outputEnd) {
@@ -928,8 +919,7 @@
     }
 
     @Override
-    public void writeNull()
-        throws IOException, JsonGenerationException
+    public void writeNull() throws IOException
     {
         _verifyValueWrite(WRITE_NULL);
         _writeNull();
@@ -1918,8 +1908,7 @@
         return inputOffset;
     }
 
-    protected final void _outputSurrogates(int surr1, int surr2)
-        throws IOException
+    protected final void _outputSurrogates(int surr1, int surr2) throws IOException
     {
         int c = _decodeSurrogate(surr1, surr2);
         if ((_outputTail + 4) > _outputEnd) {
@@ -1945,13 +1934,18 @@
     {
         byte[] bbuf = _outputBuffer;
         if (ch >= SURR1_FIRST && ch <= SURR2_LAST) { // yes, outside of BMP; add an escape
-            bbuf[outputPtr++] = BYTE_BACKSLASH;
-            bbuf[outputPtr++] = BYTE_u;
-            
-            bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
-            bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
-            bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
-            bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
+            // 23-Nov-2015, tatu: As per [core#223], may or may not want escapes;
+            //   it would be added here... but as things are, we do not have proper
+            //   access yet...
+//            if (Feature.ESCAPE_UTF8_SURROGATES.enabledIn(_features)) {
+                bbuf[outputPtr++] = BYTE_BACKSLASH;
+                bbuf[outputPtr++] = BYTE_u;
+                
+                bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
+                bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
+                bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
+                bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
+//            } else { ... }
         } else {
             bbuf[outputPtr++] = (byte) (0xe0 | (ch >> 12));
             bbuf[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
@@ -1959,7 +1953,7 @@
         }
         return outputPtr;
     }
-    
+
     private final void _writeNull() throws IOException
     {
         if ((_outputTail + 4) >= _outputEnd) {
@@ -1974,8 +1968,7 @@
      * 
      * @param charToEscape Character to escape using escape sequence (\\uXXXX)
      */
-    private int _writeGenericEscape(int charToEscape, int outputPtr)
-        throws IOException
+    private int _writeGenericEscape(int charToEscape, int outputPtr) throws IOException
     {
         final byte[] bbuf = _outputBuffer;
         bbuf[outputPtr++] = BYTE_BACKSLASH;
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
index cc04868..cc2c927 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
@@ -64,13 +64,33 @@
      * been fully processed, and needs to be finished for
      * some access (or skipped to obtain the next token)
      */
-    protected boolean _tokenIncomplete = false;
+    protected boolean _tokenIncomplete;
 
     /**
      * Temporary storage for partially parsed name bytes.
      */
     private int _quad1;
 
+    /**
+     * Value of {@link #_inputPtr} at the time when the first character of
+     * name token was read. Used for calculating token location when requested;
+     * combined with {@link #_currInputProcessed}, may be updated appropriately
+     * as needed.
+     *
+     * @since 2.7
+     */
+    protected int _nameStartOffset; 
+
+    /**
+     * @since 2.7
+     */
+    protected int _nameStartRow;
+
+    /**
+     * @since 2.7
+     */
+    protected int _nameStartCol;
+
     /*
     /**********************************************************
     /* Input buffering (from former 'StreamBasedParserBase')
@@ -168,9 +188,16 @@
     @Override
     protected final boolean loadMore() throws IOException
     {
+        final int bufSize = _inputEnd;
+
         _currInputProcessed += _inputEnd;
         _currInputRowStart -= _inputEnd;
-        
+
+        // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+        //   this increase to avoid "moving" name-offset, resulting most likely
+        //   in negative value, which is fine as combine value remains unchanged.
+        _nameStartOffset -= bufSize;
+
         if (_inputStream != null) {
             int space = _inputBuffer.length;
             if (space == 0) { // only occurs when we've been closed
@@ -206,9 +233,15 @@
         // Need to move remaining data in front?
         int amount = _inputEnd - _inputPtr;
         if (amount > 0 && _inputPtr > 0) {
-            _currInputProcessed += _inputPtr;
-            _currInputRowStart -= _inputPtr;
-            System.arraycopy(_inputBuffer, _inputPtr, _inputBuffer, 0, amount);
+            final int ptr = _inputPtr;
+
+            _currInputProcessed += ptr;
+            _currInputRowStart -= ptr;
+            // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+            //  (note: probably has little effect here but just in case)
+            _nameStartOffset -= ptr;
+
+            System.arraycopy(_inputBuffer, ptr, _inputBuffer, 0, amount);
             _inputEnd = amount;
         } else {
             _inputEnd = 0;
@@ -645,26 +678,6 @@
         return outputCount;
     }
 
-    // As per [Issue#108], must ensure we call the right method
-    @Override
-    public JsonLocation getTokenLocation()
-    {
-        return new JsonLocation(_ioContext.getSourceReference(),
-                getTokenCharacterOffset(), -1L, // bytes, chars
-                getTokenLineNr(),
-                getTokenColumnNr());
-    }
-
-    // As per [Issue#108], must ensure we call the right method
-    @Override
-    public JsonLocation getCurrentLocation()
-    {
-        int col = _inputPtr - _currInputRowStart + 1; // 1-based
-        return new JsonLocation(_ioContext.getSourceReference(),
-                _currInputProcessed + _inputPtr, -1L, // bytes, chars
-                _currInputRow, col);
-    }
-    
     /*
     /**********************************************************
     /* Public API, traversal, basic
@@ -678,7 +691,6 @@
     @Override
     public JsonToken nextToken() throws IOException
     {
-        _numTypesValid = NR_UNKNOWN;
         /* First: field names are special -- we will always tokenize
          * (part of) value along with field name to simplify
          * state handling. If so, can and need to use secondary token:
@@ -686,6 +698,9 @@
         if (_currToken == JsonToken.FIELD_NAME) {
             return _nextAfterName();
         }
+        // But if we didn't already have a name, and (partially?) decode number,
+        // need to ensure no numeric information is leaked
+        _numTypesValid = NR_UNKNOWN;
         if (_tokenIncomplete) {
             _skipString(); // only strings can be partial
         }
@@ -695,29 +710,24 @@
             close();
             return (_currToken = null);
         }
-
-        // First, need to ensure we know the starting location of token
-        // after skipping leading white space
-        _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
-        _tokenInputRow = _currInputRow;
-        _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
-        // finally: clear any data retained so far
+        // clear any data retained so far
         _binaryValue = null;
 
         // Closing scope?
         if (i == INT_RBRACKET) {
+            _updateLocation();
             if (!_parsingContext.inArray()) {
                 _reportMismatchedEndMarker(i, '}');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             return (_currToken = JsonToken.END_ARRAY);
         }
         if (i == INT_RCURLY) {
+            _updateLocation();
             if (!_parsingContext.inObject()) {
                 _reportMismatchedEndMarker(i, ']');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             return (_currToken = JsonToken.END_OBJECT);
         }
 
@@ -734,14 +744,17 @@
          * state is never retained.
          */
         if (!_parsingContext.inObject()) {
+            _updateLocation();
             return _nextTokenNotInObject(i);
         }
         // So first parse the field name itself:
+        _updateNameLocation();
         String n = _parseName(i);
         _parsingContext.setCurrentName(n);
         _currToken = JsonToken.FIELD_NAME;
 
         i = _skipColon();
+        _updateLocation();
 
         // Ok: we must have a value... what is it? Strings are very common, check first:
         if (i == INT_QUOTE) {
@@ -846,6 +859,9 @@
         _nameCopied = false; // need to invalidate if it was copied
         JsonToken t = _nextToken;
         _nextToken = null;
+
+ // !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
+        
         // Also: may need to start new context?
         if (t == JsonToken.START_ARRAY) {
             _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
@@ -865,7 +881,6 @@
     public boolean nextFieldName(SerializableString str) throws IOException
     {
         // // // Note: most of code below is copied from nextToken()
-        
         _numTypesValid = NR_UNKNOWN;
         if (_currToken == JsonToken.FIELD_NAME) { // can't have name right after name
             _nextAfterName();
@@ -880,27 +895,24 @@
             _currToken = null;
             return false;
         }
-        _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
-        _tokenInputRow = _currInputRow;
-        _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
-        // finally: clear any data retained so far
         _binaryValue = null;
 
         // Closing scope?
         if (i == INT_RBRACKET) {
+            _updateLocation();
             if (!_parsingContext.inArray()) {
                 _reportMismatchedEndMarker(i, '}');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             _currToken = JsonToken.END_ARRAY;
             return false;
         }
         if (i == INT_RCURLY) {
+            _updateLocation();
             if (!_parsingContext.inObject()) {
                 _reportMismatchedEndMarker(i, ']');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             _currToken = JsonToken.END_OBJECT;
             return false;
         }
@@ -914,11 +926,13 @@
         }
 
         if (!_parsingContext.inObject()) {
+            _updateLocation();
             _nextTokenNotInObject(i);
             return false;
         }
         
         // // // This part differs, name parsing
+        _updateNameLocation();
         if (i == INT_QUOTE) {
             // when doing literal match, must consider escaping:
             byte[] nameBytes = str.asQuotedUTF8();
@@ -969,25 +983,23 @@
             _currToken = null;
             return null;
         }
-        _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
-        _tokenInputRow = _currInputRow;
-        _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
         _binaryValue = null;
 
         if (i == INT_RBRACKET) {
+            _updateLocation();
             if (!_parsingContext.inArray()) {
                 _reportMismatchedEndMarker(i, '}');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             _currToken = JsonToken.END_ARRAY;
             return null;
         }
         if (i == INT_RCURLY) {
+            _updateLocation();
             if (!_parsingContext.inObject()) {
                 _reportMismatchedEndMarker(i, ']');
             }
-            _parsingContext = _parsingContext.getParent();
+            _parsingContext = _parsingContext.clearAndGetParent();
             _currToken = JsonToken.END_OBJECT;
             return null;
         }
@@ -999,17 +1011,19 @@
             }
             i = _skipWS();
         }
-
         if (!_parsingContext.inObject()) {
+            _updateLocation();
             _nextTokenNotInObject(i);
             return null;
         }
 
+        _updateNameLocation();
         final String nameStr = _parseName(i);
         _parsingContext.setCurrentName(nameStr);
         _currToken = JsonToken.FIELD_NAME;
 
         i = _skipColon();
+        _updateLocation();
         if (i == INT_QUOTE) {
             _tokenIncomplete = true;
             _nextToken = JsonToken.VALUE_STRING;
@@ -1110,6 +1124,7 @@
     private final void _isNextTokenNameYes(int i) throws IOException
     {
         _currToken = JsonToken.FIELD_NAME;
+        _updateLocation();
 
         switch (i) {
         case '"':
@@ -1152,8 +1167,7 @@
         }
         _nextToken = _handleUnexpectedValue(i);
     }
-    
-    
+
     private final boolean _isNextTokenNameMaybe(int i, SerializableString str) throws IOException
     {
         // // // and this is back to standard nextToken()
@@ -1163,6 +1177,7 @@
         final boolean match = n.equals(str.getValue());
         _currToken = JsonToken.FIELD_NAME;
         i = _skipColon();
+        _updateLocation();
 
         // Ok: we must have a value... what is it? Strings are very common, check first:
         if (i == INT_QUOTE) {
@@ -1853,7 +1868,7 @@
 
     /**
      * Method called when not even first 8 bytes are guaranteed
-     * to come consequtively. Happens rarely, so this is offlined;
+     * to come consecutively. Happens rarely, so this is offlined;
      * plus we'll also do full checks for escaping etc.
      */
     protected String slowParseName() throws IOException
@@ -1988,7 +2003,7 @@
     /**
      * Method called when we see non-white space character other
      * than double quote, when expecting a field name.
-     * In standard mode will just throw an expection; but
+     * In standard mode will just throw an exception; but
      * in non-standard modes may be able to parse name.
      */
     protected String _handleOddName(int ch) throws IOException
@@ -3608,6 +3623,54 @@
 
     /*
     /**********************************************************
+    /* Improved location updating (refactored in 2.7)
+    /**********************************************************
+     */
+
+    // As per [core#108], must ensure we call the right method
+    @Override
+    public JsonLocation getTokenLocation()
+    {
+        final Object src = _ioContext.getSourceReference();
+        if (_currToken == JsonToken.FIELD_NAME) {
+            long total = _currInputProcessed + (_nameStartOffset-1);
+            return new JsonLocation(src,
+                    total, -1L, _nameStartRow, _nameStartCol);
+        }
+        return new JsonLocation(src,
+                _tokenInputTotal-1, -1L, _tokenInputRow, _tokenInputCol);
+    }
+
+    // As per [core#108], must ensure we call the right method
+    @Override
+    public JsonLocation getCurrentLocation()
+    {
+        int col = _inputPtr - _currInputRowStart + 1; // 1-based
+        return new JsonLocation(_ioContext.getSourceReference(),
+                _currInputProcessed + _inputPtr, -1L, // bytes, chars
+                _currInputRow, col);
+    }
+
+    // @since 2.7
+    private final void _updateLocation()
+    {
+        _tokenInputRow = _currInputRow;
+        final int ptr = _inputPtr;
+        _tokenInputTotal = _currInputProcessed + ptr;
+        _tokenInputCol = ptr - _currInputRowStart;
+    }
+
+    // @since 2.7
+    private final void _updateNameLocation()
+    {
+        _nameStartRow = _currInputRow;
+        final int ptr = _inputPtr;
+        _nameStartOffset = ptr;
+        _nameStartCol = ptr - _currInputRowStart;
+    }
+
+    /*
+    /**********************************************************
     /* Internal methods, other
     /**********************************************************
      */
diff --git a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
index 4e91969..af871ce 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
@@ -17,7 +17,7 @@
     final protected static int SHORT_WRITE = 32;
 
     final protected static char[] HEX_CHARS = CharTypes.copyHexChars();
-    
+
     /*
     /**********************************************************
     /* Output buffering
@@ -25,7 +25,7 @@
      */
 
     final protected Writer _writer;
-    
+
     /**
      * Intermediate buffer in which contents are buffered before
      * being written using {@link #_writer}.
@@ -35,13 +35,13 @@
     /**
      * Pointer to the first buffered character to output
      */
-    protected int _outputHead = 0;
+    protected int _outputHead;
 
     /**
      * Pointer to the position right beyond the last character to output
      * (end marker; may point to position right beyond the end of the buffer)
      */
-    protected int _outputTail = 0;
+    protected int _outputTail;
 
     /**
      * End marker of the output buffer; one past the last valid position
@@ -121,6 +121,72 @@
         }
         _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
     }
+
+    protected void _writeFieldName(String name, boolean commaBefore) throws IOException
+    {
+        if (_cfgPrettyPrinter != null) {
+            _writePPFieldName(name, commaBefore);
+            return;
+        }
+        // for fast+std case, need to output up to 2 chars, comma, dquote
+        if ((_outputTail + 1) >= _outputEnd) {
+            _flushBuffer();
+        }
+        if (commaBefore) {
+            _outputBuffer[_outputTail++] = ',';
+        }
+        // Alternate mode, in which quoting of field names disabled?
+        if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
+            _writeString(name);
+            return;
+        }
+        // we know there's room for at least one more char
+        _outputBuffer[_outputTail++] = '"';
+        // The beef:
+        _writeString(name);
+        // and closing quotes; need room for one more char:
+        if (_outputTail >= _outputEnd) {
+            _flushBuffer();
+        }
+        _outputBuffer[_outputTail++] = '"';
+    }
+    
+    protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
+    {
+        if (_cfgPrettyPrinter != null) {
+            _writePPFieldName(name, commaBefore);
+            return;
+        }
+        // for fast+std case, need to output up to 2 chars, comma, dquote
+        if ((_outputTail + 1) >= _outputEnd) {
+            _flushBuffer();
+        }
+        if (commaBefore) {
+            _outputBuffer[_outputTail++] = ',';
+        }
+        // Alternate mode, in which quoting of field names disabled?
+        final char[] quoted = name.asQuotedChars();
+        if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
+            writeRaw(quoted, 0, quoted.length);
+            return;
+        }
+        // we know there's room for at least one more char
+        _outputBuffer[_outputTail++] = '"';
+        // The beef:
+        final int qlen = quoted.length;
+        if ((_outputTail + qlen + 1) >= _outputEnd) {
+            writeRaw(quoted, 0, qlen);
+            // and closing quotes; need room for one more char:
+            if (_outputTail >= _outputEnd) {
+                _flushBuffer();
+            }
+            _outputBuffer[_outputTail++] = '"';
+        } else {
+            System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
+            _outputTail += qlen;
+            _outputBuffer[_outputTail++] = '"';
+        }
+    }
     
     /*
     /**********************************************************
@@ -157,7 +223,7 @@
             }
             _outputBuffer[_outputTail++] = ']';
         }
-        _writeContext = _writeContext.getParent();
+        _writeContext = _writeContext.clearAndGetParent();
     }
 
     @Override
@@ -189,87 +255,14 @@
             }
             _outputBuffer[_outputTail++] = '}';
         }
-        _writeContext = _writeContext.getParent();
+        _writeContext = _writeContext.clearAndGetParent();
     }
 
-    protected void _writeFieldName(String name, boolean commaBefore) throws IOException
-    {
-        if (_cfgPrettyPrinter != null) {
-            _writePPFieldName(name, commaBefore);
-            return;
-        }
-        // for fast+std case, need to output up to 2 chars, comma, dquote
-        if ((_outputTail + 1) >= _outputEnd) {
-            _flushBuffer();
-        }
-        if (commaBefore) {
-            _outputBuffer[_outputTail++] = ',';
-        }
-
-        /* To support [JACKSON-46], we'll do this:
-         * (Question: should quoting of spaces (etc) still be enabled?)
-         */
-        if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
-            _writeString(name);
-            return;
-        }
-
-        // we know there's room for at least one more char
-        _outputBuffer[_outputTail++] = '"';
-        // The beef:
-        _writeString(name);
-        // and closing quotes; need room for one more char:
-        if (_outputTail >= _outputEnd) {
-            _flushBuffer();
-        }
-        _outputBuffer[_outputTail++] = '"';
-    }
-
-    protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
-    {
-        if (_cfgPrettyPrinter != null) {
-            _writePPFieldName(name, commaBefore);
-            return;
-        }
-        // for fast+std case, need to output up to 2 chars, comma, dquote
-        if ((_outputTail + 1) >= _outputEnd) {
-            _flushBuffer();
-        }
-        if (commaBefore) {
-            _outputBuffer[_outputTail++] = ',';
-        }
-        /* To support [JACKSON-46], we'll do this:
-         * (Question: should quoting of spaces (etc) still be enabled?)
-         */
-        final char[] quoted = name.asQuotedChars();
-        if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
-            writeRaw(quoted, 0, quoted.length);
-            return;
-        }
-        // we know there's room for at least one more char
-        _outputBuffer[_outputTail++] = '"';
-        // The beef:
-        final int qlen = quoted.length;
-        if ((_outputTail + qlen + 1) >= _outputEnd) {
-            writeRaw(quoted, 0, qlen);
-            // and closing quotes; need room for one more char:
-            if (_outputTail >= _outputEnd) {
-                _flushBuffer();
-            }
-            _outputBuffer[_outputTail++] = '"';
-        } else {
-            System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
-            _outputTail += qlen;
-            _outputBuffer[_outputTail++] = '"';
-        }
-    }
-    
     /**
      * Specialized version of <code>_writeFieldName</code>, off-lined
      * to keep the "fast path" as simple (and hopefully fast) as possible.
      */
-    protected void _writePPFieldName(String name, boolean commaBefore)
-        throws IOException, JsonGenerationException
+    protected void _writePPFieldName(String name, boolean commaBefore) throws IOException
     {
         if (commaBefore) {
             _cfgPrettyPrinter.writeObjectEntrySeparator(this);
@@ -292,8 +285,7 @@
         }
     }
 
-    protected void _writePPFieldName(SerializableString name, boolean commaBefore)
-        throws IOException, JsonGenerationException
+    protected void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
     {
         if (commaBefore) {
             _cfgPrettyPrinter.writeObjectEntrySeparator(this);
diff --git a/src/main/java/com/fasterxml/jackson/core/sym/BytesToNameCanonicalizer.java b/src/main/java/com/fasterxml/jackson/core/sym/BytesToNameCanonicalizer.java
deleted file mode 100644
index 7d610c1..0000000
--- a/src/main/java/com/fasterxml/jackson/core/sym/BytesToNameCanonicalizer.java
+++ /dev/null
@@ -1,1322 +0,0 @@
-package com.fasterxml.jackson.core.sym;
-
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.concurrent.atomic.AtomicReference;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.util.InternCache;
-
-/**
- * A caching symbol table implementation used for canonicalizing JSON field
- * names (as {@link Name}s which are constructed directly from a byte-based
- * input source).
- * Complications arise from trying to do efficient reuse and merging of
- * symbol tables, to be able to make use of usually shared vocabulary
- * of subsequent parsing runs.
- *
- * @deprecated Since 2.6, replaced by {@link ByteQuadsCanonicalizer}
- */
-@Deprecated
-public final class BytesToNameCanonicalizer
-{
-    private static final int DEFAULT_T_SIZE = 64;
-
-    /**
-     * Let's not expand symbol tables past some maximum size;
-     * this should protected against OOMEs caused by large documents
-     * with unique (~= random) names.
-     */
-    private static final int MAX_T_SIZE = 0x10000; // 64k entries == 256k mem
-    
-    /**
-     * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k;
-     * this corresponds to 64k main hash index. This should allow for enough distinct
-     * names for almost any case.
-     */
-    final static int MAX_ENTRIES_FOR_REUSE = 6000;
-
-    /**
-     * Also: to thwart attacks based on hash collisions (which may or may not
-     * be cheap to calculate), we will need to detect "too long"
-     * collision chains.
-     *<p>
-     * Note: longest chain we have been able to produce without malicious
-     * intent has been 10 (with "com.fasterxml.jackson.core.sym.TestSymbolTables");
-     * our setting should be reasonable here. Also note that overflow
-     * chains are shared between multiple primary cells, which could cause
-     * problems for lower values.
-     *<p>
-     * Also note that value was lowered from 255 (2.3 and earlier) to 100 for 2.4,
-     * but raised again to 200 for 2.5.2 (as per [core#187])
-     * 
-     * @since 2.1
-     */
-    private final static int MAX_COLL_CHAIN_LENGTH = 200;
-
-    /**
-     * No point in trying to construct tiny tables, just need to resize soon.
-     */
-    final static int MIN_HASH_SIZE = 16;
-
-    /**
-     * We will also need to define initial size for collision list,
-     * when copying it.
-     */
-    final static int INITIAL_COLLISION_LEN = 32;
-
-    /**
-     * Bucket index is 8 bits, and value 0 is reserved to represent
-     * 'empty' status.
-     */
-    final static int LAST_VALID_BUCKET = 0xFE;
-    
-    /*
-    /**********************************************************
-    /* Linkage, needed for merging symbol tables
-    /**********************************************************
-     */
-
-    /**
-     * Reference to the root symbol table, for child tables, so
-     * that they can merge table information back as necessary.
-     */
-    final protected BytesToNameCanonicalizer _parent;
-
-    /**
-     * Member that is only used by the root table instance: root
-     * passes immutable state into child instances, and children
-     * may return new state if they add entries to the table.
-     * Child tables do NOT use the reference.
-     */
-    final protected AtomicReference<TableInfo> _tableInfo;
-    
-    /**
-     * Seed value we use as the base to make hash codes non-static between
-     * different runs, but still stable for lifetime of a single symbol table
-     * instance.
-     * This is done for security reasons, to avoid potential DoS attack via
-     * hash collisions.
-     * 
-     * @since 2.1
-     */
-    final private int _seed;
-    
-    /*
-    /**********************************************************
-    /* Configuration
-    /**********************************************************
-     */
-
-    /**
-     * Whether canonical symbol Strings are to be intern()ed before added
-     * to the table or not.
-     *<p>
-     * NOTE: non-final to allow disabling intern()ing in case of excessive
-     * collisions.
-     */
-    protected boolean _intern;
-
-    /**
-     * Flag that indicates whether we should throw an exception if enough 
-     * hash collisions are detected (true); or just worked around (false).
-     * 
-     * @since 2.4
-     */
-    protected final boolean _failOnDoS;
-    
-    /*
-    /**********************************************************
-    /* Main table state
-    /**********************************************************
-     */
-    
-    // // // First, global information
-
-    /**
-     * Total number of Names in the symbol table;
-     * only used for child tables.
-     */
-    protected int _count;
-
-    /**
-     * We need to keep track of the longest collision list; this is needed
-     * both to indicate problems with attacks and to allow flushing for
-     * other cases.
-     * 
-     * @since 2.1
-     */
-    protected int _longestCollisionList;
-    
-    // // // Then information regarding primary hash array and its
-    // // // matching Name array
-
-    /**
-     * Mask used to truncate 32-bit hash value to current hash array
-     * size; essentially, hash array size - 1 (since hash array sizes
-     * are 2^N).
-     */
-    protected int _hashMask;
-
-    /**
-     * Array of 2^N size, which contains combination
-     * of 24-bits of hash (0 to indicate 'empty' slot),
-     * and 8-bit collision bucket index (0 to indicate empty
-     * collision bucket chain; otherwise subtract one from index)
-     */
-    protected int[] _hash;
-
-    /**
-     * Array that contains <code>Name</code> instances matching
-     * entries in <code>_mainHash</code>. Contains nulls for unused
-     * entries.
-     */
-    protected Name[] _mainNames;
-
-    // // // Then the collision/spill-over area info
-
-    /**
-     * Array of heads of collision bucket chains; size dynamically
-     */
-    protected Bucket[] _collList;
-
-    /**
-     * Total number of Names in collision buckets (included in
-     * <code>_count</code> along with primary entries)
-     */
-    protected int _collCount;
-
-    /**
-     * Index of the first unused collision bucket entry (== size of
-     * the used portion of collision list): less than
-     * or equal to 0xFF (255), since max number of entries is 255
-     * (8-bit, minus 0 used as 'empty' marker)
-     */
-    protected int _collEnd;
-
-    // // // Info regarding pending rehashing...
-
-    /**
-     * This flag is set if, after adding a new entry, it is deemed
-     * that a rehash is warranted if any more entries are to be added.
-     */
-    private transient boolean _needRehash;
-
-    /*
-    /**********************************************************
-    /* Sharing, versioning
-    /**********************************************************
-     */
-
-    // // // Which of the buffers may be shared (and are copy-on-write)?
-
-    /**
-     * Flag that indicates whether underlying data structures for
-     * the main hash area are shared or not. If they are, then they
-     * need to be handled in copy-on-write way, i.e. if they need
-     * to be modified, a copy needs to be made first; at this point
-     * it will not be shared any more, and can be modified.
-     *<p>
-     * This flag needs to be checked both when adding new main entries,
-     * and when adding new collision list queues (i.e. creating a new
-     * collision list head entry)
-     */
-    private boolean _hashShared;
-
-    private boolean _namesShared;
-
-    /**
-     * Flag that indicates whether underlying data structures for
-     * the collision list are shared or not. If they are, then they
-     * need to be handled in copy-on-write way, i.e. if they need
-     * to be modified, a copy needs to be made first; at this point
-     * it will not be shared any more, and can be modified.
-     *<p>
-     * This flag needs to be checked when adding new collision entries.
-     */
-    private boolean _collListShared;
-
-    /*
-    /**********************************************************
-    /* Bit of DoS detection goodness
-    /**********************************************************
-     */
-
-    /**
-     * Lazily constructed structure that is used to keep track of
-     * collision buckets that have overflowed once: this is used
-     * to detect likely attempts at denial-of-service attacks that
-     * uses hash collisions.
-     * 
-     * @since 2.4
-     */
-    protected BitSet _overflows;
-    
-    /*
-    /**********************************************************
-    /* Life-cycle: constructors
-    /**********************************************************
-     */
-
-    /**
-     * Constructor used for creating per-<code>JsonFactory</code> "root"
-     * symbol tables: ones used for merging and sharing common symbols
-     * 
-     * @param sz Initial hash area size
-     * @param intern Whether Strings contained should be {@link String#intern}ed
-     * @param seed Random seed valued used to make it more difficult to cause
-     *   collisions (used for collision-based DoS attacks).
-     */
-    private BytesToNameCanonicalizer(int sz, boolean intern, int seed, boolean failOnDoS) {
-        _parent = null;
-        _seed = seed;
-        _intern = intern;
-        _failOnDoS = failOnDoS;
-        // Sanity check: let's now allow hash sizes below certain minimum value
-        if (sz < MIN_HASH_SIZE) {
-            sz = MIN_HASH_SIZE;
-        } else {
-            /* Also; size must be 2^N; otherwise hash algorithm won't
-             * work... so let's just pad it up, if so
-             */
-            if ((sz & (sz - 1)) != 0) { // only true if it's 2^N
-                int curr = MIN_HASH_SIZE;
-                while (curr < sz) {
-                    curr += curr;
-                }
-                sz = curr;
-            }
-        }
-        _tableInfo = new AtomicReference<TableInfo>(initTableInfo(sz));
-    }
-
-    /**
-     * Constructor used when creating a child instance
-     */
-    private BytesToNameCanonicalizer(BytesToNameCanonicalizer parent, boolean intern,
-            int seed, boolean failOnDoS, TableInfo state)
-    {
-        _parent = parent;
-        _seed = seed;
-        _intern = intern;
-        _failOnDoS = failOnDoS;
-        _tableInfo = null; // not used by child tables
-
-        // Then copy shared state
-        _count = state.count;
-        _hashMask = state.mainHashMask;
-        _hash = state.mainHash;
-        _mainNames = state.mainNames;
-        _collList = state.collList;
-        _collCount = state.collCount;
-        _collEnd = state.collEnd;
-        _longestCollisionList = state.longestCollisionList;
-
-        // and then set other state to reflect sharing status
-        _needRehash = false;
-        _hashShared = true;
-        _namesShared = true;
-        _collListShared = true;
-    }
-
-    /*
-        public TableInfo(int count, int mainHashMask, int[] mainHash, Name[] mainNames,
-                Bucket[] collList, int collCount, int collEnd, int longestCollisionList)
-     */
-    private TableInfo initTableInfo(int sz) {
-        return new TableInfo(0, // count
-                sz - 1, // mainHashMask
-                new int[sz], // mainHash
-                new Name[sz], // mainNames
-                null, // collList
-                0, // collCount,
-                0, // collEnd
-                0 // longestCollisionList
-        );
-    }
-
-    /*
-    /**********************************************************
-    /* Life-cycle: factory methods, merging
-    /**********************************************************
-     */
-
-    /**
-     * Factory method to call to create a symbol table instance with a
-     * randomized seed value.
-     */
-    public static BytesToNameCanonicalizer createRoot() {
-        /* [Issue-21]: Need to use a variable seed, to thwart hash-collision
-         * based attacks.
-         */
-        long now = System.currentTimeMillis();
-        // ensure it's not 0; and might as well require to be odd so:
-        int seed = (((int) now) + ((int) (now >>> 32))) | 1;
-        return createRoot(seed);
-    }
-
-    /**
-     * Factory method that should only be called from unit tests, where seed
-     * value should remain the same.
-     */
-    protected static BytesToNameCanonicalizer createRoot(int seed) {
-        return new BytesToNameCanonicalizer(DEFAULT_T_SIZE, true, seed, true);
-    }
-
-    /**
-     * Factory method used to create actual symbol table instance to
-     * use for parsing.
-     */
-    public BytesToNameCanonicalizer makeChild(int flags) {
-        return new BytesToNameCanonicalizer(this,
-                JsonFactory.Feature.INTERN_FIELD_NAMES.enabledIn(flags),
-                _seed,
-                JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW.enabledIn(flags),
-                _tableInfo.get());
-    }
-
-    @Deprecated // since 2.4
-    public BytesToNameCanonicalizer makeChild(boolean canonicalize, boolean intern) {
-        return new BytesToNameCanonicalizer(this, intern, _seed,
-        		true, // JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW
-                _tableInfo.get());
-    }
-    
-    /**
-     * Method called by the using code to indicate it is done
-     * with this instance. This lets instance merge accumulated
-     * changes into parent (if need be), safely and efficiently,
-     * and without calling code having to know about parent
-     * information
-     */
-    public void release()
-    {
-        // we will try to merge if child table has new entries
-        if (_parent != null && maybeDirty()) {
-            _parent.mergeChild(new TableInfo(this));
-            /* Let's also mark this instance as dirty, so that just in
-             * case release was too early, there's no corruption of possibly shared data.
-             */
-            _hashShared = true;
-            _namesShared = true;
-            _collListShared = true;
-        }
-    }
-
-    private void mergeChild(TableInfo childState)
-    {
-        final int childCount = childState.count;
-        TableInfo currState = _tableInfo.get();
-
-        /* Should usually grow; but occasionally could also shrink if
-         * (but only if) collision list overflow ends up clearing
-         * some collision lists.
-         */
-        if (childCount == currState.count) {
-            return;
-        }
-
-        /* One caveat: let's try to avoid problems with
-         * degenerate cases of documents with generated "random"
-         * names: for these, symbol tables would bloat indefinitely.
-         * One way to do this is to just purge tables if they grow
-         * too large, and that's what we'll do here.
-         */
-        if (childCount > MAX_ENTRIES_FOR_REUSE) {
-            /* Should there be a way to get notified about this
-             * event, to log it or such? (as it's somewhat abnormal
-             * thing to happen)
-             */
-            // At any rate, need to clean up the tables
-            childState = initTableInfo(DEFAULT_T_SIZE);
-        }
-        _tableInfo.compareAndSet(currState, childState);
-    }
-
-    /*
-    /**********************************************************
-    /* API, accessors
-    /**********************************************************
-     */
-
-    public int size()
-    {
-        if (_tableInfo != null) { // root table
-            return _tableInfo.get().count;
-        }
-        // nope, child table
-        return _count;
-    }
-
-    /**
-     * @since 2.1
-     */
-    public int bucketCount() { return _hash.length; }
-    
-    /**
-     * Method called to check to quickly see if a child symbol table
-     * may have gotten additional entries. Used for checking to see
-     * if a child table should be merged into shared table.
-     */
-    public boolean maybeDirty() { return !_hashShared; }
-
-    /**
-     * @since 2.1
-     */
-    public int hashSeed() { return _seed; }
-    
-    /**
-     * Method mostly needed by unit tests; calculates number of
-     * entries that are in collision list. Value can be at most
-     * ({@link #size} - 1), but should usually be much lower, ideally 0.
-     * 
-     * @since 2.1
-     */
-    public int collisionCount() { return _collCount; }
-
-    /**
-     * Method mostly needed by unit tests; calculates length of the
-     * longest collision chain. This should typically be a low number,
-     * but may be up to {@link #size} - 1 in the pathological case
-     * 
-     * @since 2.1
-     */
-    public int maxCollisionLength() {
-        return _longestCollisionList;
-    }
-
-    /*
-    /**********************************************************
-    /* Public API, accessing symbols:
-    /**********************************************************
-     */
-    
-    public static Name getEmptyName() {
-        return Name1.getEmptyName();
-    }
-
-    /**
-     * Finds and returns name matching the specified symbol, if such
-     * name already exists in the table.
-     * If not, will return null.
-     *<p>
-     * Note: separate methods to optimize common case of
-     * short element/attribute names (4 or less ascii characters)
-     *
-     * @param q1 int32 containing first 4 bytes of the name;
-     *   if the whole name less than 4 bytes, padded with zero bytes
-     *   in front (zero MSBs, ie. right aligned)
-     *
-     * @return Name matching the symbol passed (or constructed for
-     *   it)
-     */
-    public Name findName(int q1)
-    {
-        int hash = calcHash(q1);
-        int ix = (hash & _hashMask);
-        int val = _hash[ix];
-        
-        /* High 24 bits of the value are low 24 bits of hash (low 8 bits
-         * are bucket index)... match?
-         */
-        if ((((val >> 8) ^ hash) << 8) == 0) { // match
-            // Ok, but do we have an actual match?
-            Name name = _mainNames[ix];
-            if (name == null) { // main slot empty; can't find
-                return null;
-            }
-            if (name.equals(q1)) {
-                return name;
-            }
-        } else if (val == 0) { // empty slot? no match
-            return null;
-        }
-        // Maybe a spill-over?
-        val &= 0xFF;
-        if (val > 0) { // 0 means 'empty'
-            val -= 1; // to convert from 1-based to 0...
-            Bucket bucket = _collList[val];
-            if (bucket != null) {
-                return bucket.find(hash, q1, 0);
-            }
-        }
-        // Nope, no match whatsoever
-        return null;
-    }
-
-    /**
-     * Finds and returns name matching the specified symbol, if such
-     * name already exists in the table.
-     * If not, will return null.
-     *<p>
-     * Note: separate methods to optimize common case of relatively
-     * short element/attribute names (8 or less ascii characters)
-     *
-     * @param q1 int32 containing first 4 bytes of the name.
-     * @param q2 int32 containing bytes 5 through 8 of the
-     *   name; if less than 8 bytes, padded with up to 3 zero bytes
-     *   in front (zero MSBs, ie. right aligned)
-     *
-     * @return Name matching the symbol passed (or constructed for it)
-     */
-    public Name findName(int q1, int q2)
-    {
-        int hash = (q2 == 0) ? calcHash(q1) : calcHash(q1, q2);
-        int ix = (hash & _hashMask);
-        int val = _hash[ix];
-        
-        /* High 24 bits of the value are low 24 bits of hash (low 8 bits
-         * are bucket index)... match?
-         */
-        if ((((val >> 8) ^ hash) << 8) == 0) { // match
-            // Ok, but do we have an actual match?
-            Name name = _mainNames[ix];
-            if (name == null) { // main slot empty; can't find
-                return null;
-            }
-            if (name.equals(q1, q2)) {
-                return name;
-            }
-        } else if (val == 0) { // empty slot? no match
-            return null;
-        }
-        // Maybe a spill-over?
-        val &= 0xFF;
-        if (val > 0) { // 0 means 'empty'
-            val -= 1; // to convert from 1-based to 0...
-            Bucket bucket = _collList[val];
-            if (bucket != null) {
-                return bucket.find(hash, q1, q2);
-            }
-        }
-        // Nope, no match whatsoever
-        return null;
-    }
-
-    public Name findName(int q1, int q2, int q3)
-    {
-        int hash = calcHash(q1, q2, q3);
-        int ix = (hash & _hashMask);
-        int val = _hash[ix];
-        
-        if ((((val >> 8) ^ hash) << 8) == 0) { // match
-            // Ok, but do we have an actual match?
-            Name name = _mainNames[ix];
-            if (name == null) { // main slot empty; can't find
-                return null;
-            }
-            if (name.equals(q1, q2, q3)) {
-                return name;
-            }
-        } else if (val == 0) { // empty slot? no match
-            return null;
-        }
-        // Maybe a spill-over?
-        val &= 0xFF;
-        if (val > 0) { // 0 means 'empty'
-            val -= 1; // to convert from 1-based to 0...
-            Bucket bucket = _collList[val];
-            if (bucket != null) {
-                return bucket.find(hash, q1, q2, q3);
-            }
-        }
-        // Nope, no match whatsoever
-        return null;
-    }
-    
-    /**
-     * Finds and returns name matching the specified symbol, if such
-     * name already exists in the table; or if not, creates name object,
-     * adds to the table, and returns it.
-     *<p>
-     * Note: this is the general purpose method that can be called for
-     * names of any length. However, if name is less than 9 bytes long,
-     * it is preferable to call the version optimized for short
-     * names.
-     *
-     * @param q Array of int32s, each of which contain 4 bytes of
-     *   encoded name
-     * @param qlen Number of int32s, starting from index 0, in quads
-     *   parameter
-     *
-     * @return Name matching the symbol passed (or constructed for it)
-     */
-    public Name findName(int[] q, int qlen)
-    {
-        if (qlen < 4) { // another sanity check
-            if (qlen == 3) {
-                return findName(q[0], q[1], q[2]);
-            }
-            return findName(q[0], (qlen < 2) ? 0 : q[1]);
-        }
-        int hash = calcHash(q, qlen);
-        // (for rest of comments regarding logic, see method above)
-        int ix = (hash & _hashMask);
-        int val = _hash[ix];
-        if ((((val >> 8) ^ hash) << 8) == 0) {
-            Name name = _mainNames[ix];
-            if (name == null // main slot empty; no collision list then either
-                || name.equals(q, qlen)) { // should be match, let's verify
-                return name;
-            }
-        } else if (val == 0) { // empty slot? no match
-            return null;
-        }
-        val &= 0xFF;
-        if (val > 0) { // 0 means 'empty'
-            val -= 1; // to convert from 1-based to 0...
-            Bucket bucket = _collList[val];
-            if (bucket != null) {
-                return bucket.find(hash, q, qlen);
-            }
-        }
-        return null;
-    }
-
-    /*
-    /**********************************************************
-    /* API, mutators
-    /**********************************************************
-     */
-
-    public Name addName(String name, int q1, int q2)
-    {
-        if (_intern) {
-            name = InternCache.instance.intern(name);
-        }
-        int hash = (q2 == 0) ? calcHash(q1) : calcHash(q1, q2);
-        Name symbol = constructName(hash, name, q1, q2);
-        _addSymbol(hash, symbol);
-        return symbol;
-    }
-    
-    public Name addName(String name, int[] q, int qlen)
-    {
-        if (_intern) {
-            name = InternCache.instance.intern(name);
-        }
-        int hash;
-        if (qlen < 4) {
-            if (qlen == 1) {
-                hash = calcHash(q[0]);
-            } else if (qlen == 2) {
-                hash = calcHash(q[0], q[1]);
-            } else {
-                hash = calcHash(q[0], q[1], q[2]);
-            }
-        } else {
-            hash = calcHash(q, qlen);
-        }
-        Name symbol = constructName(hash, name, q, qlen);
-        _addSymbol(hash, symbol);
-        return symbol;
-    }
-    
-    /*
-    /**********************************************************
-    /* Helper methods
-    /**********************************************************
-     */
-
-    /* Note on hash calculation: we try to make it more difficult to
-     * generate collisions automatically; part of this is to avoid
-     * simple "multiply-add" algorithm (like JDK String.hashCode()),
-     * and add bit of shifting. And other part is to make this
-     * non-linear, at least for shorter symbols.
-     */
-    
-    // JDK uses 31; other fine choices are 33 and 65599, let's use 33
-    // as it seems to give fewest collisions for us
-    // (see [http://www.cse.yorku.ca/~oz/hash.html] for details)
-    private final static int MULT = 33;
-    private final static int MULT2 = 65599;
-    private final static int MULT3 = 31;
-    
-    public int calcHash(int q1)
-    {
-        int hash = q1 ^ _seed;
-        hash += (hash >>> 15); // to xor hi- and low- 16-bits
-        hash ^= (hash >>> 9); // as well as lowest 2 bytes
-        return hash;
-    }
-
-    public int calcHash(int q1, int q2)
-    {
-        // For two quads, let's change algorithm a bit, to spice
-        // things up (can do bit more processing anyway)
-        int hash = q1;
-        hash ^= (hash >>> 15); // try mixing first and second byte pairs first
-        hash += (q2 * MULT); // then add second quad
-        hash ^= _seed;
-        hash += (hash >>> 7); // and shuffle some more
-        // 26-Mar-2015, tatu: As per [core#187] need bit more shuffling. This may
-        //   seem like a magical number (and in a way, it is), but it was the sweet
-        //   spot for some reason (5 and 3 work ok but converges for 4, for tested case)
-        hash ^= (hash >>> 4);
-        return hash;
-    }
-
-    public int calcHash(int q1, int q2, int q3)
-    {
-        // use same algorithm as multi-byte, tested to work well
-        int hash = q1 ^ _seed;
-        hash += (hash >>> 9);
-        hash *= MULT;
-        hash += q2;
-        hash *= MULT2;
-        hash += (hash >>> 15);
-        hash ^= q3;
-        hash += (hash >>> 17);
-
-        // and finally shuffle some more once done
-        hash += (hash >>> 15); // to get high-order bits to mix more
-        hash ^= (hash << 9); // as well as lowest 2 bytes
-
-        return hash;
-    }
-    
-    public int calcHash(int[] q, int qlen)
-    {
-        if (qlen < 4) {
-            throw new IllegalArgumentException();
-        }
-
-        /* And then change handling again for "multi-quad" case; mostly
-         * to make calculation of collisions less fun. For example,
-         * add seed bit later in the game, and switch plus/xor around,
-         * use different shift lengths.
-         */
-        int hash = q[0] ^ _seed;
-        hash += (hash >>> 9);
-        hash *= MULT;
-        hash += q[1];
-        hash *= MULT2;
-        hash += (hash >>> 15);
-        hash ^= q[2];
-        hash += (hash >>> 17);
-        
-        for (int i = 3; i < qlen; ++i) {
-            hash = (hash * MULT3) ^ q[i];
-            // for longer entries, mess a bit in-between too
-            hash += (hash >>> 3);
-            hash ^= (hash << 7);
-        }
-        // and finally shuffle some more once done
-        hash += (hash >>> 15); // to get high-order bits to mix more
-        hash ^= (hash << 9); // as well as lowest 2 bytes
-        return hash;
-    }
-
-    // Method only used by unit tests
-    protected static int[] calcQuads(byte[] wordBytes) {
-        int blen = wordBytes.length;
-        int[] result = new int[(blen + 3) / 4];
-        for (int i = 0; i < blen; ++i) {
-            int x = wordBytes[i] & 0xFF;
-
-            if (++i < blen) {
-                x = (x << 8) | (wordBytes[i] & 0xFF);
-                if (++i < blen) {
-                    x = (x << 8) | (wordBytes[i] & 0xFF);
-                    if (++i < blen) {
-                        x = (x << 8) | (wordBytes[i] & 0xFF);
-                    }
-                }
-            }
-            result[i >> 2] = x;
-        }
-        return result;
-    }
-
-    /*
-    /**********************************************************
-    /* Standard methods
-    /**********************************************************
-     */
-
-    /*
-    @Override
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[BytesToNameCanonicalizer, size: ");
-        sb.append(_count);
-        sb.append('/');
-        sb.append(_mainHash.length);
-        sb.append(", ");
-        sb.append(_collCount);
-        sb.append(" coll; avg length: ");
-
-        // Average length: minimum of 1 for all (1 == primary hit);
-        // and then 1 per each traversal for collisions/buckets
-        //int maxDist = 1;
-        int pathCount = _count;
-        for (int i = 0; i < _collEnd; ++i) {
-            int spillLen = _collList[i].length();
-            for (int j = 1; j <= spillLen; ++j) {
-                pathCount += j;
-            }
-        }
-        double avgLength;
-
-        if (_count == 0) {
-            avgLength = 0.0;
-        } else {
-            avgLength = (double) pathCount / (double) _count;
-        }
-        // let's round up a bit (two 2 decimal places)
-        //avgLength -= (avgLength % 0.01);
-
-        sb.append(avgLength);
-        sb.append(']');
-        return sb.toString();
-    }
-    */
-
-    /*
-    /**********************************************************
-    /* Internal methods
-    /**********************************************************
-     */
-
-    private void _addSymbol(int hash, Name symbol)
-    {
-        if (_hashShared) { // always have to modify main entry
-            unshareMain();
-        }
-        // First, do we need to rehash?
-        if (_needRehash) {
-            rehash();
-        }
-
-        ++_count;
-
-        /* Ok, enough about set up: now we need to find the slot to add
-         * symbol in:
-         */
-        int ix = (hash & _hashMask);
-        if (_mainNames[ix] == null) { // primary empty?
-            _hash[ix] = (hash << 8);
-            if (_namesShared) {
-                unshareNames();
-            }
-            _mainNames[ix] = symbol;
-        } else { // nope, it's a collision, need to spill over
-            /* How about spill-over area... do we already know the bucket
-             * (is the case if it's not the first collision)
-             */
-            if (_collListShared) {
-                unshareCollision(); // also allocates if list was null
-            }
-            ++_collCount;
-            int entryValue = _hash[ix];
-            int bucket = entryValue & 0xFF;
-            if (bucket == 0) { // first spill over?
-                if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket
-                    bucket = _collEnd;
-                    ++_collEnd;
-                    // need to expand?
-                    if (bucket >= _collList.length) {
-                        expandCollision();
-                    }
-                } else { // nope, have to share... let's find shortest?
-                    bucket = findBestBucket();
-                }
-                // Need to mark the entry... and the spill index is 1-based
-                _hash[ix] = (entryValue & ~0xFF) | (bucket + 1);
-            } else {
-                --bucket; // 1-based index in value
-            }
-            
-            // And then just need to link the new bucket entry in
-            Bucket newB = new Bucket(symbol, _collList[bucket]);
-            int collLen = newB.length;
-            if (collLen > MAX_COLL_CHAIN_LENGTH) {
-                /* 23-May-2014, tatu: Instead of throwing an exception right away, let's handle
-                 *   in bit smarter way.
-                 */
-                _handleSpillOverflow(bucket, newB);
-            } else {
-                _collList[bucket] = newB;
-                // but, be careful wrt attacks
-                _longestCollisionList = Math.max(newB.length, _longestCollisionList);
-            }
-        }
-
-        /* Ok. Now, do we need a rehash next time? Need to have at least
-         * 50% fill rate no matter what:
-         */
-        {
-            int hashSize = _hash.length;
-            if (_count > (hashSize >> 1)) {
-                int hashQuarter = (hashSize >> 2);
-                /* And either strictly above 75% (the usual) or
-                 * just 50%, and collision count >= 25% of total hash size
-                 */
-                if (_count > (hashSize - hashQuarter)) {
-                    _needRehash = true;
-                } else if (_collCount >= hashQuarter) {
-                    _needRehash = true;
-                }
-            }
-        }
-    }
-
-    private void _handleSpillOverflow(int bindex, Bucket newBucket)
-    {
-        if (_overflows == null) {
-            _overflows = new BitSet();
-            _overflows.set(bindex);
-        } else {
-            if (_overflows.get(bindex)) {
-                // Has happened once already, so not a coincident...
-                if (_failOnDoS) {
-                    reportTooManyCollisions(MAX_COLL_CHAIN_LENGTH);
-                }
-                // but even if we don't fail, we will stop intern()ing
-                _intern = false;
-            } else {
-                _overflows.set(bindex);
-            }
-        }
-        // regardless, if we get this far, clear up the bucket, adjust size appropriately.
-        _collList[bindex] = null;
-        _count -= (newBucket.length);
-        // we could calculate longest; but for now just mark as invalid
-        _longestCollisionList = -1;
-    }
-    
-    private void rehash()
-    {
-        _needRehash = false;        
-        // Note: since we'll make copies, no need to unshare, can just mark as such:
-        _namesShared = false;
-
-        /* And then we can first deal with the main hash area. Since we
-         * are expanding linearly (double up), we know there'll be no
-         * collisions during this phase.
-         */
-        int[] oldMainHash = _hash;
-        int len = oldMainHash.length;
-        int newLen = len+len;
-
-        /* 13-Mar-2010, tatu: Let's guard against OOME that could be caused by
-         *    large documents with unique (or mostly so) names
-         */
-        if (newLen > MAX_T_SIZE) {
-            nukeSymbols();
-            return;
-        }
-        
-        _hash = new int[newLen];
-        _hashMask = (newLen - 1);
-        Name[] oldNames = _mainNames;
-        _mainNames = new Name[newLen];
-        int symbolsSeen = 0; // let's do a sanity check
-        for (int i = 0; i < len; ++i) {
-            Name symbol = oldNames[i];
-            if (symbol != null) {
-                ++symbolsSeen;
-                int hash = symbol.hashCode();
-                int ix = (hash & _hashMask);
-                _mainNames[ix] = symbol;
-                _hash[ix] = hash << 8; // will clear spill index
-            }
-        }
-
-        /* And then the spill area. This may cause collisions, although
-         * not necessarily as many as there were earlier. Let's allocate
-         * same amount of space, however
-         */
-        int oldEnd = _collEnd;
-        if (oldEnd == 0) { // no prior collisions...
-            _longestCollisionList = 0;
-            return;
-        }
-
-        _collCount = 0;
-        _collEnd = 0;
-        _collListShared = false;
-
-        int maxColl = 0;
-        
-        Bucket[] oldBuckets = _collList;
-        _collList = new Bucket[oldBuckets.length];
-        for (int i = 0; i < oldEnd; ++i) {
-            for (Bucket curr = oldBuckets[i]; curr != null; curr = curr.next) {
-                ++symbolsSeen;
-                Name symbol = curr.name;
-                int hash = symbol.hashCode();
-                int ix = (hash & _hashMask);
-                int val = _hash[ix];
-                if (_mainNames[ix] == null) { // no primary entry?
-                    _hash[ix] = (hash << 8);
-                    _mainNames[ix] = symbol;
-                } else { // nope, it's a collision, need to spill over
-                    ++_collCount;
-                    int bucket = val & 0xFF;
-                    if (bucket == 0) { // first spill over?
-                        if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket
-                            bucket = _collEnd;
-                            ++_collEnd;
-                            // need to expand?
-                            if (bucket >= _collList.length) {
-                                expandCollision();
-                            }
-                        } else { // nope, have to share... let's find shortest?
-                            bucket = findBestBucket();
-                        }
-                        // Need to mark the entry... and the spill index is 1-based
-                        _hash[ix] = (val & ~0xFF) | (bucket + 1);
-                    } else {
-                        --bucket; // 1-based index in value
-                    }
-                    // And then just need to link the new bucket entry in
-                    Bucket newB = new Bucket(symbol, _collList[bucket]);
-                    _collList[bucket] = newB;
-                    maxColl = Math.max(maxColl, newB.length);
-                }
-            } // for (... buckets in the chain ...)
-        } // for (... list of bucket heads ... )
-
-        _longestCollisionList = maxColl;
-        
-        if (symbolsSeen != _count) { // sanity check
-            throw new RuntimeException("Internal error: count after rehash "+symbolsSeen+"; should be "+_count);
-        }
-    }
-
-    /**
-     * Helper method called to empty all shared symbols, but to leave
-     * arrays allocated
-     */
-    private void nukeSymbols() {
-        _count = 0;
-        _longestCollisionList = 0;
-        Arrays.fill(_hash, 0);
-        Arrays.fill(_mainNames, null);
-        Arrays.fill(_collList, null);
-        _collCount = 0;
-        _collEnd = 0;
-    }
-    
-    /**
-     * Method called to find the best bucket to spill a Name over to:
-     * usually the first bucket that has only one entry, but in general
-     * first one of the buckets with least number of entries
-     */
-    private int findBestBucket() {
-        Bucket[] buckets = _collList;
-        int bestCount = Integer.MAX_VALUE;
-        int bestIx = -1;
-
-        for (int i = 0, len = _collEnd; i < len; ++i) {
-            Bucket b = buckets[i];
-            // [#145] may become null due to long overflow chain
-            if (b == null) {
-                return i;
-            }
-            int count = b.length;
-            if (count < bestCount) {
-                if (count == 1) { // best possible
-                    return i;
-                }
-                bestCount = count;
-                bestIx = i;
-            }
-        }
-        return bestIx;
-    }
-
-    /**
-     * Method that needs to be called, if the main hash structure
-     * is (may be) shared. This happens every time something is added,
-     * even if addition is to the collision list (since collision list
-     * index comes from lowest 8 bits of the primary hash entry)
-     */
-    private void unshareMain() {
-        final int[] old = _hash;
-        _hash = Arrays.copyOf(old, old.length);
-        _hashShared = false;
-    }
-
-    private void unshareCollision() {
-        Bucket[] old = _collList;
-        if (old == null) {
-            _collList = new Bucket[INITIAL_COLLISION_LEN];
-        } else {
-            _collList = Arrays.copyOf(old, old.length);
-        }
-        _collListShared = false;
-    }
-
-    private void unshareNames() {
-        final Name[] old = _mainNames;
-        _mainNames = Arrays.copyOf(old, old.length);
-        _namesShared = false;
-    }
-
-    private void expandCollision() {
-        final Bucket[] old = _collList;
-        _collList = Arrays.copyOf(old, old.length * 2);
-    }
-
-    /*
-    /**********************************************************
-    /* Constructing name objects
-    /**********************************************************
-     */
-
-    private static Name constructName(int hash, String name, int q1, int q2) {
-        if (q2 == 0) { // one quad only?
-            return new Name1(name, hash, q1);
-        }
-        return new Name2(name, hash, q1, q2);
-    }
-
-    private static Name constructName(int hash, String name, int[] quads, int qlen) {
-        if (qlen < 4) { // Need to check for 3 quad one, can do others too
-            switch (qlen) {
-            case 1:
-                return new Name1(name, hash, quads[0]);
-            case 2:
-                return new Name2(name, hash, quads[0], quads[1]);
-            case 3:
-            default:
-                return new Name3(name, hash, quads[0], quads[1], quads[2]);
-            }
-        }
-        return NameN.construct(name, hash, quads, qlen);
-    }
-
-    /*
-    /**********************************************************
-    /* Other helper methods
-    /**********************************************************
-     */
-
-    /**
-     * @since 2.1
-     */
-    protected void reportTooManyCollisions(int maxLen)
-    {
-        throw new IllegalStateException("Longest collision chain in symbol table (of size "+_count
-                +") now exceeds maximum, "+maxLen+" -- suspect a DoS attack based on hash collisions");
-    }
-
-    /*
-    /**********************************************************
-    /* Helper classes
-    /**********************************************************
-     */
-
-    /**
-     * Immutable value class used for sharing information as efficiently
-     * as possible, by only require synchronization of reference manipulation
-     * but not access to contents.
-     * 
-     * @since 2.1
-     */
-    private final static class TableInfo
-    {
-        public final int count;
-        public final int mainHashMask;
-        public final int[] mainHash;
-        public final Name[] mainNames;
-        public final Bucket[] collList;
-        public final int collCount;
-        public final int collEnd;
-        public final int longestCollisionList;
-
-        public TableInfo(int count, int mainHashMask, int[] mainHash, Name[] mainNames,
-                Bucket[] collList, int collCount, int collEnd, int longestCollisionList)
-        {
-            this.count = count;
-            this.mainHashMask = mainHashMask;
-            this.mainHash = mainHash;
-            this.mainNames = mainNames;
-            this.collList = collList;
-            this.collCount = collCount;
-            this.collEnd = collEnd;
-            this.longestCollisionList = longestCollisionList;
-        }
-
-        public TableInfo(BytesToNameCanonicalizer src)
-        {
-            count = src._count;
-            mainHashMask = src._hashMask;
-            mainHash = src._hash;
-            mainNames = src._mainNames;
-            collList = src._collList;
-            collCount = src._collCount;
-            collEnd = src._collEnd;
-            longestCollisionList = src._longestCollisionList;
-        }
-    }
-    
-    final private static class Bucket
-    {
-        public final Name name;
-        public final Bucket next;
-        public final int hash;
-        public final int length;
-
-        Bucket(Name name, Bucket next) {
-            this.name = name;
-            this.next = next;
-            length = (next == null) ? 1 : next.length+1;
-            hash = name.hashCode();
-        }
-
-        public Name find(int h, int firstQuad, int secondQuad) {
-            if (hash == h) {
-                if (name.equals(firstQuad, secondQuad)) {
-                    return name;
-                }
-            }
-            for (Bucket curr = next; curr != null; curr = curr.next) {
-                if (curr.hash == h) {
-                    Name currName = curr.name;
-                    if (currName.equals(firstQuad, secondQuad)) {
-                        return currName;
-                    }
-                }
-            }
-            return null;
-        }
-
-        public Name find(int h, int q1, int q2, int q3) {
-            if (hash == h) {
-                if (name.equals(q1, q2, q3)) {
-                    return name;
-                }
-            }
-            for (Bucket curr = next; curr != null; curr = curr.next) {
-                if (curr.hash == h) {
-                    Name currName = curr.name;
-                    if (currName.equals(q1, q2, q3)) {
-                        return currName;
-                    }
-                }
-            }
-            return null;
-        }
-        
-        public Name find(int h, int[] quads, int qlen) {
-            if (hash == h) {
-                if (name.equals(quads, qlen)) {
-                    return name;
-                }
-            }
-            for (Bucket curr = next; curr != null; curr = curr.next) {
-                if (curr.hash == h) {
-                    Name currName = curr.name;
-                    if (currName.equals(quads, qlen)) {
-                        return currName;
-                    }
-                }
-            }
-            return null;
-        }
-    }
-}
diff --git a/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java b/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java
index 2c57157..a668c7e 100644
--- a/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java
+++ b/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java
@@ -88,7 +88,11 @@
      * subtypes they may be different parameters or possibly none at all).
      * 
      * @since 2.5
+     *
+     * @deprecated Since 2.7: does not have meaning as parameters depend on type
+     *    resolved.
      */
+    @Deprecated // since 2.7
     public Class<?> getParameterSource() {
         return null;
     }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java b/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
index 0a004c5..510d2fd 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
@@ -79,7 +79,7 @@
      * Number of open levels of nesting. Used to determine amount of
      * indentation to use.
      */
-    protected transient int _nesting = 0;
+    protected transient int _nesting;
 
     /*
     /**********************************************************
@@ -245,8 +245,7 @@
      */
 
     @Override
-    public void writeRootValueSeparator(JsonGenerator jg)
-        throws IOException, JsonGenerationException
+    public void writeRootValueSeparator(JsonGenerator jg) throws IOException
     {
         if (_rootSeparator != null) {
             jg.writeRaw(_rootSeparator);
@@ -254,8 +253,7 @@
     }
 
     @Override
-    public void writeStartObject(JsonGenerator jg)
-        throws IOException, JsonGenerationException
+    public void writeStartObject(JsonGenerator jg) throws IOException
     {
         jg.writeRaw('{');
         if (!_objectIndenter.isInline()) {
@@ -264,8 +262,7 @@
     }
 
     @Override
-    public void beforeObjectEntries(JsonGenerator jg)
-        throws IOException, JsonGenerationException
+    public void beforeObjectEntries(JsonGenerator jg) throws IOException
     {
         _objectIndenter.writeIndentation(jg, _nesting);
     }
@@ -280,8 +277,7 @@
      * (white-space) decoration.
      */
     @Override
-    public void writeObjectFieldValueSeparator(JsonGenerator jg)
-        throws IOException, JsonGenerationException
+    public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException
     {
         if (_spacesInObjectEntries) {
             jg.writeRaw(" : ");
@@ -300,16 +296,14 @@
      * (white-space) decoration.
      */
     @Override
-    public void writeObjectEntrySeparator(JsonGenerator jg)
-        throws IOException, JsonGenerationException
+    public void writeObjectEntrySeparator(JsonGenerator jg) throws IOException
     {
         jg.writeRaw(',');
         _objectIndenter.writeIndentation(jg, _nesting);
     }
 
     @Override
-    public void writeEndObject(JsonGenerator jg, int nrOfEntries)
-        throws IOException, JsonGenerationException
+    public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException
     {
         if (!_objectIndenter.isInline()) {
             --_nesting;
@@ -323,8 +317,7 @@
     }
 
     @Override
-    public void writeStartArray(JsonGenerator jg)
-        throws IOException, JsonGenerationException
+    public void writeStartArray(JsonGenerator jg) throws IOException
     {
         if (!_arrayIndenter.isInline()) {
             ++_nesting;
@@ -333,9 +326,7 @@
     }
 
     @Override
-    public void beforeArrayValues(JsonGenerator jg)
-        throws IOException, JsonGenerationException
-    {
+    public void beforeArrayValues(JsonGenerator jg) throws IOException {
         _arrayIndenter.writeIndentation(jg, _nesting);
     }
 
@@ -409,43 +400,4 @@
         @Override
         public boolean isInline() { return true; }
     }
-    
-    /**
-     * @deprecated Since 2.5 use {@link DefaultIndenter} instead
-     */
-    @Deprecated
-    public static class Lf2SpacesIndenter extends DefaultIndenter
-    {
-        /** @deprecated Use {@link DefaultIndenter#SYSTEM_LINEFEED_INSTANCE} instead.
-         */
-        @SuppressWarnings("hiding")
-        @Deprecated
-        public static final Lf2SpacesIndenter instance = new Lf2SpacesIndenter();
-
-        /** @deprecated Use {@code new DefaultIndenter("  ", DefaultIndenter.SYS_LF)} instead
-         */
-        @Deprecated
-        public Lf2SpacesIndenter() {
-            super("  ", DefaultIndenter.SYS_LF);
-        }
-        
-        /** @deprecated Use {@code new DefaultIndenter("  ", lf)} instead
-         */
-        @Deprecated
-        public Lf2SpacesIndenter(String lf) {
-            super("  ", lf);
-        }
-
-        /**
-         * Note: method was accidentally missing from 2.5.0; put back for 2.5.1 and
-         * later 2.5.x versions.
-         */
-        @Override
-        public Lf2SpacesIndenter withLinefeed(String lf) {
-            if (lf.equals(getEol())) {
-                return this;
-            }
-            return new Lf2SpacesIndenter(lf);
-        }
-    }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
index 9d53afa..f8c31ca 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
@@ -128,11 +128,24 @@
     public int getFeatureMask() { return delegate.getFeatureMask(); }
 
     @Override
+    @Deprecated
     public JsonGenerator setFeatureMask(int mask) {
         delegate.setFeatureMask(mask);
         return this;
     }
 
+    @Override
+    public JsonGenerator overrideStdFeatures(int values, int mask) {
+        delegate.overrideStdFeatures(values, mask);
+        return this;
+    }
+
+    @Override
+    public JsonGenerator overrideFormatFeatures(int values, int mask) {
+        delegate.overrideFormatFeatures(values, mask);
+        return this;
+    }
+
     /*
     /**********************************************************
     /* Configuring generator
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
index 7f4241d..c96d239 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
@@ -60,11 +60,24 @@
     @Override public int getFeatureMask() { return delegate.getFeatureMask(); }
 
     @Override
+    @Deprecated // since 2.7
     public JsonParser setFeatureMask(int mask) {
         delegate.setFeatureMask(mask);
         return this;
     }
 
+    @Override
+    public JsonParser overrideStdFeatures(int values, int mask) {
+        delegate.overrideStdFeatures(values, mask);
+        return this;
+    }
+
+    @Override
+    public JsonParser overrideFormatFeatures(int values, int mask) {
+        delegate.overrideFormatFeatures(values, mask);
+        return this;
+    }
+
     @Override public FormatSchema getSchema() { return delegate.getSchema(); }
     @Override public void setSchema(FormatSchema schema) { delegate.setSchema(schema); }
     @Override public boolean canUseSchema(FormatSchema schema) {  return delegate.canUseSchema(schema); }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
index 68ba240..85250b1 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
@@ -82,7 +82,7 @@
     /**
      * Flag that indicates whether _seqments is non-empty
      */
-    private boolean _hasSegments = false;
+    private boolean _hasSegments;
 
     // // // Currently used segment; not (yet) contained in _seqments
 
diff --git a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
index 5d14f71..d5a2ae0 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
+++ b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
@@ -1,15 +1,45 @@
 package com.fasterxml.jackson.core;
 
+import java.io.StringWriter;
 
 public class TestExceptions extends BaseTest
 {
-    // For [Issue#10]
+    private final JsonFactory JSON_F = new JsonFactory();
+    
+    // For [core#10]
     public void testOriginalMesssage()
     {
-        JsonProcessingException exc = new JsonParseException("Foobar", JsonLocation.NA);
+        JsonProcessingException exc = new JsonParseException(null, "Foobar", JsonLocation.NA);
         String msg = exc.getMessage();
         String orig = exc.getOriginalMessage();
         assertEquals("Foobar", orig);
         assertTrue(msg.length() > orig.length());
     }
+
+    // [core#198]
+    public void testAccessToParser() throws Exception
+    {
+        JsonParser p = JSON_F.createParser("{}");
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        JsonParseException e = new JsonParseException(p, "Test!");
+        assertSame(p, e.getProcessor());
+        assertEquals("Test!", e.getOriginalMessage());
+        JsonLocation loc = e.getLocation();
+        assertNotNull(loc);
+        assertEquals(2, loc.getColumnNr());
+        assertEquals(1, loc.getLineNr());
+        p.close();
+    }
+
+    // [core#198]
+    public void testAccessToGenerator() throws Exception
+    {
+        StringWriter w = new StringWriter();
+        JsonGenerator g = JSON_F.createGenerator(w);
+        g.writeStartObject();
+        JsonGenerationException e = new JsonGenerationException("Test!", g);
+        assertSame(g, e.getProcessor());
+        assertEquals("Test!", e.getOriginalMessage());
+        g.close();
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/LocationInArrayTest.java b/src/test/java/com/fasterxml/jackson/core/json/LocationInArrayTest.java
new file mode 100644
index 0000000..6883523
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/LocationInArrayTest.java
@@ -0,0 +1,66 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+
+// Tests mostly for [core#229]
+public class LocationInArrayTest extends com.fasterxml.jackson.core.BaseTest
+{
+    final JsonFactory JSON_F = new JsonFactory();
+
+    // for [core#229]
+    public void testOffsetInArraysBytes() throws Exception {
+        _testOffsetInArrays(true);
+    }
+    
+    // for [core#229]
+    public void testOffsetInArraysChars() throws Exception {
+        _testOffsetInArrays(false);
+    }        
+
+    private void _testOffsetInArrays(boolean useBytes) throws Exception
+    {
+        JsonParser p;
+        final String DOC = "  [10, 251,\n   3  ]";
+
+        // first, char based:
+        p = useBytes ? JSON_F.createParser(DOC.getBytes("UTF-8"))
+                : JSON_F.createParser(DOC.toCharArray());
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        _assertLocation(useBytes, p.getTokenLocation(), 2L, 1, 3);
+        _assertLocation(useBytes, p.getCurrentLocation(), 3L, 1, 4);
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        _assertLocation(useBytes, p.getTokenLocation(), 3L, 1, 4);
+        assertEquals(10, p.getIntValue()); // just to ensure read proceeds to end
+        // 2-digits so
+        _assertLocation(useBytes, p.getCurrentLocation(), 5L, 1, 6);
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        _assertLocation(useBytes, p.getTokenLocation(), 7L, 1, 8);
+        assertEquals(251, p.getIntValue()); // just to ensure read proceeds to end
+        _assertLocation(useBytes, p.getCurrentLocation(), 10L, 1, 11);
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        _assertLocation(useBytes, p.getTokenLocation(), 15L, 2, 4);
+        assertEquals(3, p.getIntValue());
+        _assertLocation(useBytes, p.getCurrentLocation(), 16L, 2, 5);
+
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        _assertLocation(useBytes, p.getTokenLocation(), 18L, 2, 7);
+        _assertLocation(useBytes, p.getCurrentLocation(), 19L, 2, 8);
+        
+        p.close();
+    }
+
+    private void _assertLocation(boolean useBytes, JsonLocation loc, long offset, int row, int col)
+    {
+        assertEquals(row, loc.getLineNr());
+        assertEquals(col, loc.getColumnNr());
+
+        if (useBytes) {
+            assertEquals(offset, loc.getByteOffset());
+        } else {
+            assertEquals(offset, loc.getCharOffset());
+        }
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/LocationInObjectTest.java b/src/test/java/com/fasterxml/jackson/core/json/LocationInObjectTest.java
new file mode 100644
index 0000000..eb317d4
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/LocationInObjectTest.java
@@ -0,0 +1,99 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+
+// tests for [core#37]
+public class LocationInObjectTest extends BaseTest
+{
+    public void testOffsetWithObjectFieldsUsingUTF8() throws Exception
+    {
+        final JsonFactory f = new JsonFactory();
+        byte[] b = "{\"f1\":\"v1\",\"f2\":{\"f3\":\"v3\"},\"f4\":[true,false],\"f5\":5}".getBytes("UTF-8");
+        //            1      6      11    16 17    22      28    33 34 39      46    51
+        JsonParser p = f.createParser(b);
+
+        assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+        assertEquals(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals(1L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(6L, p.getTokenLocation().getByteOffset());
+
+        assertEquals("f2", p.nextFieldName());
+        assertEquals(11L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.START_OBJECT, p.nextValue());
+        assertEquals(16L, p.getTokenLocation().getByteOffset());
+
+        assertEquals("f3", p.nextFieldName());
+        assertEquals(17L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.VALUE_STRING, p.nextValue());
+        assertEquals(22L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+        assertEquals("f4", p.nextFieldName());
+        assertEquals(28L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.START_ARRAY, p.nextValue());
+        assertEquals(33L, p.getTokenLocation().getByteOffset());
+
+        assertEquals(JsonToken.VALUE_TRUE, p.nextValue());
+        assertEquals(34L, p.getTokenLocation().getByteOffset());
+
+        assertEquals(JsonToken.VALUE_FALSE, p.nextValue());
+        assertEquals(39L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.END_ARRAY, p.nextToken());
+
+        assertEquals("f5", p.nextFieldName());
+        assertEquals(46L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(51L, p.getTokenLocation().getByteOffset());
+        assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+        p.close();
+    }
+
+    public void testOffsetWithObjectFieldsUsingReader() throws Exception
+    {
+        final JsonFactory f = new JsonFactory();
+        char[] c = "{\"f1\":\"v1\",\"f2\":{\"f3\":\"v3\"},\"f4\":[true,false],\"f5\":5}".toCharArray();
+        //            1      6      11    16 17    22      28    33 34 39      46    51
+        JsonParser p = f.createParser(c);
+
+        assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+        assertEquals(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals(1L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals(6L, p.getTokenLocation().getCharOffset());
+
+        assertEquals("f2", p.nextFieldName());
+        assertEquals(11L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.START_OBJECT, p.nextValue());
+        assertEquals(16L, p.getTokenLocation().getCharOffset());
+
+        assertEquals("f3", p.nextFieldName());
+        assertEquals(17L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.VALUE_STRING, p.nextValue());
+        assertEquals(22L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+        assertEquals("f4", p.nextFieldName());
+        assertEquals(28L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.START_ARRAY, p.nextValue());
+        assertEquals(33L, p.getTokenLocation().getCharOffset());
+
+        assertEquals(JsonToken.VALUE_TRUE, p.nextValue());
+        assertEquals(34L, p.getTokenLocation().getCharOffset());
+
+        assertEquals(JsonToken.VALUE_FALSE, p.nextValue());
+        assertEquals(39L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.END_ARRAY, p.nextToken());
+
+        assertEquals("f5", p.nextFieldName());
+        assertEquals(46L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(51L, p.getTokenLocation().getCharOffset());
+        assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java b/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java
index a42c800..f3192e6 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java
@@ -5,16 +5,17 @@
 // NOTE: just a stub so for, fill me!
 public class TestLocation extends com.fasterxml.jackson.core.BaseTest
 {
+    final JsonFactory JSON_F = new JsonFactory();
+
     // Trivially simple unit test for basics wrt offsets
     public void testSimpleInitialOffsets() throws Exception
     {
-        final JsonFactory f = new JsonFactory();
         JsonLocation loc;
         JsonParser p;
         final String DOC = "{ }";
 
         // first, char based:
-        p = f.createParser(DOC);
+        p = JSON_F.createParser(DOC);
         assertToken(JsonToken.START_OBJECT, p.nextToken());
 
         loc = p.getTokenLocation();
@@ -33,7 +34,7 @@
 
         // then byte-based
         
-        p = f.createParser(DOC.getBytes("UTF-8"));
+        p = JSON_F.createParser(DOC.getBytes("UTF-8"));
         assertToken(JsonToken.START_OBJECT, p.nextToken());
 
         loc = p.getTokenLocation();
@@ -51,17 +52,16 @@
         p.close();
     }
 
-    // for [Issue#111]
+    // for [core#111]
     public void testOffsetWithInputOffset() throws Exception
     {
-        final JsonFactory f = new JsonFactory();
         JsonLocation loc;
         JsonParser p;
         // 3 spaces before, 2 after, just for padding
         byte[] b = "   { }  ".getBytes("UTF-8");
 
         // and then peel them off
-        p = f.createParser(b, 3, b.length-5);
+        p = JSON_F.createParser(b, 3, b.length-5);
         assertToken(JsonToken.START_OBJECT, p.nextToken());
 
         loc = p.getTokenLocation();
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java b/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
index feb8560..2aaeeb1 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
@@ -25,12 +25,23 @@
     {
         _testIsNextTokenName1(false);
         _testIsNextTokenName1(true);
+    }
+
+    public void testIsNextTokenName2() throws Exception {
         _testIsNextTokenName2(false);
         _testIsNextTokenName2(true);
+    }        
+    
+    public void testIsNextTokenName3() throws Exception {
         _testIsNextTokenName3(false);
         _testIsNextTokenName3(true);
     }
 
+    public void testIsNextTokenName4() throws Exception {
+        _testIsNextTokenName4(false);
+        _testIsNextTokenName4(true);
+    }
+    
     // [jackson-core#34]
     public void testIssue34() throws Exception
     {
@@ -110,6 +121,7 @@
         assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
         assertEquals("name2", jp.getCurrentName());
         assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+        // do NOT check number value, to enforce skipping
 
         assertFalse(jp.nextFieldName(NAME));
         assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
@@ -234,6 +246,27 @@
         p.close();
     }
 
+    private void _testIsNextTokenName4(boolean useStream) throws Exception
+    {
+        final String DOC = "{\"name\":-123,\"name2\":99}";
+        JsonParser jp = useStream ?
+                JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
+            : JSON_F.createParser(new StringReader(DOC));
+        assertToken(JsonToken.START_OBJECT, jp.nextToken());
+
+        assertTrue(jp.nextFieldName(new SerializedString("name")));
+        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+        assertEquals(-123, jp.getIntValue());
+
+        assertTrue(jp.nextFieldName(new SerializedString("name2")));
+        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+        assertEquals(99, jp.getIntValue());
+        assertToken(JsonToken.END_OBJECT, jp.nextToken());
+        assertNull(jp.nextToken());
+
+        jp.close();
+    }
+
     private void _testNextFieldNameIndent(boolean useStream) throws Exception
     {
         final String DOC = "{\n  \"name\" : \n  [\n  ]\n   }";
@@ -251,7 +284,7 @@
 
         p.close();
     }
-    
+
     private void _textNextText(boolean useStream) throws Exception
     {
         final String DOC = aposToQuotes("{'a':'123','b':5,'c':[false,'foo']}");
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java b/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
index ceea01a..fb99205 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
@@ -389,7 +389,7 @@
             }
             sb.append(segment);
             sb.append('\n');
-            // let's add somewhat arbitray number of spaces
+            // let's add somewhat arbitrary number of spaces
             int x = (i & 3);
             if (i > 300) {
                 x += i % 5;
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
index 3fed2d5..3cf4020 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
@@ -37,7 +37,7 @@
         p.close();
     }
 
-    // for [Issue#115]
+    // for [core#115]
     public void testSurrogatesWithRaw() throws Exception
     {
         final String VALUE = quote("\ud83d\ude0c");
diff --git a/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java b/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java
index 045a943..9fa5871 100644
--- a/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java
+++ b/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java
@@ -38,33 +38,6 @@
         assertEquals(6, symbols.maxCollisionLength());
     }
 
-    // Test for verifying stability of hashCode, wrt collisions, using
-    // synthetic field name generation and byte-based input (UTF-8)
-    @SuppressWarnings("deprecation")
-    public void testSyntheticWithBytesOld() throws IOException
-    {
-        // pass seed, to keep results consistent:
-        final int SEED = 33333;
-        BytesToNameCanonicalizer symbols =
-                BytesToNameCanonicalizer.createRoot(SEED).makeChild(JsonFactory.Feature.collectDefaults());
-
-        final int COUNT = 12000;
-        for (int i = 0; i < COUNT; ++i) {
-            String id = fieldNameFor(i);
-            int[] quads = calcQuads(id.getBytes("UTF-8"));
-            symbols.addName(id, quads, quads.length);
-        }
-        assertEquals(COUNT, symbols.size());
-        assertEquals(16384, symbols.bucketCount());
-
-//System.out.printf("Byte stuff: collisions %d, max-coll %d\n", symbols.collisionCount(), symbols.maxCollisionLength());
-        assertEquals(3476, symbols.collisionCount());
-        // longest collision chain not optimal but ok:
-        assertEquals(15, symbols.maxCollisionLength());
-
-        // But also verify entries are actually found?
-    }
-
     public void testSyntheticWithBytesNew() throws IOException
     {
         // pass seed, to keep results consistent:
@@ -119,35 +92,6 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
-    public void testThousandsOfSymbolsWithOldBytes() throws IOException
-    {
-        final int SEED = 33333;
-
-        BytesToNameCanonicalizer symbolsBRoot = BytesToNameCanonicalizer.createRoot(SEED);
-        final Charset utf8 = Charset.forName("UTF-8");
-        int exp = 0;
-        
-        for (int doc = 0; doc < 100; ++doc) {
-            BytesToNameCanonicalizer symbolsB =
-                    symbolsBRoot.makeChild(JsonFactory.Feature.collectDefaults());
-            for (int i = 0; i < 250; ++i) {
-                String name = "f_"+doc+"_"+i;
-
-                int[] quads = BytesToNameCanonicalizer.calcQuads(name.getBytes(utf8));
-                symbolsB.addName(name, quads, quads.length);
-                Name n = symbolsB.findName(quads, quads.length);
-                assertEquals(name, n.getName());
-            }
-            symbolsB.release();
-            exp += 250;
-            if (exp > BytesToNameCanonicalizer.MAX_ENTRIES_FOR_REUSE) {
-                exp = 0;
-            }
-            assertEquals(exp, symbolsBRoot.size());
-        }
-    }
-
     // Since 2.6
     public void testThousandsOfSymbolsWithNew() throws IOException
     {
@@ -234,30 +178,6 @@
     }
 
     // [core#187]: unexpectedly high number of collisions for straight numbers
-    @SuppressWarnings("deprecation")
-    public void testCollisionsWithBytes187() throws IOException
-    {
-        BytesToNameCanonicalizer symbols =
-                BytesToNameCanonicalizer.createRoot(1).makeChild(JsonFactory.Feature.collectDefaults());
-        final int COUNT = 30000;
-        for (int i = 0; i < COUNT; ++i) {
-            String id = String.valueOf(10000 + i);
-            int[] quads = BytesToNameCanonicalizer.calcQuads(id.getBytes("UTF-8"));
-            symbols.addName(id, quads, quads.length);
-        }
-
-//System.out.printf("Byte stuff: collisions %d, max-coll %d\n", symbols.collisionCount(), symbols.maxCollisionLength());
-        
-        assertEquals(COUNT, symbols.size());
-        assertEquals(65536, symbols.bucketCount());
-
-        // collision count acceptable
-        assertEquals(5782, symbols.collisionCount());
-        // as well as collision counts
-        assertEquals(24, symbols.maxCollisionLength());
-    }
-
-    // [core#187]: unexpectedly high number of collisions for straight numbers
     public void testCollisionsWithChars187() throws IOException
     {
         CharsToNameCanonicalizer symbols = CharsToNameCanonicalizer.createRoot(1);
@@ -386,24 +306,6 @@
         assertEquals(2, symbols.maxCollisionLength());
     }
 
-    @SuppressWarnings("deprecation")
-    public void testShortQuotedDirectBytesOld() throws IOException
-    {
-        final int COUNT = 400;
-        BytesToNameCanonicalizer symbols =
-                BytesToNameCanonicalizer.createRoot(1).makeChild(JsonFactory.Feature.collectDefaults());
-        for (int i = 0; i < COUNT; ++i) {
-            String id = String.format("\\u%04x", i);
-            int[] quads = BytesToNameCanonicalizer.calcQuads(id.getBytes("UTF-8"));
-            symbols.addName(id, quads, quads.length);
-        }
-        assertEquals(COUNT, symbols.size());
-        assertEquals(1024, symbols.bucketCount());
-
-        assertEquals(44, symbols.collisionCount());
-        assertEquals(2, symbols.maxCollisionLength());
-    }
-
     public void testShortQuotedDirectBytes() throws IOException
     {
         final int COUNT = 400;
@@ -424,7 +326,6 @@
     }
     
     // [core#191]
-    @SuppressWarnings("deprecation")
     public void testShortNameCollisionsDirect() throws IOException
     {
         final int COUNT = 600;
@@ -443,22 +344,6 @@
             assertEquals(16, symbols.collisionCount());
             assertEquals(1, symbols.maxCollisionLength());
         }
-        
-        // then byte-based
-        {
-            BytesToNameCanonicalizer symbols =
-                    BytesToNameCanonicalizer.createRoot(1).makeChild(JsonFactory.Feature.collectDefaults());
-            for (int i = 0; i < COUNT; ++i) {
-                String id = String.valueOf((char) i);
-                int[] quads = calcQuads(id.getBytes("UTF-8"));
-                symbols.addName(id, quads, quads.length);
-            }
-            assertEquals(COUNT, symbols.size());
-            assertEquals(1024, symbols.bucketCount());
-    
-            assertEquals(209, symbols.collisionCount());
-            assertEquals(1, symbols.maxCollisionLength());
-        }
     }
 
     public void testShortNameCollisionsDirectNew() throws IOException
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java b/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
index 2ce3917..4f467fe 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
+++ b/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
@@ -6,7 +6,7 @@
 
 /**
  * Set of basic unit tests for verifying that the low-level number
- * printingg methods work as expected.
+ * printing methods work as expected.
  */
 public class TestNumberPrinting
     extends com.fasterxml.jackson.core.BaseTest
diff --git a/src/test/java/com/fasterxml/jackson/failing/Surrogate223Test.java b/src/test/java/com/fasterxml/jackson/failing/Surrogate223Test.java
new file mode 100644
index 0000000..33dd2ae
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/failing/Surrogate223Test.java
@@ -0,0 +1,90 @@
+package com.fasterxml.jackson.failing;
+
+import java.io.ByteArrayOutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
+public class Surrogate223Test extends BaseTest
+{
+    private final JsonFactory JSON_F = new JsonFactory();
+    
+    // for [core#223]
+    public void testSurrogatesByteBacked() throws Exception
+    {
+        ByteArrayOutputStream out;
+        JsonGenerator g;
+        final String toQuote = new String(Character.toChars(0x1F602));
+        assertEquals(2, toQuote.length()); // just sanity check
+
+        // default should be disabled:
+//        assertFalse(JSON_F.isEnabled(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES));
+
+        out = new ByteArrayOutputStream();
+        g = JSON_F.createGenerator(out);
+        g.writeStartArray();
+        g.writeString(toQuote);
+        g.writeEndArray();
+        g.close();
+        assertEquals(2 + 2 + 4, out.size()); // brackets, quotes, 4-byte encoding
+
+        // Also parse back to ensure correctness
+        JsonParser p = JSON_F.createParser(out.toByteArray());
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+        
+        // but may revert back to original behavior
+        out = new ByteArrayOutputStream();
+        g = JSON_F.createGenerator(out);
+//        g.enable(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES);
+        g.writeStartArray();
+        g.writeString(toQuote);
+        g.writeEndArray();
+        g.close();
+        assertEquals(2 + 2 + 12, out.size()); // brackets, quotes, 2 x 6 byte JSON escape
+    }
+
+    // for [core#223]
+    public void testSurrogatesCharBacked() throws Exception
+    {
+        Writer out;
+        JsonGenerator g;
+        final String toQuote = new String(Character.toChars(0x1F602));
+        assertEquals(2, toQuote.length()); // just sanity check
+
+        // default should be disabled:
+//        assertFalse(JSON_F.isEnabled(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES));
+
+        out = new StringWriter();
+        g = JSON_F.createGenerator(out);
+        g.writeStartArray();
+        g.writeString(toQuote);
+        g.writeEndArray();
+        g.close();
+        assertEquals(2 + 2 + 2, out.toString().length()); // brackets, quotes, 2 chars as is
+
+        // Also parse back to ensure correctness
+        JsonParser p = JSON_F.createParser(out.toString());
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        p.close();
+        
+        // but may revert back to original behavior
+        out = new StringWriter();
+        g = JSON_F.createGenerator(out);
+//        g.enable(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES);
+        g.writeStartArray();
+        g.writeString(toQuote);
+        g.writeEndArray();
+        g.close();
+        assertEquals(2 + 2 + 12, out.toString().length()); // brackets, quotes, 2 x 6 byte JSON escape
+    }
+}