在SpiderMonkey的代码中经常能够看到JSAtom这一个数据结构。它并不是定义在 js/src/jsatom.h 中,而是在js/src/vm/String.h中。SpiderMonkey为了能够快速的实现字符串的复制、比较操作,使用了一系列的C++对象。具体实现在String.h的注释中有描述:
/*
* JavaScript strings
*
* Conceptually, a JS string is just an array of chars and a length. This array
* of chars may or may not be null-terminated and, if it is, the null character
* is not included in the length.
*
* To improve performance of common operations, the following optimizations are
* made which affect the engine’s representation of strings:
*
* - The plain vanilla representation is a “flat” string which consists of a
* string header in the GC heap and a malloc’d null terminated char array.
*
* - To avoid copying a substring of an existing “base” string , a “dependent”
* string (JSDependentString) can be created which points into the base
* string’s char array.
*
* - To avoid O(n^2) char buffer copying, a “rope” node (JSRope) can be created
* to represent a delayed string concatenation. Concatenation (called
* flattening) is performed if and when a linear char array is requested. In
* general, ropes form a binary dag whose internal nodes are JSRope string
* headers with no associated char array and whose leaf nodes are either flat
* or dependent strings.
*
* - To avoid copying the left-hand side when flattening, the left-hand side’s
* buffer may be grown to make space for a copy of the right-hand side (see
* comment in JSString::flatten). This optimization requires that there are
* no external pointers into the char array. We conservatively maintain this
* property via a flat string’s “extensible” property.
*
* - To avoid allocating small char arrays, short strings can be stored inline
* in the string header (JSInlineString). To increase the max size of such
* inline strings, extra-large string headers can be used (JSShortString).
*
* - To avoid comparing O(n) string equality comparison, strings can be
* canonicalized to “atoms” (JSAtom) such that there is a single atom with a
* given (length,chars).
*
* - To avoid copying all strings created through the JSAPI, an “external”
* string (JSExternalString) can be created whose chars are managed by the
* JSAPI client.
*
* Although all strings share the same basic memory layout, we can conceptually
* arrange them into a hierarchy of operations/invariants and represent this
* hierarchy in C++ with classes:
*
* C++ type operations+fields / invariants+properties
* ========================== =========================================
* JSString (abstract) getCharsZ, getChars, length / -
* |
* | JSRope leftChild, rightChild / -
* |
* JSLinearString (abstract) chars / might be null-terminated
* |
* | JSDependentString base / -
* |
* JSFlatString - / null terminated
* | |
* | +– JSStableString - / may have external pointers into char array
* | |
* | +– JSExternalString - / char array memory managed by embedding
* | |
* | +– JSExtensibleString capacity / no external pointers into char array
* | |
* | +– JSUndependedString original dependent base / -
* | |
* | +– JSInlineString - / chars stored in header
* |
* | JSShortString - / header is fat
* |
* JSAtom - / string equality === pointer equality
* |
* js::PropertyName - / chars don’t contain an index (uint32_t)
*
* Classes marked with (abstract) above are not literally C++ Abstract Base
* Classes (since there are no virtual functions, pure or not, in this
* hierarchy), but have the same meaning: there are no strings with this type as
* its most-derived type.
*
* Technically, there are three additional most-derived types that satisfy the
* invariants of more than one of the abovementioned most-derived types:
* - InlineAtom = JSInlineString + JSAtom (atom with inline chars)
* - ShortAtom = JSShortString + JSAtom (atom with (more) inline chars)
* - StableAtom = JSStableString + JSAtom (atom with out-of-line chars)
*
* Derived string types can be queried from ancestor types via isX() and
* retrieved with asX() debug-only-checked casts.
*
* The ensureX() operations mutate ‘this’ in place to effectively the type to be
* at least X (e.g., ensureLinear will change a JSRope to be a JSFlatString).
*/