js字符串最多存儲(chǔ)多少字節(jié)?
V8的heap上限只有2GB不到闻葵,允許分配的單個(gè)字符串大小上限更只有大約是512MB不到民泵。JS字符串是UTF16編碼保存,所以也就是2.68億個(gè)字符槽畔。FF大約也是這個(gè)數(shù)字栈妆。
https://www.zhihu.com/question/61105131
JavaScript字符串底層是如何實(shí)現(xiàn)的?
作者:RednaxelaFX
鏈接:https://www.zhihu.com/question/51132164/answer/124450796
來源:知乎
著作權(quán)歸作者所有厢钧。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)鳞尔,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
目前主流的做法是把String值的實(shí)現(xiàn)分為5大類使用場(chǎng)景:
- 已經(jīng)要查看內(nèi)容的字符串:使用flat string思路來實(shí)現(xiàn)早直,本質(zhì)上說就是用數(shù)組形式來存儲(chǔ)String的內(nèi)容寥假;
- 拼接字符串但尚未查看其內(nèi)容:使用“rope”思路或其它延遲拼接的思路來實(shí)現(xiàn)。當(dāng)需要查看其內(nèi)容時(shí)則進(jìn)行“flatten”操作將其轉(zhuǎn)換為flat string表現(xiàn)形式莽鸿。最常見rope的內(nèi)部節(jié)點(diǎn)就像二叉樹(RopeNode { Left; Right })一樣昧旨,但也可以有采用更多叉樹的設(shè)計(jì)的節(jié)點(diǎn)拾给,或者是用更動(dòng)態(tài)的多叉樹實(shí)現(xiàn)祥得;
- 子串(substring):使用“slice”思路來實(shí)現(xiàn),也就是說它只是一個(gè)view蒋得,自己并不存儲(chǔ)字符內(nèi)容而只是記錄個(gè)offset和length级及,底下的存儲(chǔ)共享自其引用的源字符串;
- 值得駐留(intern)的字符串:通常也是flat string但可能會(huì)有更多的限制额衙,存儲(chǔ)它的空間可能也跟普通String不一樣饮焦。最大的好處是在特殊場(chǎng)景下有些字符串會(huì)經(jīng)常重復(fù)出現(xiàn),或者要經(jīng)常用于相等性比較窍侧,把這些字符串駐留起來可以節(jié)省內(nèi)存(內(nèi)容相同的字符串只駐留一份)县踢,并且后續(xù)使用可以使用指針比較來代替完全的相等性比較(因?yàn)轳v留的時(shí)候已經(jīng)比較過了);
- 外來字符串:有時(shí)候JavaScript引擎跟外界交互伟件,外界想直接把一個(gè)char8_t或者char16_t傳給JavaScript引擎當(dāng)作JavaScript字符串用硼啤。JavaScript引擎可能會(huì)針對(duì)某些特殊場(chǎng)景提供一種包裝方式來直接把這些外部傳進(jìn)來的字符串當(dāng)作JavaScript String,而不拷貝其內(nèi)容斧账。
在上述5種場(chǎng)景中谴返,涉及存儲(chǔ)的時(shí)候都可以有
- 使用UTF-16為單元的最常規(guī)做法以及使用Latin-1 / ASCII的壓縮版本這兩種變種煞肾。
- 對(duì)于flat string,直接把字符串內(nèi)容粘在對(duì)象末尾的“內(nèi)嵌版”嗓袱,以及把字符串內(nèi)容放在獨(dú)立的數(shù)組里的“獨(dú)立數(shù)組版”兩個(gè)變種籍救。
如果把語言層面的一個(gè)String值類型按上述使用場(chǎng)景給拆分成若干種不同的底層實(shí)現(xiàn)類型,本質(zhì)上都是在為內(nèi)存而優(yōu)化:要么是減少String的內(nèi)存使用量(1-byte vs 2-byte渠抹、substring等)蝙昙,要么是減少拷貝的次數(shù)/長(zhǎng)度(rope的按需flatten)。
底層實(shí)現(xiàn)類型的數(shù)量的增多梧却,會(huì)使得相關(guān)處理的代碼都變得多態(tài)耸黑,不利于編譯器對(duì)其做優(yōu)化,所以這里是有取舍的篮幢。如果多態(tài)換來的內(nèi)存收益比不上多態(tài)的代碼開銷的話就得不償失了大刊。顯然,眾多JavaScript引擎都選擇了在String值類型上細(xì)分出多種實(shí)現(xiàn)類型三椿,反映了多態(tài)在這個(gè)地方總體來看是有利的缺菌。
把上面的場(chǎng)景(1)、(2)搜锰、(3)用代碼來舉例:
var s1 = "rednaxela"; // flat string, string literal
var s2 = "fx"; // flat string, string literal
var s3 = s1 + s2; // rope ("concat string", "cons string")
var s4 = s3.substring(0, 3); // substring / slice
// 這個(gè)操作可能會(huì)讓s3所引用的String值被flatten為flat string
// 同理伴郁,如果執(zhí)行 s3[0] 下標(biāo)操作也可能會(huì)讓原本是rope的String值被flatten
在有用rope來優(yōu)化字符串拼接的JavaScript引擎上,使用二元+運(yùn)算符來拼接字符串其實(shí)不會(huì)直接導(dǎo)致冗余的字符串內(nèi)容拷貝蛋叼,只有在需要使用字符串的內(nèi)容時(shí)才會(huì)對(duì)它做一次批量的flatten操作焊傅,做一次拷貝。所以字符串拼接“要用Array.prototype.join()而忌諱用+運(yùn)算符”的建議就不那么重要了狈涮。
=========================================
V8
于是讓我們來考察一下V8的String都有上述場(chǎng)景的哪些狐胎。
針對(duì)5.5.339版本來看:
v8/objects.h at 5.5.339 · v8/v8 · GitHub
// - Name
// - String
// - SeqString
// - SeqOneByteString
// - SeqTwoByteString
// - SlicedString
// - ConsString
// - ExternalString
// - ExternalOneByteString
// - ExternalTwoByteString
// - InternalizedString
// - SeqInternalizedString
// - SeqOneByteInternalizedString
// - SeqTwoByteInternalizedString
// - ConsInternalizedString
// - ExternalInternalizedString
// - ExternalOneByteInternalizedString
// - ExternalTwoByteInternalizedString
// - Symbol
V8里能表示字符串的C++類型有上面這么多種。其中Name是String(ES String Value)與Symbol(ES6 Symbol)的基類歌馍∥粘玻看看String類下面的子類是多么的豐富 >_<
簡(jiǎn)單說,String的子類都是用于實(shí)現(xiàn)ECMAScript的String值類型松却,從JavaScript層面看它們都是同一個(gè)類型——String暴浦,也就是說typeof()它們都會(huì)得到"string"。
其中:
SeqString就是上面的場(chǎng)景(1)(“flat string”)的實(shí)現(xiàn)晓锻。其中有SeqOneByteString / SeqTwoByteString分別對(duì)應(yīng)使用1-byte ASCII char與2-byte UTF-16的版本歌焦。字符串內(nèi)容都是直接粘在對(duì)象末尾的(“內(nèi)嵌版”)。
ConsString就是上面的場(chǎng)景(2)(“rope”)的實(shí)現(xiàn)砚哆。本質(zhì)上就是把還在拼接中的字符串用二叉樹(其實(shí)是二叉DAG)的方式先存著独撇,直到要查看其內(nèi)容時(shí)再flatten成SeqString。它自身不存儲(chǔ)字符內(nèi)容所以不關(guān)心1-byte還是2-byte。
SlicedString就是上面場(chǎng)景(3)(“slice / substring”)的實(shí)現(xiàn)券勺。同上它也不存儲(chǔ)字符內(nèi)容绪钥,所以1-byte還是2-byte就看引用的底層String是怎樣的。
ExternalString就是上面場(chǎng)景(5)(外部傳入的字符串)的實(shí)現(xiàn)关炼。這個(gè)涉及存儲(chǔ)程腹,所以也有1-byte與2-byte兩個(gè)實(shí)際實(shí)現(xiàn)。
InternalizedString系列就是上面場(chǎng)景(4)(“interned”)的實(shí)現(xiàn)儒拂。它的子類跟前面列舉的幾種類型一一對(duì)應(yīng)寸潦。
而String的包裝對(duì)象類型在V8里則是由StringWrapper來實(shí)現(xiàn):
bool HeapObject::IsStringWrapper() const {
return IsJSValue() && JSValue::cast(this)->value()->IsString();
}
值得注意的是:雖然ECMAScript的String值是值類型的,這并不就是說“String值就是在棧上的”社痛。
正好相反见转,V8所實(shí)現(xiàn)的String值全部都是在V8的GC堆上存儲(chǔ)的,傳遞String值時(shí)實(shí)際上傳遞的是指向它的指針蒜哀。但由于JavaScript的String值是不可變的斩箫,所以底層實(shí)現(xiàn)無論是真的把String“放在棧上”還是傳遞指針,對(duì)上層應(yīng)用的JavaScript代碼而言都沒有區(qū)別撵儿。
ExternalString雖然特殊但也不例外:它實(shí)際存儲(chǔ)字符串內(nèi)容的空間雖然是從外部傳進(jìn)來的乘客,不在V8的GC堆里,但是ExternalString對(duì)象自身作為一個(gè)對(duì)象頭還是在GC堆里的淀歇,所以該String類型實(shí)現(xiàn)邏輯上說還是在GC堆里易核。
話說V8除了上述String類型外,還有一些跟String相關(guān)的浪默、應(yīng)用于特殊場(chǎng)景的類型牡直。其中比較典型的有:
ReplacementStringBuilder:用于正則表達(dá)式的字符串替換等;
IncrementalStringBuilder:// TODO
這個(gè)版本的V8對(duì)自己字符串拼接實(shí)現(xiàn)已經(jīng)頗有信心纳决,所以 String.prototype.concat 也直接用JavaScript來實(shí)現(xiàn)了:
v8/string.js at 5.5.339 · v8/v8 · GitHub
// ECMA-262, section 15.5.4.6
function StringConcat(other /* and more */) { // length == 1
"use strict";
CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat");
var s = TO_STRING(this);
var len = arguments.length;
for (var i = 0; i < len; ++i) {
s = s + TO_STRING(arguments[i]);
}
return s;
}
這就是直接把傳入的參數(shù)拼接成ConsString返回出去碰逸。
V8連標(biāo)準(zhǔn)庫(kù)函數(shù)都用這種代碼模式來實(shí)現(xiàn)了,同學(xué)們也不用擔(dān)心這樣做會(huì)太慢啦岳链。
而V8里的 Array.prototype.join 則針對(duì)稀疏數(shù)組的情況有些有趣的優(yōu)化:
它會(huì)借助一個(gè)臨時(shí)的InternalArray為“string builder”花竞,計(jì)算出拼接結(jié)果的length之后直接分配一個(gè)合適類型和長(zhǎng)度的SeqString作為buffer來進(jìn)行拼接劲件。而這個(gè)InternalArray里的內(nèi)容可以帶有編碼為Smi的“下一段要拼接的字符串在什么位置(position)和長(zhǎng)度(length)”信息掸哑,然后從當(dāng)前位置到下一個(gè)要拼接的位置之間填充分隔符,這樣就不會(huì)在對(duì)稀疏數(shù)組的join過程中把數(shù)組中無值的位置都填充到“string builder”的實(shí)體里去了零远。這是個(gè)run-length encoding的思路苗分。
V8還有個(gè)有趣的功能:原地縮小對(duì)象而不必為了縮小而拷貝。這個(gè)有空再具體展開寫牵辣。
=========================================
Nashorn
讓我們看看JDK8u112-b04里的Nashorn實(shí)現(xiàn)摔癣。
它比V8要簡(jiǎn)單一些,實(shí)現(xiàn)ECMAScript String值的類型都是java.lang.CharSequence接口的實(shí)現(xiàn)類,其中有:
- 場(chǎng)景(1)(“flat string”):直接使用Java原生的 java.lang.String 類型择浊,方便用上JVM對(duì)String的優(yōu)化戴卜。在一個(gè)JDK/JVM自身就有針對(duì)1-byte / 2-byte場(chǎng)景做優(yōu)化的實(shí)現(xiàn)上(例如Oracle JDK9 / OpenJDK9的Compact Strings),Nashorn就會(huì)自動(dòng)獲得相應(yīng)的優(yōu)化琢岩;
- 場(chǎng)景(2)(“rope”):不免俗投剥,有個(gè)實(shí)現(xiàn)了CharSequence接口的ConsString類型;
- 場(chǎng)景(3)(“slice / substring”):直接用java.lang.String.substring()實(shí)現(xiàn)担孔,沒有額外優(yōu)化江锨。Oracle JDK / OpenJDK在JDK7后撤銷了java.lang.String的子串共享實(shí)現(xiàn),所以Nashorn里的slice() / substring()在這些JDK上會(huì)涉及拷貝開銷…orz糕篇!
- 場(chǎng)景(4)(“intern”):只有少量地方做了intern啄育,是直接用 java.lang.String.intern() 的。
- 場(chǎng)景(5)(外部傳入的字符串):沒有特別的對(duì)應(yīng)支持拌消。Nashorn面向的用戶是其它JVM上的語言(例如Java)挑豌,所以外部傳入的字符串最可能的也就是 java.lang.String ,正好Nashorn自身的flat string就是直接用 java.lang.String 墩崩,所以也就不用做什么額外工作來支持這些外來字符串了浮毯。
ECMAScript的String包裝對(duì)象類型則由這個(gè)NativeString類型表示:NativeString,里面就是包裝著一個(gè)代表String值的CharSequence類型引用泰鸡。
Nashorn在實(shí)現(xiàn) String.prototype.concat() 時(shí)沒有特別的實(shí)現(xiàn)债蓝,是直接把參數(shù)拼接成一串ConsString然后直接返回沒有flatten的ConsString。
=========================================
SpiderMonkey
這里用FIREFOX_AURORA_51_BASE版代碼來考察盛龄。
總體來說SpiderMonkey里的String的內(nèi)部實(shí)現(xiàn)思路與V8的非常相似饰迹。
代碼里的注釋把設(shè)計(jì)思路講解得很清楚了:
http://hg.mozilla.org/mozilla-central/file/fc69febcbf6c/js/src/vm/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 leftmost string when flattening, we may produce an
"extensible" string, which tracks not only its actual length but also its
buffer's overall size. If such an "extensible" string appears as the
leftmost string in a subsequent flatten, and its buffer has enough unused
space, we can simply flatten the rest of the ropes into its buffer,
leaving its text in place. We then transfer ownership of its buffer to the
flattened rope, and mutate the donor extensible string into a dependent
string referencing its original buffer.
(The term "extensible" does not imply that we ever 'realloc' the buffer.
Extensible strings may have dependent strings pointing into them, and the
JSAPI hands out pointers to flat strings' buffers, so resizing with
'realloc' is generally not possible.)
- To avoid allocating small char arrays, short strings can be stored inline
in the string header (JSInlineString). These come in two flavours:
JSThinInlineString, which is the same size as JSString; and
JSFatInlineString, which has a larger header and so can fit more chars.
- 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.
- To avoid using two bytes per character for every string, string characters
are stored as Latin1 instead of TwoByte if all characters are representable
in Latin1.
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) get(Latin1|TwoByte)CharsZ, get(Latin1|TwoByte)Chars, length / -
| \
| JSRope leftChild, rightChild / -
|
JSLinearString (abstract) latin1Chars, twoByteChars / might be null-terminated
| \
| JSDependentString base / -
|
JSFlatString - / null terminated
| |
| +-- JSExternalString - / char array memory managed by embedding
| |
| +-- JSExtensibleString tracks total buffer capacity (including current text)
| |
| +-- JSUndependedString original dependent base / -
| |
| +-- JSInlineString (abstract) - / chars stored in header
| |
| +-- JSThinInlineString - / header is normal
| |
| +-- JSFatInlineString - / 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.
Atoms can additionally be permanent, i.e. unable to be collected, and can
be combined with other string types to create 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, abstract)
- ThinInlineAtom = JSThinInlineString + JSAtom (atom with inline chars)
- FatInlineAtom = JSFatInlineString + JSAtom (atom with (more) inline 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).
*/
可以看到,SpiderMonkey里的 JSString 是表現(xiàn)ECMAScript String值的基類余舶。它下面的子類的層次設(shè)計(jì)跟V8的頗有相似之處啊鸭,完全應(yīng)對(duì)了本回答開頭提到的5種場(chǎng)景:
- 場(chǎng)景(1)(“flat string”):JSFlatString 及其子類。最特別的是它的“inline string”匿值,這是在JSString的共同header里“偷空間”來存儲(chǔ)字符內(nèi)容的設(shè)計(jì)赠制。這種思路也叫做“small string”優(yōu)化,我在以前另一個(gè)回答里提及過:在stack上做small string或small vector優(yōu)化比在heap上效率高嗎? - RednaxelaFX 的回答
- 場(chǎng)景(2)(“rope”):JSRope 實(shí)現(xiàn)了典型的二叉樹(二叉DAG)形式的rope挟憔。不過它具體用在字符串拼接的時(shí)候也有些有趣的優(yōu)化钟些,上面引用的代碼注釋以及提到了:flat string下面有一種專門為用作字符串拼接的buffer的類型JSExtensibleString,它可以在拼接過程中有一個(gè)比較長(zhǎng)的長(zhǎng)度绊谭,然后等拼接結(jié)束確定最終長(zhǎng)度后再原地把自己的長(zhǎng)度縮短到實(shí)際長(zhǎng)度政恍。這個(gè)功能也跟V8可以原地縮小對(duì)象大小的功能類似。
- 場(chǎng)景(3)(“slice / substring”):JSDependentString
- 場(chǎng)景(4)(“intern”):JSAtom 及其子類 js::PropertyName
- 場(chǎng)景(5)(外部傳入的字符串):JSExternalString
上述所有涉及實(shí)際字符串內(nèi)容的存儲(chǔ)的類似都有針對(duì)7-bit Latin1與2-byte UTF-16的特化支持达传。
=========================================
Chakra / ChakraCore
請(qǐng)參考
大大的回答篙耗∑戎回頭有空我再寫點(diǎn)我的版本。
=========================================
其它JavaScript引擎的細(xì)節(jié)回頭再更新…
310
作者:Thomson
鏈接:https://www.zhihu.com/question/51132164/answer/124477176
來源:知乎
著作權(quán)歸作者所有宗弯。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)脯燃,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
R大已經(jīng)答全了蒙保,我就填下Chakra的坑吧曲伊。
Chakra的C++實(shí)現(xiàn)的String的基類是JavascriptString,保存的基本上就是一個(gè)字符串指針(為了跨平臺(tái)自定義了char16追他,在Windows上定義成WCHAR坟募。
ChakraCore/JavascriptString.h at master · Microsoft/ChakraCore · GitHub
class JavascriptString _ABSTRACT : public RecyclableObject
{
...
private:
const char16* m_pszValue; // Flattened, '\0' terminated contents
charcount_t m_charLength; // Length in characters, not including '\0'.
為了優(yōu)化常見使用場(chǎng)景如字符串連接,子串等操作還定義了不少子類:
JavascriptString
|- LiteralString
| |- CompundString
| |- ConcateStringBase
| |- ConcatStringN
| | |- ConcatString
| |- ConcatStringBuilder
| PropertyString
| SingleCharString
| SubString
| WritableString
比如經(jīng)常使用的字符串連接操作如下:
ChakraCore/JavascriptString.cpp at master · Microsoft/ChakraCore · GitHub邑狸,
inline JxavascriptString* JavascriptString::Concat(JavascriptString* pstLeft, JavascriptString* pstRight)
{
if(!pstLeft->IsFinalized())
{
if(CompoundString::Is(pstLeft))
{
return Concat_Compound(pstLeft, pstRight);
}
if(VirtualTableInfo<ConcatString>::HasVirtualTable(pstLeft))
{
return Concat_ConcatToCompound(pstLeft, pstRight);
}
}
else if(pstLeft->GetLength() == 0 || pstRight->GetLength() == 0)
{
return Concat_OneEmpty(pstLeft, pstRight);
}
if(pstLeft->GetLength() != 1 || pstRight->GetLength() != 1)
{
return ConcatString::New(pstLeft, pstRight);
}
return Concat_BothOneChar(pstLeft, pstRight);
}
對(duì)非簡(jiǎn)單的字符串連接直接構(gòu)造了ConcatString對(duì)象懈糯,該對(duì)象父類(ConcatStringN)里面有一個(gè)JavascriptString指針的數(shù)組(ConcatStringN通過模板可連接的JavascriptString數(shù)量參數(shù)化,ConcatString對(duì)應(yīng)最常見的N=2)单雾,在ConcatString的構(gòu)造函數(shù)里面把待連接的兩個(gè)JavascriptString存進(jìn)數(shù)組赚哗,這樣可以不用分配內(nèi)存和做copy。由于左右都是JavascriptString*硅堆,同樣可以使ConcatString屿储,這樣遞歸下去就會(huì)生成R大提到 rope 思路的DAG(我開始沒注意到這里的遞歸,多謝R大指出)渐逃。整個(gè)字符串的 flatten 是需要的時(shí)候再做够掠,借用了lazy computation的想法。
ChakraCore/ConcatString.h at master · Microsoft/ChakraCore · GitHub
template <int N>
class ConcatStringN : public ConcatStringBase
{
...
protected:
JavascriptString* m_slots[N]; // These contain the child nodes. 1 slot is per 1 item (JavascriptString*).
};
ChakraCore/ConcatString.cpp at master · Microsoft/ChakraCore · GitHub
ConcatString::ConcatString(JavascriptString* a, JavascriptString* b) :
ConcatStringN<2>(a->GetLibrary()->GetStringTypeStatic(), false)
{
a = CompoundString::GetImmutableOrScriptUnreferencedString(a);
b = CompoundString::GetImmutableOrScriptUnreferencedString(b);
m_slots[0] = a;
m_slots[1] = b;
this->SetLength(a->GetLength() + b->GetLength()); // does not include null character
}
另外對(duì)SubString也有類似的優(yōu)化茄菊,直接構(gòu)造了SubString對(duì)象作為JavascriptString的子類對(duì)象返回疯潭。
ChakraCore/SubString.h at master · Microsoft/ChakraCore · GitHub
class SubString sealed : public JavascriptString
{
void const * originalFullStringReference; // Only here to prevent recycler to free this buffer.
SubString(void const * originalFullStringReference, const char16* subString, charcount_t length, ScriptContext *scriptContext);
ChakraCore/SubString.cpp at master · Microsoft/ChakraCore · GitHub
inline SubString::SubString(void const * originalFullStringReference, const char16* subString, charcount_t length, ScriptContext *scriptContext) :
JavascriptString(scriptContext->GetLibrary()->GetStringTypeStatic())
{
this->SetBuffer(subString);
this->originalFullStringReference = originalFullStringReference;
this->SetLength(length);
...
}