JavascriptString.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #pragma once
  7. namespace Js
  8. {
  9. typedef struct
  10. {
  11. uint32 shift;
  12. } Boyer_Moore_Jump;
  13. // Boyer Moore table for only the first character in the search string.
  14. #if defined(_M_IX86) || defined(_M_IX64)
  15. // This table gets memset to 0. The x86 CRT is optimized for doing copies 128 bytes
  16. // at a time, for 16 byte aligned memory. If this table isn't 16 byte aligned, we pay
  17. // an additional cost to pre-align it, dealing with trailing bytes, and the copy
  18. // ends up being twice as slow.
  19. typedef Boyer_Moore_Jump __declspec(align(16)) JmpTable[0x80];
  20. #else
  21. typedef Boyer_Moore_Jump JmpTable[0x80];
  22. #endif
  23. struct PropertyCache;
  24. class SubString;
  25. class StringCopyInfoStack;
  26. bool IsValidCharCount(size_t charCount);
  27. const charcount_t k_InvalidCharCount = static_cast<charcount_t>(-1);
  28. class JavascriptString : public RecyclableObject
  29. {
  30. friend Lowerer;
  31. friend LowererMD;
  32. friend bool IsValidCharCount(size_t);
  33. JavascriptString() = delete;
  34. JavascriptString(JavascriptString&) = delete;
  35. private:
  36. Field(const char16*) m_pszValue; // Flattened, '\0' terminated contents
  37. Field(charcount_t) m_charLength; // Length in characters, not including '\0'.
  38. static const charcount_t MaxCharLength = INT_MAX - 1; // Max number of chars not including '\0'.
  39. protected:
  40. static const byte MaxCopyRecursionDepth = 3;
  41. public:
  42. BOOL HasItemAt(charcount_t idxChar);
  43. BOOL GetItemAt(charcount_t idxChar, Var* value);
  44. char16 GetItem(charcount_t index);
  45. virtual void GetPropertyRecord(_Out_ PropertyRecord const** propertyRecord, bool dontLookupFromDictionary = false);
  46. virtual void CachePropertyRecord(_In_ PropertyRecord const* propertyRecord);
  47. _Ret_range_(m_charLength, m_charLength) charcount_t GetLength() const;
  48. // Non-finalized strings haven't allocated buffers yet, but
  49. // it always makes sense to talk about string's size in bytes.
  50. charcount_t GetSizeInBytes() const { return GetLength() * sizeof(char16); };
  51. virtual size_t GetAllocatedByteCount() const;
  52. virtual bool IsSubstring() const;
  53. int GetLengthAsSignedInt() const;
  54. const char16* UnsafeGetBuffer() const;
  55. LPCWSTR GetSzCopy(ArenaAllocator* alloc); // Copy to an Arena
  56. const char16* GetString(); // Get string, may not be NULL terminated
  57. // NumberUtil::FIntRadStrToDbl and parts of GlobalObject::EntryParseInt were refactored into ToInteger
  58. Var ToInteger(int radix = 0);
  59. double ToDouble();
  60. bool ToDouble(double * result);
  61. static const char16* GetSzHelper(JavascriptString *str) { return str->GetSz(); }
  62. virtual const char16* GetSz(); // Get string, NULL terminated
  63. virtual void const * GetOriginalStringReference(); // Get the allocated object that owns the original full string buffer
  64. #if ENABLE_TTD
  65. //Get the associated property id for this string if there is one (e.g. it is a propertystring otherwise return Js::PropertyIds::_none)
  66. virtual Js::PropertyId TryGetAssociatedPropertyId() const { return Js::PropertyIds::_none; }
  67. #endif
  68. public:
  69. template <typename StringType>
  70. void Copy(__out_ecount(bufLen) char16 *const buffer, const charcount_t bufLen);
  71. void Copy(__out_xcount(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth)
  72. {
  73. if (this->IsFinalized())
  74. {
  75. // If we have the buffer already, just copy it
  76. const CharCount copyCharLength = this->GetLength();
  77. CopyHelper(buffer, this->GetString(), copyCharLength);
  78. }
  79. else
  80. {
  81. CopyVirtual(buffer, nestedStringTreeCopyInfos, recursionDepth);
  82. }
  83. }
  84. virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth);
  85. private:
  86. void FinishCopy(__inout_xcount(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos);
  87. public:
  88. virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const { return -1; }
  89. virtual bool IsTree() const { return false; }
  90. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags propertyOperationFlags) override;
  91. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags propertyOperationFlags) override;
  92. virtual PropertyQueryFlags HasItemQuery(uint32 index) override sealed;
  93. virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  94. virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  95. virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, EnumeratorCache * enumeratorCache = nullptr) override;
  96. virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info) override;
  97. virtual BOOL IsEnumerable(PropertyId propertyId) override;
  98. virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags propertyOperationFlags) override;
  99. virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags propertyOperationFlags) override;
  100. virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  101. virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  102. virtual PropertyQueryFlags GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  103. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  104. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  105. virtual RecyclableObject* ToObject(ScriptContext * requestContext) override;
  106. virtual Var GetTypeOfString(ScriptContext * requestContext) override;
  107. // should never be called, JavascriptConversion::ToPrimitive() short-circuits and returns input value
  108. virtual BOOL ToPrimitive(JavascriptHint hint, Var* value, ScriptContext * requestContext) override { AssertMsg(false, "String ToPrimitive should not be called"); *value = this; return true;}
  109. virtual RecyclableObject * CloneToScriptContext(ScriptContext* requestContext) override;
  110. virtual BOOL BufferEquals(__in_ecount(otherLength) LPCWSTR otherBuffer, __in charcount_t otherLength);
  111. char16* GetNormalizedString(PlatformAgnostic::UnicodeText::NormalizationForm, ArenaAllocator*, charcount_t&);
  112. static bool Equals(JavascriptString* aLeft, JavascriptString* aRight);
  113. static bool LessThan(Var aLeft, Var aRight);
  114. static bool IsNegZero(JavascriptString *string);
  115. static uint strstr(JavascriptString *string, JavascriptString *substring, bool useBoyerMoore, uint start=0);
  116. static int strcmp(JavascriptString *string1, JavascriptString *string2);
  117. private:
  118. char16* GetSzCopy(); // get a copy of the inner string without compacting the chunks
  119. template<bool toUpper, bool useInvariant>
  120. static JavascriptString* ToCaseCore(JavascriptString* pThis);
  121. static int IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, int searchLen, int position);
  122. static int LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, charcount_t searchLen, charcount_t position);
  123. static bool BuildLastCharForwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen);
  124. static bool BuildFirstCharBackwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen);
  125. static charcount_t ConvertToIndex(Var varIndex, ScriptContext *scriptContext);
  126. template <typename T, bool copyBuffer>
  127. static JavascriptString* NewWithBufferT(const char16 * content, charcount_t charLength, ScriptContext * scriptContext);
  128. bool GetPropertyBuiltIns(PropertyId propertyId, Var* value, ScriptContext* scriptContext);
  129. static const char stringToIntegerMap[128];
  130. static const uint8 maxUintStringLengthTable[37];
  131. protected:
  132. JavascriptString(StaticType * type);
  133. JavascriptString(StaticType * type, charcount_t charLength, const char16* szValue);
  134. DEFINE_VTABLE_CTOR_ABSTRACT(JavascriptString, RecyclableObject);
  135. void SetLength(charcount_t newLength);
  136. void SetBuffer(const char16* buffer);
  137. bool IsValidIndexValue(charcount_t idx) const;
  138. static charcount_t SafeSzSize(charcount_t length); // Throws on overflow
  139. charcount_t SafeSzSize() const; // Throws on overflow
  140. public:
  141. bool IsFinalized() const { return this->UnsafeGetBuffer() != NULL; }
  142. public:
  143. static JavascriptString* NewWithSz(__in_z const char16 * content, ScriptContext* scriptContext);
  144. static JavascriptString* NewWithBuffer(__in_ecount(charLength) const char16 * content, charcount_t charLength, ScriptContext * scriptContext);
  145. static JavascriptString* NewCopySz(__in_z const char16* content, ScriptContext* scriptContext);
  146. static JavascriptString* NewCopyBuffer(__in_ecount(charLength) const char16* content, charcount_t charLength, ScriptContext* scriptContext);
  147. static __ecount(length+1) char16* AllocateLeafAndCopySz(__in Recycler* recycler, __in_ecount(length) const char16* content, charcount_t length);
  148. static __ecount(length+1) char16* AllocateAndCopySz(__in ArenaAllocator* arena, __in_ecount(length) const char16* content, charcount_t length);
  149. static void CopyHelper(__out_ecount(countNeeded) char16 *dst, __in_ecount(countNeeded) const char16 * str, charcount_t countNeeded);
  150. public:
  151. JavascriptString* ConcatDestructive(JavascriptString* pstRight);
  152. private:
  153. JavascriptString* ConcatDestructive_Compound(JavascriptString* pstRight);
  154. JavascriptString* ConcatDestructive_ConcatToCompound(JavascriptString* pstRight);
  155. JavascriptString* ConcatDestructive_OneEmpty(JavascriptString* pstRight);
  156. JavascriptString* ConcatDestructive_CompoundAppendChars(JavascriptString* pstRight);
  157. public:
  158. static JavascriptString* Concat(JavascriptString * pstLeft, JavascriptString * pstRight);
  159. static JavascriptString* Concat3(JavascriptString * pstLeft, JavascriptString * pstCenter, JavascriptString * pstRight);
  160. private:
  161. static JavascriptString* Concat_Compound(JavascriptString * pstLeft, JavascriptString * pstRight);
  162. static JavascriptString* Concat_ConcatToCompound(JavascriptString * pstLeft, JavascriptString * pstRight);
  163. static JavascriptString* Concat_OneEmpty(JavascriptString * pstLeft, JavascriptString * pstRight);
  164. static JavascriptString* Concat_BothOneChar(JavascriptString * pstLeft, JavascriptString * pstRight);
  165. public:
  166. static uint32 GetOffsetOfpszValue()
  167. {
  168. return offsetof(JavascriptString, m_pszValue);
  169. }
  170. static uint32 GetOffsetOfcharLength()
  171. {
  172. return offsetof(JavascriptString, m_charLength);
  173. }
  174. class EntryInfo
  175. {
  176. public:
  177. static FunctionInfo NewInstance;
  178. static FunctionInfo At;
  179. static FunctionInfo CharAt;
  180. static FunctionInfo CharCodeAt;
  181. static FunctionInfo CodePointAt;
  182. static FunctionInfo Concat;
  183. static FunctionInfo FromCharCode;
  184. static FunctionInfo FromCodePoint;
  185. static FunctionInfo IndexOf;
  186. static FunctionInfo LastIndexOf;
  187. static FunctionInfo LocaleCompare;
  188. static FunctionInfo Match;
  189. static FunctionInfo Normalize;
  190. static FunctionInfo Raw;
  191. static FunctionInfo Replace;
  192. static FunctionInfo Search;
  193. static FunctionInfo Slice;
  194. static FunctionInfo Split;
  195. static FunctionInfo Substring;
  196. static FunctionInfo Substr;
  197. static FunctionInfo ToLocaleLowerCase;
  198. static FunctionInfo ToLocaleUpperCase;
  199. static FunctionInfo ToLowerCase;
  200. static FunctionInfo ToString;
  201. static FunctionInfo ToUpperCase;
  202. static FunctionInfo Trim;
  203. static FunctionInfo TrimLeft;
  204. static FunctionInfo TrimStart;
  205. static FunctionInfo TrimRight;
  206. static FunctionInfo TrimEnd;
  207. static FunctionInfo Repeat;
  208. static FunctionInfo StartsWith;
  209. static FunctionInfo EndsWith;
  210. static FunctionInfo Includes;
  211. static FunctionInfo PadStart;
  212. static FunctionInfo PadEnd;
  213. #ifdef TAGENTRY
  214. #undef TAGENTRY
  215. #endif
  216. #define TAGENTRY(name, ...) static FunctionInfo name;
  217. #include "JavascriptStringTagEntries.h"
  218. #undef TAGENTRY
  219. static FunctionInfo ValueOf;
  220. static FunctionInfo SymbolIterator;
  221. };
  222. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  223. static Var EntryAt(RecyclableObject* function, CallInfo callInfo, ...);
  224. static Var EntryCharAt(RecyclableObject* function, CallInfo callInfo, ...);
  225. static Var EntryCharCodeAt(RecyclableObject* function, CallInfo callInfo, ...);
  226. static Var EntryCodePointAt(RecyclableObject* function, CallInfo callInfo, ...);
  227. static Var EntryConcat(RecyclableObject* function, CallInfo callInfo, ...);
  228. static Var EntryFromCharCode(RecyclableObject* function, CallInfo callInfo, ...);
  229. static Var EntryFromCodePoint(RecyclableObject* function, CallInfo callInfo, ...);
  230. static Var EntryIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  231. static Var EntryLastIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  232. static Var EntryLocaleCompare(RecyclableObject* function, CallInfo callInfo, ...);
  233. static Var EntryMatch(RecyclableObject* function, CallInfo callInfo, ...);
  234. static Var EntryNormalize(RecyclableObject* function, CallInfo callInfo, ...);
  235. static Var EntryRaw(RecyclableObject* function, CallInfo callInfo, ...);
  236. static Var EntryReplace(RecyclableObject* function, CallInfo callInfo, ...);
  237. static Var EntrySearch(RecyclableObject* function, CallInfo callInfo, ...);
  238. static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
  239. static Var EntrySplit(RecyclableObject* function, CallInfo callInfo, ...);
  240. static Var EntrySubstring(RecyclableObject* function, CallInfo callInfo, ...);
  241. static Var EntrySubstr(RecyclableObject* function, CallInfo callInfo, ...);
  242. static Var EntryToLocaleLowerCase(RecyclableObject* function, CallInfo callInfo, ...);
  243. static Var EntryToLocaleUpperCase(RecyclableObject* function, CallInfo callInfo, ...);
  244. static Var EntryToLowerCase(RecyclableObject* function, CallInfo callInfo, ...);
  245. static Var EntryToString(RecyclableObject* function, CallInfo callInfo, ...);
  246. static Var EntryToUpperCase(RecyclableObject* function, CallInfo callInfo, ...);
  247. static Var EntryTrim(RecyclableObject* function, CallInfo callInfo, ...);
  248. static Var EntryTrimStart(RecyclableObject* function, CallInfo callInfo, ...);
  249. static Var EntryTrimEnd(RecyclableObject* function, CallInfo callInfo, ...);
  250. static Var EntryRepeat(RecyclableObject* function, CallInfo callInfo, ...);
  251. static Var EntryStartsWith(RecyclableObject* function, CallInfo callInfo, ...);
  252. static Var EntryEndsWith(RecyclableObject* function, CallInfo callInfo, ...);
  253. static Var EntryIncludes(RecyclableObject* function, CallInfo callInfo, ...);
  254. static Var EntryAnchor(RecyclableObject* function, CallInfo callInfo, ...);
  255. static Var EntryBig(RecyclableObject* function, CallInfo callInfo, ...);
  256. static Var EntryBlink(RecyclableObject* function, CallInfo callInfo, ...);
  257. static Var EntryBold(RecyclableObject* function, CallInfo callInfo, ...);
  258. static Var EntryFixed(RecyclableObject* function, CallInfo callInfo, ...);
  259. static Var EntryFontColor(RecyclableObject* function, CallInfo callInfo, ...);
  260. static Var EntryFontSize(RecyclableObject* function, CallInfo callInfo, ...);
  261. static Var EntryItalics(RecyclableObject* function, CallInfo callInfo, ...);
  262. static Var EntryLink(RecyclableObject* function, CallInfo callInfo, ...);
  263. static Var EntrySmall(RecyclableObject* function, CallInfo callInfo, ...);
  264. static Var EntryStrike(RecyclableObject* function, CallInfo callInfo, ...);
  265. static Var EntrySub(RecyclableObject* function, CallInfo callInfo, ...);
  266. static Var EntrySup(RecyclableObject* function, CallInfo callInfo, ...);
  267. static Var EntryValueOf(RecyclableObject* function, CallInfo callInfo, ...);
  268. static Var EntrySymbolIterator(RecyclableObject* function, CallInfo callInfo, ...);
  269. static Var EntryPadStart(RecyclableObject* function, CallInfo callInfo, ...);
  270. static Var EntryPadEnd(RecyclableObject* function, CallInfo callInfo, ...);
  271. static JavascriptString* RepeatCore(JavascriptString* currentString, charcount_t count, ScriptContext* scriptContext);
  272. static JavascriptString* PadCore(ArgumentReader& args, JavascriptString *mainString, bool isPadStart, ScriptContext* scriptContext);
  273. static Var SubstringCore(JavascriptString* str, int start, int span, ScriptContext* scriptContext);
  274. static charcount_t GetBufferLength(const char16 *content);
  275. static charcount_t GetBufferLength(const char16 *content, int charLengthOrMinusOne);
  276. static bool IsASCII7BitChar(char16 ch) { return ch < 0x0080; }
  277. static char ToASCII7BitChar(char16 ch) { Assert(IsASCII7BitChar(ch)); return static_cast<char>(ch); }
  278. private:
  279. static int IndexOf(ArgumentReader& args, ScriptContext* scriptContext, const char16* apiNameForErrorMsg, bool isRegExpAnAllowedArg);
  280. static void GetThisStringArgument(ArgumentReader& args, ScriptContext* scriptContext, const char16* apiNameForErrorMsg, JavascriptString** ppThis);
  281. static void GetThisAndSearchStringArguments(ArgumentReader& args, ScriptContext* scriptContext, const char16* apiNameForErrorMsg, JavascriptString** ppThis, JavascriptString** ppSearch, bool isRegExpAnAllowedArg);
  282. static BOOL GetThisValueVar(Var aValue, JavascriptString** pString, ScriptContext* scriptContext);
  283. static Var StringBracketHelper(Arguments args, ScriptContext *scriptContext, __in_ecount(cchTag) char16 const*pszTag, charcount_t cchTag,
  284. __in_ecount_opt(cchProp) char16 const*pszProp, charcount_t cchProp);
  285. template< size_t N >
  286. static Var StringBracketHelper(Arguments args, ScriptContext *scriptContext, const char16 (&tag)[N]);
  287. template< size_t N1, size_t N2 >
  288. static Var StringBracketHelper(Arguments args, ScriptContext *scriptContext, const char16 (&tag)[N1], const char16 (&prop)[N2]);
  289. static void SearchValueHelper(ScriptContext* scriptContext, Var aValue, JavascriptRegExp ** ppSearchRegEx, JavascriptString ** ppSearchString);
  290. static void ReplaceValueHelper(ScriptContext* scriptContext, Var aValue, RecyclableObject** ppReplaceFn, JavascriptString ** ppReplaceString);
  291. template<bool toUpper>
  292. static JavascriptString* ToLocaleCaseHelper(JavascriptString* thisObj);
  293. static void InstantiateForceInlinedMembers();
  294. template <bool trimLeft, bool trimRight>
  295. static Var TrimLeftRightHelper(JavascriptString* arg, ScriptContext* scriptContext);
  296. static Var DoStringReplace(Arguments& args, CallInfo& callInfo, JavascriptString* input, ScriptContext* scriptContext);
  297. static Var DoStringSplit(Arguments& args, CallInfo& callInfo, JavascriptString* input, ScriptContext* scriptContext);
  298. template<int argCount, typename FallbackFn>
  299. static Var DelegateToRegExSymbolFunction(ArgumentReader &args, PropertyId symbolPropertyId, FallbackFn fallback, PCWSTR varName, ScriptContext* scriptContext);
  300. static Var GetRegExSymbolFunction(Var regExp, PropertyId propertyId, ScriptContext* scriptContext);
  301. template<int argCount> // The count is excluding 'this'
  302. static Var CallRegExSymbolFunction(Var fn, Var regExp, Arguments& args, PCWSTR const varName, ScriptContext* scriptContext);
  303. template<int argCount> // The count is excluding 'this'
  304. static Var CallRegExFunction(RecyclableObject* fnObj, Var regExp, Arguments& args, ScriptContext *scriptContext);
  305. };
  306. template <> bool VarIsImpl<JavascriptString>(RecyclableObject* obj);
  307. template<>
  308. struct PropertyRecordStringHashComparer<JavascriptString *>
  309. {
  310. inline static bool Equals(JavascriptString * str1, JavascriptString * str2)
  311. {
  312. // We want to pin the strings str1 and str2 because flattening of any of these strings could cause a GC and result in the other string getting collected if it was optimized
  313. // away by the compiler. We would normally have called the EnterPinnedScope/LeavePinnedScope methods here but it adds extra call instructions to the assembly code. As Equals
  314. // methods could get called a lot of times this can show up as regressions in benchmarks.
  315. volatile Js::JavascriptString** keepAliveString1 = (volatile Js::JavascriptString**)& str1;
  316. volatile Js::JavascriptString** keepAliveString2 = (volatile Js::JavascriptString**)& str2;
  317. auto keepAliveLambda = [&]() {
  318. UNREFERENCED_PARAMETER(keepAliveString1);
  319. UNREFERENCED_PARAMETER(keepAliveString2);
  320. };
  321. return (str1->GetLength() == str2->GetLength() &&
  322. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2->GetString(), str1->GetLength()));
  323. }
  324. inline static bool Equals(JavascriptString * str1, JsUtil::CharacterBuffer<WCHAR> const & str2)
  325. {
  326. return (str1->GetLength() == str2.GetLength() &&
  327. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2.GetBuffer(), str1->GetLength()));
  328. }
  329. inline static bool Equals(JavascriptString * str1, PropertyRecord const * str2)
  330. {
  331. return (str1->GetLength() == str2->GetLength() && !Js::IsInternalPropertyId(str2->GetPropertyId()) &&
  332. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2->GetBuffer(), str1->GetLength()));
  333. }
  334. inline static hash_t GetHashCode(JavascriptString * str)
  335. {
  336. return JsUtil::CharacterBuffer<WCHAR>::StaticGetHashCode(str->GetString(), str->GetLength());
  337. }
  338. };
  339. inline bool PropertyRecordStringHashComparer<PropertyRecord const *>::Equals(PropertyRecord const * str1, JavascriptString * str2)
  340. {
  341. return (str1->GetLength() == str2->GetLength() && !Js::IsInternalPropertyId(str1->GetPropertyId()) &&
  342. JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetBuffer(), str2->GetString(), str1->GetLength()));
  343. }
  344. template <typename T>
  345. class JavascriptStringHelpers
  346. {
  347. public:
  348. static bool Equals(T* aLeft, T* aRight);
  349. };
  350. }
  351. template <>
  352. struct DefaultComparer<Js::JavascriptString*>
  353. {
  354. inline static bool Equals(Js::JavascriptString * x, Js::JavascriptString * y)
  355. {
  356. return Js::JavascriptString::Equals(x, y);
  357. }
  358. inline static hash_t GetHashCode(Js::JavascriptString * pStr)
  359. {
  360. return JsUtil::CharacterBuffer<char16>::StaticGetHashCode(pStr->GetString(), pStr->GetLength());
  361. }
  362. };