JavascriptString.h 24 KB

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