JavascriptString.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. typedef struct
  9. {
  10. unsigned long shift;
  11. } Boyer_Moore_Jump;
  12. // Boyer Moore table for only the first character in the search string.
  13. #if defined(_M_IX86) || defined(_M_IX64)
  14. // This table gets memset to 0. The x86 CRT is optimized for doing copies 128 bytes
  15. // at a time, for 16 byte aligned memory. If this table isn't 16 byte aligned, we pay
  16. // an additional cost to pre-align it, dealing with trailing bytes, and the copy
  17. // ends up being twice as slow.
  18. typedef Boyer_Moore_Jump __declspec(align(16)) JmpTable[0x80];
  19. #else
  20. typedef Boyer_Moore_Jump JmpTable[0x80];
  21. #endif
  22. struct PropertyCache;
  23. class SubString;
  24. class StringCopyInfoStack;
  25. bool IsValidCharCount(size_t charCount);
  26. const charcount_t k_InvalidCharCount = static_cast<charcount_t>(-1);
  27. //
  28. // To inspect strings in hybrid debugging, we use vtable lookup to find out concrete string type
  29. // then inspect string content accordingly.
  30. //
  31. // To ensure all known string vtables are listed and exported from chakra.dll and handler class
  32. // exists in chakradiag.dll, declare an abstract method in base JavascriptString class. Any concrete
  33. // subclass that has runtime string instance must DECLARE_CONCRETE_STRING_CLASS, otherwise
  34. // we'll get a compile time error.
  35. //
  36. #if DBG && defined(NTBUILD)
  37. #define DECLARE_CONCRETE_STRING_CLASS_BASE virtual void _declareConcreteStringClass() = 0
  38. #define DECLARE_CONCRETE_STRING_CLASS virtual void _declareConcreteStringClass() override
  39. #else
  40. #define DECLARE_CONCRETE_STRING_CLASS_BASE
  41. #define DECLARE_CONCRETE_STRING_CLASS
  42. #endif
  43. class JavascriptString abstract : public RecyclableObject
  44. {
  45. friend Lowerer;
  46. friend LowererMD;
  47. friend bool IsValidCharCount(size_t);
  48. private:
  49. const wchar_t* m_pszValue; // Flattened, '\0' terminated contents
  50. charcount_t m_charLength; // Length in characters, not including '\0'.
  51. static const charcount_t MaxCharLength = INT_MAX - 1; // Max number of chars not including '\0'.
  52. protected:
  53. static const byte MaxCopyRecursionDepth = 3;
  54. public:
  55. BOOL HasItemAt(charcount_t idxChar);
  56. BOOL GetItemAt(charcount_t idxChar, Var* value);
  57. wchar_t GetItem(charcount_t index);
  58. _Ret_range_(m_charLength, m_charLength) charcount_t GetLength() const;
  59. virtual size_t GetAllocatedByteCount() const;
  60. virtual bool IsSubstring() const;
  61. int GetLengthAsSignedInt() const;
  62. const wchar_t* UnsafeGetBuffer() const;
  63. LPCWSTR GetSzCopy(ArenaAllocator* alloc); // Copy to an Arena
  64. const wchar_t* GetString(); // Get string, may not be NULL terminated
  65. // NumberUtil::FIntRadStrToDbl and parts of GlobalObject::EntryParseInt were refactored into ToInteger
  66. Var ToInteger(int radix = 0);
  67. double ToDouble();
  68. bool ToDouble(double * result);
  69. static const wchar_t* GetSzHelper(JavascriptString *str) { return str->GetSz(); }
  70. virtual const wchar_t* GetSz(); // Get string, NULL terminated
  71. virtual void const * GetOriginalStringReference(); // Get the original full string (Same as GetString() unless it is a SubString);
  72. public:
  73. template <typename StringType>
  74. void Copy(__out_ecount(bufLen) wchar_t *const buffer, const charcount_t bufLen);
  75. void Copy(__out_xcount(m_charLength) wchar_t *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth)
  76. {
  77. if (this->IsFinalized())
  78. {
  79. // If we have the buffer already, just copy it
  80. const CharCount copyCharLength = this->GetLength();
  81. CopyHelper(buffer, this->GetString(), copyCharLength);
  82. }
  83. else
  84. {
  85. CopyVirtual(buffer, nestedStringTreeCopyInfos, recursionDepth);
  86. }
  87. }
  88. virtual void CopyVirtual(_Out_writes_(m_charLength) wchar_t *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth);
  89. private:
  90. void FinishCopy(__inout_xcount(m_charLength) wchar_t *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos);
  91. public:
  92. virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const { return -1; }
  93. virtual bool IsTree() const { return false; }
  94. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags propertyOperationFlags) override;
  95. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags propertyOperationFlags) override;
  96. virtual BOOL HasItem(uint32 index) override sealed;
  97. virtual BOOL GetItem(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  98. virtual BOOL GetItemReference(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  99. virtual BOOL GetEnumerator(BOOL enumNonEnumerable, Var* enumerator, ScriptContext * requestContext, bool preferSnapshotSemantics = true, bool enumSymbols = false) override;
  100. virtual BOOL HasProperty(PropertyId propertyId) override;
  101. virtual BOOL IsEnumerable(PropertyId propertyId) override;
  102. virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags propertyOperationFlags) override;
  103. virtual BOOL GetProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  104. virtual BOOL GetProperty(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  105. virtual BOOL GetPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  106. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  107. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  108. virtual RecyclableObject* ToObject(ScriptContext * requestContext) override;
  109. virtual Var GetTypeOfString(ScriptContext * requestContext) override;
  110. // should never be called, JavascriptConversion::ToPrimitive() short-circuits and returns input value
  111. virtual BOOL ToPrimitive(JavascriptHint hint, Var* value, ScriptContext * requestContext) override { AssertMsg(false, "String ToPrimitive should not be called"); *value = this; return true;}
  112. virtual RecyclableObject * CloneToScriptContext(ScriptContext* requestContext) override;
  113. virtual BOOL BufferEquals(__in_ecount(otherLength) LPCWSTR otherBuffer, __in charcount_t otherLength);
  114. virtual wchar_t* GetNormalizedString(NORM_FORM, ArenaAllocator*, charcount_t&);
  115. static bool Is(Var aValue);
  116. static JavascriptString* FromVar(Var aValue);
  117. static bool Equals(Var aLeft, Var aRight);
  118. static bool LessThan(Var aLeft, Var aRight);
  119. static bool IsNegZero(JavascriptString *string);
  120. static uint strstr(JavascriptString *string, JavascriptString *substring, bool useBoyerMoore, uint start=0);
  121. static int strcmp(JavascriptString *string1, JavascriptString *string2);
  122. private:
  123. enum ToCase{
  124. ToLower,
  125. ToUpper
  126. };
  127. wchar_t* GetSzCopy(); // get a copy of the inner string without compacting the chunks
  128. static Var ToCaseCore(JavascriptString* pThis, ToCase toCase);
  129. static int IndexOfUsingJmpTable(JmpTable jmpTable, const wchar_t* inputStr, int len, const wchar_t* searchStr, int searchLen, int position);
  130. static int LastIndexOfUsingJmpTable(JmpTable jmpTable, const wchar_t* inputStr, int len, const wchar_t* searchStr, int searchLen, int position);
  131. static bool BuildLastCharForwardBoyerMooreTable(JmpTable jmpTable, const wchar_t* searchStr, int searchLen);
  132. static bool BuildFirstCharBackwardBoyerMooreTable(JmpTable jmpTable, const wchar_t* searchStr, int searchLen);
  133. static charcount_t ConvertToIndex(Var varIndex, ScriptContext *scriptContext);
  134. template <typename T, bool copyBuffer>
  135. static JavascriptString* NewWithBufferT(const wchar_t * content, charcount_t charLength, ScriptContext * scriptContext);
  136. bool GetPropertyBuiltIns(PropertyId propertyId, Var* value, ScriptContext* scriptContext);
  137. static const char stringToIntegerMap[128];
  138. static const uint8 maxUintStringLengthTable[37];
  139. protected:
  140. JavascriptString(StaticType * type);
  141. JavascriptString(StaticType * type, charcount_t charLength, const wchar_t* szValue);
  142. DEFINE_VTABLE_CTOR_ABSTRACT(JavascriptString, RecyclableObject);
  143. DECLARE_CONCRETE_STRING_CLASS_BASE;
  144. void SetLength(charcount_t newLength);
  145. void SetBuffer(const wchar_t* buffer);
  146. bool IsValidIndexValue(charcount_t idx) const;
  147. static charcount_t SafeSzSize(charcount_t length); // Throws on overflow
  148. charcount_t SafeSzSize() const; // Throws on overflow
  149. public:
  150. bool IsFinalized() const { return this->UnsafeGetBuffer() != NULL; }
  151. public:
  152. static JavascriptString* NewWithSz(__in_z const wchar_t * content, ScriptContext* scriptContext);
  153. static JavascriptString* NewWithBuffer(__in_ecount(charLength) const wchar_t * content, charcount_t charLength, ScriptContext * scriptContext);
  154. static JavascriptString* NewCopySz(__in_z const wchar_t* content, ScriptContext* scriptContext);
  155. static JavascriptString* NewCopyBuffer(__in_ecount(charLength) const wchar_t* content, charcount_t charLength, ScriptContext* scriptContext);
  156. static JavascriptString* NewWithArenaSz(__in_z const wchar_t * content, ScriptContext* scriptContext);
  157. static JavascriptString* NewWithArenaBuffer(__in_ecount(charLength) const wchar_t * content, charcount_t charLength, ScriptContext * scriptContext);
  158. static JavascriptString* NewCopySzFromArena(__in_z const wchar_t* content, ScriptContext* scriptContext, ArenaAllocator *arena);
  159. static __ecount(length+1) wchar_t* AllocateLeafAndCopySz(__in Recycler* recycler, __in_ecount(length) const wchar_t* content, charcount_t length);
  160. static __ecount(length+1) wchar_t* AllocateAndCopySz(__in ArenaAllocator* arena, __in_ecount(length) const wchar_t* content, charcount_t length);
  161. static void CopyHelper(__out_ecount(countNeeded) wchar_t *dst, __in_ecount(countNeeded) const wchar_t * str, charcount_t countNeeded);
  162. public:
  163. JavascriptString* ConcatDestructive(JavascriptString* pstRight);
  164. private:
  165. JavascriptString* ConcatDestructive_Compound(JavascriptString* pstRight);
  166. JavascriptString* ConcatDestructive_ConcatToCompound(JavascriptString* pstRight);
  167. JavascriptString* ConcatDestructive_OneEmpty(JavascriptString* pstRight);
  168. JavascriptString* ConcatDestructive_CompoundAppendChars(JavascriptString* pstRight);
  169. public:
  170. static JavascriptString* Concat(JavascriptString * pstLeft, JavascriptString * pstRight);
  171. static JavascriptString* Concat3(JavascriptString * pstLeft, JavascriptString * pstCenter, JavascriptString * pstRight);
  172. private:
  173. static JavascriptString* Concat_Compound(JavascriptString * pstLeft, JavascriptString * pstRight);
  174. static JavascriptString* Concat_ConcatToCompound(JavascriptString * pstLeft, JavascriptString * pstRight);
  175. static JavascriptString* Concat_OneEmpty(JavascriptString * pstLeft, JavascriptString * pstRight);
  176. static JavascriptString* Concat_BothOneChar(JavascriptString * pstLeft, JavascriptString * pstRight);
  177. public:
  178. static uint32 GetOffsetOfpszValue()
  179. {
  180. return offsetof(JavascriptString, m_pszValue);
  181. }
  182. static uint32 GetOffsetOfcharLength()
  183. {
  184. return offsetof(JavascriptString, m_charLength);
  185. }
  186. class EntryInfo
  187. {
  188. public:
  189. static FunctionInfo NewInstance;
  190. static FunctionInfo CharAt;
  191. static FunctionInfo CharCodeAt;
  192. static FunctionInfo CodePointAt;
  193. static FunctionInfo Concat;
  194. static FunctionInfo FromCharCode;
  195. static FunctionInfo FromCodePoint;
  196. static FunctionInfo IndexOf;
  197. static FunctionInfo LastIndexOf;
  198. static FunctionInfo LocaleCompare;
  199. static FunctionInfo Match;
  200. static FunctionInfo Normalize;
  201. static FunctionInfo Raw;
  202. static FunctionInfo Replace;
  203. static FunctionInfo Search;
  204. static FunctionInfo Slice;
  205. static FunctionInfo Split;
  206. static FunctionInfo Substring;
  207. static FunctionInfo Substr;
  208. static FunctionInfo ToLocaleLowerCase;
  209. static FunctionInfo ToLocaleUpperCase;
  210. static FunctionInfo ToLowerCase;
  211. static FunctionInfo ToString;
  212. static FunctionInfo ToUpperCase;
  213. static FunctionInfo Trim;
  214. static FunctionInfo TrimLeft;
  215. static FunctionInfo TrimRight;
  216. static FunctionInfo Repeat;
  217. static FunctionInfo StartsWith;
  218. static FunctionInfo EndsWith;
  219. static FunctionInfo Includes;
  220. #ifdef TAGENTRY
  221. #undef TAGENTRY
  222. #endif
  223. #define TAGENTRY(name, ...) static FunctionInfo name;
  224. #include "JavascriptStringTagEntries.h"
  225. #undef TAGENTRY
  226. static FunctionInfo ValueOf;
  227. static FunctionInfo SymbolIterator;
  228. };
  229. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  230. static Var EntryCharAt(RecyclableObject* function, CallInfo callInfo, ...);
  231. static Var EntryCharCodeAt(RecyclableObject* function, CallInfo callInfo, ...);
  232. static Var EntryCodePointAt(RecyclableObject* function, CallInfo callInfo, ...);
  233. static Var EntryConcat(RecyclableObject* function, CallInfo callInfo, ...);
  234. static Var EntryFromCharCode(RecyclableObject* function, CallInfo callInfo, ...);
  235. static Var EntryFromCodePoint(RecyclableObject* function, CallInfo callInfo, ...);
  236. static Var EntryIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  237. static Var EntryLastIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  238. static Var EntryLocaleCompare(RecyclableObject* function, CallInfo callInfo, ...);
  239. static Var EntryMatch(RecyclableObject* function, CallInfo callInfo, ...);
  240. static Var EntryNormalize(RecyclableObject* function, CallInfo callInfo, ...);
  241. static Var EntryRaw(RecyclableObject* function, CallInfo callInfo, ...);
  242. static Var EntryReplace(RecyclableObject* function, CallInfo callInfo, ...);
  243. static Var EntrySearch(RecyclableObject* function, CallInfo callInfo, ...);
  244. static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
  245. static Var EntrySplit(RecyclableObject* function, CallInfo callInfo, ...);
  246. static Var EntrySubstring(RecyclableObject* function, CallInfo callInfo, ...);
  247. static Var EntrySubstr(RecyclableObject* function, CallInfo callInfo, ...);
  248. static Var EntryToLocaleLowerCase(RecyclableObject* function, CallInfo callInfo, ...);
  249. static Var EntryToLocaleUpperCase(RecyclableObject* function, CallInfo callInfo, ...);
  250. static Var EntryToLowerCase(RecyclableObject* function, CallInfo callInfo, ...);
  251. static Var EntryToString(RecyclableObject* function, CallInfo callInfo, ...);
  252. static Var EntryToUpperCase(RecyclableObject* function, CallInfo callInfo, ...);
  253. static Var EntryTrim(RecyclableObject* function, CallInfo callInfo, ...);
  254. static Var EntryTrimLeft(RecyclableObject* function, CallInfo callInfo, ...);
  255. static Var EntryTrimRight(RecyclableObject* function, CallInfo callInfo, ...);
  256. static Var EntryRepeat(RecyclableObject* function, CallInfo callInfo, ...);
  257. static Var EntryStartsWith(RecyclableObject* function, CallInfo callInfo, ...);
  258. static Var EntryEndsWith(RecyclableObject* function, CallInfo callInfo, ...);
  259. static Var EntryIncludes(RecyclableObject* function, CallInfo callInfo, ...);
  260. static Var EntryAnchor(RecyclableObject* function, CallInfo callInfo, ...);
  261. static Var EntryBig(RecyclableObject* function, CallInfo callInfo, ...);
  262. static Var EntryBlink(RecyclableObject* function, CallInfo callInfo, ...);
  263. static Var EntryBold(RecyclableObject* function, CallInfo callInfo, ...);
  264. static Var EntryFixed(RecyclableObject* function, CallInfo callInfo, ...);
  265. static Var EntryFontColor(RecyclableObject* function, CallInfo callInfo, ...);
  266. static Var EntryFontSize(RecyclableObject* function, CallInfo callInfo, ...);
  267. static Var EntryItalics(RecyclableObject* function, CallInfo callInfo, ...);
  268. static Var EntryLink(RecyclableObject* function, CallInfo callInfo, ...);
  269. static Var EntrySmall(RecyclableObject* function, CallInfo callInfo, ...);
  270. static Var EntryStrike(RecyclableObject* function, CallInfo callInfo, ...);
  271. static Var EntrySub(RecyclableObject* function, CallInfo callInfo, ...);
  272. static Var EntrySup(RecyclableObject* function, CallInfo callInfo, ...);
  273. static Var EntryValueOf(RecyclableObject* function, CallInfo callInfo, ...);
  274. static Var EntrySymbolIterator(RecyclableObject* function, CallInfo callInfo, ...);
  275. static Var SubstringCore(JavascriptString* str, int start, int span, ScriptContext* scriptContext);
  276. static charcount_t GetBufferLength(const wchar_t *content);
  277. static charcount_t GetBufferLength(const wchar_t *content, int charLengthOrMinusOne);
  278. static bool IsASCII7BitChar(wchar_t ch) { return ch < 0x0080; }
  279. static char ToASCII7BitChar(wchar_t ch) { Assert(IsASCII7BitChar(ch)); return static_cast<char>(ch); }
  280. private:
  281. static int IndexOf(ArgumentReader& args, ScriptContext* scriptContext, const wchar_t* apiNameForErrorMsg, bool isRegExpAnAllowedArg);
  282. static void GetThisStringArgument(ArgumentReader& args, ScriptContext* scriptContext, const wchar_t* apiNameForErrorMsg, JavascriptString** ppThis);
  283. static void GetThisAndSearchStringArguments(ArgumentReader& args, ScriptContext* scriptContext, const wchar_t* apiNameForErrorMsg, JavascriptString** ppThis, JavascriptString** ppSearch, bool isRegExpAnAllowedArg);
  284. static BOOL GetThisValueVar(Var aValue, JavascriptString** pString, ScriptContext* scriptContext);
  285. static Var StringBracketHelper(Arguments args, ScriptContext *scriptContext, __in_ecount(cchTag) wchar_t const*pszTag, charcount_t cchTag,
  286. __in_ecount_opt(cchProp) wchar_t const*pszProp, charcount_t cchProp);
  287. template< size_t N >
  288. static Var StringBracketHelper(Arguments args, ScriptContext *scriptContext, const wchar_t (&tag)[N]);
  289. template< size_t N1, size_t N2 >
  290. static Var StringBracketHelper(Arguments args, ScriptContext *scriptContext, const wchar_t (&tag)[N1], const wchar_t (&prop)[N2]);
  291. static void SearchValueHelper(ScriptContext* scriptContext, Var aValue, JavascriptRegExp ** ppSearchRegEx, JavascriptString ** ppSearchString);
  292. static void ReplaceValueHelper(ScriptContext* scriptContext, Var aValue, JavascriptFunction ** ppReplaceFn, JavascriptString ** ppReplaceString);
  293. static Var ToLocaleCaseHelper(Var thisObj, bool toUpper, ScriptContext *scriptContext);
  294. static void InstantiateForceInlinedMembers();
  295. template <bool trimLeft, bool trimRight>
  296. static Var TrimLeftRightHelper(JavascriptString* arg, ScriptContext* scriptContext);
  297. };
  298. template<>
  299. struct PropertyRecordStringHashComparer<JavascriptString *>
  300. {
  301. __inline static bool Equals(JavascriptString * str1, JavascriptString * str2)
  302. {
  303. return (str1->GetLength() == str2->GetLength() &&
  304. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2->GetString(), str1->GetLength()));
  305. }
  306. __inline static bool Equals(JavascriptString * str1, JsUtil::CharacterBuffer<WCHAR> const & str2)
  307. {
  308. return (str1->GetLength() == str2.GetLength() &&
  309. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2.GetBuffer(), str1->GetLength()));
  310. }
  311. __inline static bool Equals(JavascriptString * str1, PropertyRecord const * str2)
  312. {
  313. return (str1->GetLength() == str2->GetLength() && !Js::IsInternalPropertyId(str2->GetPropertyId()) &&
  314. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2->GetBuffer(), str1->GetLength()));
  315. }
  316. __inline static uint GetHashCode(JavascriptString * str)
  317. {
  318. return JsUtil::CharacterBuffer<WCHAR>::StaticGetHashCode(str->GetString(), str->GetLength());
  319. }
  320. };
  321. __inline bool PropertyRecordStringHashComparer<PropertyRecord const *>::Equals(PropertyRecord const * str1, JavascriptString * str2)
  322. {
  323. return (str1->GetLength() == str2->GetLength() && !Js::IsInternalPropertyId(str1->GetPropertyId()) &&
  324. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetBuffer(), str2->GetString(), str1->GetLength()));
  325. }
  326. }
  327. template <>
  328. struct DefaultComparer<Js::JavascriptString*>
  329. {
  330. __inline static bool Equals(Js::JavascriptString * x, Js::JavascriptString * y)
  331. {
  332. return Js::JavascriptString::Equals(x, y);
  333. }
  334. __inline static uint GetHashCode(Js::JavascriptString * pStr)
  335. {
  336. return JsUtil::CharacterBuffer<wchar_t>::StaticGetHashCode(pStr->GetString(), pStr->GetLength());
  337. }
  338. };