summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/Identifier.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/Identifier.h')
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.h490
1 files changed, 225 insertions, 265 deletions
diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h
index 4fb1a2ffa..6733ec5f2 100644
--- a/Source/JavaScriptCore/runtime/Identifier.h
+++ b/Source/JavaScriptCore/runtime/Identifier.h
@@ -22,288 +22,248 @@
#define Identifier_h
#include "VM.h"
-#include <wtf/Optional.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/WTFThreadData.h>
#include <wtf/text/CString.h>
-#include <wtf/text/UniquedStringImpl.h>
#include <wtf/text/WTFString.h>
namespace JSC {
-class ExecState;
-
-ALWAYS_INLINE bool isIndex(uint32_t index)
-{
- return index != 0xFFFFFFFFU;
-}
-
-template <typename CharType>
-ALWAYS_INLINE Optional<uint32_t> parseIndex(const CharType* characters, unsigned length)
-{
- // An empty string is not a number.
- if (!length)
- return Nullopt;
-
- // Get the first character, turning it into a digit.
- uint32_t value = characters[0] - '0';
- if (value > 9)
- return Nullopt;
-
- // Check for leading zeros. If the first characher is 0, then the
- // length of the string must be one - e.g. "042" is not equal to "42".
- if (!value && length > 1)
- return Nullopt;
-
- while (--length) {
- // Multiply value by 10, checking for overflow out of 32 bits.
- if (value > 0xFFFFFFFFU / 10)
- return Nullopt;
- value *= 10;
-
- // Get the next character, turning it into a digit.
- uint32_t newValue = *(++characters) - '0';
- if (newValue > 9)
- return Nullopt;
-
- // Add in the old value, checking for overflow out of 32 bits.
- newValue += value;
- if (newValue < value)
- return Nullopt;
- value = newValue;
+ class ExecState;
+
+ class Identifier {
+ friend class Structure;
+ public:
+ Identifier() { }
+ enum EmptyIdentifierFlag { EmptyIdentifier };
+ Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { }
+
+ // Only to be used with string literals.
+ template<unsigned charactersCount>
+ Identifier(ExecState* exec, const char (&characters)[charactersCount]) : m_string(add(exec, characters)) { }
+ template<unsigned charactersCount>
+ Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { }
+
+ Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { }
+ Identifier(ExecState* exec, const String& s) : m_string(add(exec, s.impl())) { }
+
+ Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { }
+ Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { }
+ Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { }
+ Identifier(VM* vm, const String& s) : m_string(add(vm, s.impl())) { }
+
+ const String& string() const { return m_string; }
+ StringImpl* impl() const { return m_string.impl(); }
+
+ const UChar* deprecatedCharacters() const { return m_string.deprecatedCharacters(); }
+ int length() const { return m_string.length(); }
+
+ CString ascii() const { return m_string.ascii(); }
+ CString utf8() const { return m_string.utf8(); }
+
+ static Identifier from(const PrivateName& name)
+ {
+ Identifier result;
+ result.m_string = name.uid();
+ return result;
+ }
+
+ static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
+
+ JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, unsigned y);
+ JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, int y);
+ static Identifier from(ExecState* exec, double y);
+ static Identifier from(VM*, unsigned y);
+ static Identifier from(VM*, int y);
+ static Identifier from(VM*, double y);
+
+ bool isNull() const { return m_string.isNull(); }
+ bool isEmpty() const { return m_string.isEmpty(); }
+
+ friend bool operator==(const Identifier&, const Identifier&);
+ friend bool operator!=(const Identifier&, const Identifier&);
+
+ friend bool operator==(const Identifier&, const LChar*);
+ friend bool operator==(const Identifier&, const char*);
+ friend bool operator!=(const Identifier&, const LChar*);
+ friend bool operator!=(const Identifier&, const char*);
+
+ static bool equal(const StringImpl*, const LChar*);
+ static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
+ static bool equal(const StringImpl*, const LChar*, unsigned length);
+ static bool equal(const StringImpl*, const UChar*, unsigned length);
+ static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
+
+ // Only to be used with string literals.
+ static PassRefPtr<StringImpl> add(VM*, const char*);
+ JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(ExecState*, const char*);
+
+ private:
+ String m_string;
+
+ template <typename CharType>
+ ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
+
+ static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
+ static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
+
+ template <typename T> static PassRefPtr<StringImpl> add(VM*, const T*, int length);
+ static PassRefPtr<StringImpl> add8(VM*, const UChar*, int length);
+ template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
+
+ static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r)
+ {
+#ifndef NDEBUG
+ checkCurrentIdentifierTable(exec);
+#endif
+ if (r->isIdentifier())
+ return r;
+ return addSlowCase(exec, r);
+ }
+ static PassRefPtr<StringImpl> add(VM* vm, StringImpl* r)
+ {
+#ifndef NDEBUG
+ checkCurrentIdentifierTable(vm);
+#endif
+ if (r->isIdentifier())
+ return r;
+ return addSlowCase(vm, r);
+ }
+
+ JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r);
+ JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(VM*, StringImpl* r);
+
+ JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(ExecState*);
+ JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(VM*);
+ };
+
+ template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
+ {
+ ASSERT(maxSingleCharacterString == 0xff);
+ return true;
}
- if (!isIndex(value))
- return Nullopt;
- return value;
-}
-
-ALWAYS_INLINE Optional<uint32_t> parseIndex(StringImpl& impl)
-{
- if (impl.is8Bit())
- return parseIndex(impl.characters8(), impl.length());
- return parseIndex(impl.characters16(), impl.length());
-}
-
-class Identifier {
- friend class Structure;
-public:
- Identifier() { }
- enum EmptyIdentifierFlag { EmptyIdentifier };
- Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { ASSERT(m_string.impl()->isAtomic()); }
-
- const String& string() const { return m_string; }
- UniquedStringImpl* impl() const { return static_cast<UniquedStringImpl*>(m_string.impl()); }
-
- int length() const { return m_string.length(); }
-
- CString ascii() const { return m_string.ascii(); }
- CString utf8() const { return m_string.utf8(); }
-
- // There's 2 functions to construct Identifier from string, (1) fromString and (2) fromUid.
- // They have different meanings in keeping or discarding symbol-ness of strings.
- // (1): fromString
- // Just construct Identifier from string. String held by Identifier is always atomized.
- // Symbol-ness of StringImpl*, which represents that the string is inteded to be used for ES6 Symbols, is discarded.
- // So a constructed Identifier never represents a symbol.
- // (2): fromUid
- // `StringImpl* uid` represents ether String or Symbol property.
- // fromUid keeps symbol-ness of provided StringImpl* while fromString discards it.
- // Use fromUid when constructing Identifier from StringImpl* which may represent symbols.
-
- // Only to be used with string literals.
- template<unsigned charactersCount>
- static Identifier fromString(VM*, const char (&characters)[charactersCount]);
- template<unsigned charactersCount>
- static Identifier fromString(ExecState*, const char (&characters)[charactersCount]);
- static Identifier fromString(VM*, const LChar*, int length);
- static Identifier fromString(VM*, const UChar*, int length);
- static Identifier fromString(VM*, const String&);
- static Identifier fromString(ExecState*, AtomicStringImpl*);
- static Identifier fromString(ExecState*, const AtomicString&);
- static Identifier fromString(ExecState*, const String&);
- static Identifier fromString(ExecState*, const char*);
-
- static Identifier fromUid(VM*, UniquedStringImpl* uid);
- static Identifier fromUid(ExecState*, UniquedStringImpl* uid);
- static Identifier fromUid(const PrivateName&);
-
- static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
-
- JS_EXPORT_PRIVATE static Identifier from(ExecState*, unsigned y);
- JS_EXPORT_PRIVATE static Identifier from(ExecState*, int y);
- static Identifier from(ExecState*, double y);
- static Identifier from(VM*, unsigned y);
- static Identifier from(VM*, int y);
- static Identifier from(VM*, double y);
-
- bool isNull() const { return m_string.isNull(); }
- bool isEmpty() const { return m_string.isEmpty(); }
- bool isSymbol() const { return !isNull() && impl()->isSymbol(); }
-
- friend bool operator==(const Identifier&, const Identifier&);
- friend bool operator!=(const Identifier&, const Identifier&);
-
- friend bool operator==(const Identifier&, const LChar*);
- friend bool operator==(const Identifier&, const char*);
- friend bool operator!=(const Identifier&, const LChar*);
- friend bool operator!=(const Identifier&, const char*);
-
- static bool equal(const StringImpl*, const LChar*);
- static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
- static bool equal(const StringImpl*, const LChar*, unsigned length);
- static bool equal(const StringImpl*, const UChar*, unsigned length);
- static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
-
- // Only to be used with string literals.
- JS_EXPORT_PRIVATE static Ref<StringImpl> add(VM*, const char*);
- JS_EXPORT_PRIVATE static Ref<StringImpl> add(ExecState*, const char*);
-
- void dump(PrintStream&) const;
-
-private:
- String m_string;
-
- // Only to be used with string literals.
- template<unsigned charactersCount>
- Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { ASSERT(m_string.impl()->isAtomic()); }
-
- Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
- Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
- Identifier(ExecState*, AtomicStringImpl*);
- Identifier(ExecState*, const AtomicString&);
- Identifier(VM* vm, const String& string) : m_string(add(vm, string.impl())) { ASSERT(m_string.impl()->isAtomic()); }
- Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { ASSERT(m_string.impl()->isAtomic()); }
-
- Identifier(SymbolImpl& uid)
- : m_string(&uid)
+ template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
{
+ return (c <= maxSingleCharacterString);
}
- template <typename CharType>
- ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
+ template <typename T>
+ struct CharBuffer {
+ const T* s;
+ unsigned int length;
+ };
+
+ template <typename T>
+ struct IdentifierCharBufferTranslator {
+ static unsigned hash(const CharBuffer<T>& buf)
+ {
+ return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length);
+ }
+
+ static bool equal(StringImpl* str, const CharBuffer<T>& buf)
+ {
+ return Identifier::equal(str, buf.s, buf.length);
+ }
+
+ static void translate(StringImpl*& location, const CharBuffer<T>& buf, unsigned hash)
+ {
+ T* d;
+ StringImpl& r = StringImpl::createUninitialized(buf.length, d).leakRef();
+ for (unsigned i = 0; i != buf.length; i++)
+ d[i] = buf.s[i];
+ r.setHash(hash);
+ location = &r;
+ }
+ };
+
+ template <typename T>
+ PassRefPtr<StringImpl> Identifier::add(VM* vm, const T* s, int length)
+ {
+ if (length == 1) {
+ T c = s[0];
+ if (canUseSingleCharacterString(c))
+ return add(vm, vm->smallStrings.singleCharacterStringRep(c));
+ }
+
+ if (!length)
+ return StringImpl::empty();
+ CharBuffer<T> buf = { s, static_cast<unsigned>(length) };
+ HashSet<StringImpl*>::AddResult addResult = vm->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T>>(buf);
+
+ // If the string is newly-translated, then we need to adopt it.
+ // The boolean in the pair tells us if that is so.
+ return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
+ }
- static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
- static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
+ inline bool operator==(const Identifier& a, const Identifier& b)
+ {
+ return Identifier::equal(a, b);
+ }
- template <typename T> static Ref<StringImpl> add(VM*, const T*, int length);
- static Ref<StringImpl> add8(VM*, const UChar*, int length);
- template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
+ inline bool operator!=(const Identifier& a, const Identifier& b)
+ {
+ return !Identifier::equal(a, b);
+ }
- static Ref<StringImpl> add(ExecState*, StringImpl*);
- static Ref<StringImpl> add(VM*, StringImpl*);
+ inline bool operator==(const Identifier& a, const LChar* b)
+ {
+ return Identifier::equal(a, b);
+ }
-#ifndef NDEBUG
- JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(ExecState*);
- JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(VM*);
-#else
- JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(ExecState*);
- JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(VM*);
-#endif
-};
-
-template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
-{
- ASSERT(maxSingleCharacterString == 0xff);
- return true;
-}
-
-template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
-{
- return (c <= maxSingleCharacterString);
-}
-
-template <typename T>
-Ref<StringImpl> Identifier::add(VM* vm, const T* s, int length)
-{
- if (length == 1) {
- T c = s[0];
- if (canUseSingleCharacterString(c))
- return *vm->smallStrings.singleCharacterStringRep(c);
+ inline bool operator==(const Identifier& a, const char* b)
+ {
+ return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+ }
+
+ inline bool operator!=(const Identifier& a, const LChar* b)
+ {
+ return !Identifier::equal(a, b);
+ }
+
+ inline bool operator!=(const Identifier& a, const char* b)
+ {
+ return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+ }
+
+ inline bool Identifier::equal(const StringImpl* r, const LChar* s)
+ {
+ return WTF::equal(r, s);
+ }
+
+ inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
+ {
+ return WTF::equal(r, s, length);
+ }
+
+ inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
+ {
+ return WTF::equal(r, s, length);
+ }
+
+ IdentifierTable* createIdentifierTable();
+ void deleteIdentifierTable(IdentifierTable*);
+
+ struct IdentifierRepHash : PtrHash<RefPtr<StringImpl>> {
+ static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); }
+ static unsigned hash(StringImpl* key) { return key->existingHash(); }
+ };
+
+ struct IdentifierMapIndexHashTraits : HashTraits<int> {
+ static int emptyValue() { return std::numeric_limits<int>::max(); }
+ static const bool emptyValueIsZero = false;
+ };
+
+ typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
+ typedef HashMap<StringImpl*, int, IdentifierRepHash, HashTraits<StringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
+
+ template<typename U, typename V>
+ HashSet<StringImpl*>::AddResult IdentifierTable::add(U value)
+ {
+ HashSet<StringImpl*>::AddResult result = m_table.add<V>(value);
+ (*result.iterator)->setIsIdentifier(true);
+ return result;
}
- if (!length)
- return *StringImpl::empty();
-
- return *AtomicStringImpl::add(s, length);
-}
-
-inline bool operator==(const Identifier& a, const Identifier& b)
-{
- return Identifier::equal(a, b);
-}
-
-inline bool operator!=(const Identifier& a, const Identifier& b)
-{
- return !Identifier::equal(a, b);
-}
-
-inline bool operator==(const Identifier& a, const LChar* b)
-{
- return Identifier::equal(a, b);
-}
-
-inline bool operator==(const Identifier& a, const char* b)
-{
- return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
-}
-
-inline bool operator!=(const Identifier& a, const LChar* b)
-{
- return !Identifier::equal(a, b);
-}
-
-inline bool operator!=(const Identifier& a, const char* b)
-{
- return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
-}
-
-inline bool Identifier::equal(const StringImpl* r, const LChar* s)
-{
- return WTF::equal(r, s);
-}
-
-inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
-{
- return WTF::equal(r, s, length);
-}
-
-inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
-{
- return WTF::equal(r, s, length);
-}
-
-ALWAYS_INLINE Optional<uint32_t> parseIndex(const Identifier& identifier)
-{
- auto uid = identifier.impl();
- if (!uid)
- return Nullopt;
- if (uid->isSymbol())
- return Nullopt;
- return parseIndex(*uid);
-}
-
-JSValue identifierToJSValue(VM&, const Identifier&);
-// This will stringify private symbols. When leaking JSValues to
-// non-internal code, make sure to use this function and not the above one.
-JSValue identifierToSafePublicJSValue(VM&, const Identifier&);
-
-// FIXME: It may be better for this to just be a typedef for PtrHash, since PtrHash may be cheaper to
-// compute than loading the StringImpl's hash from memory. That change would also reduce the likelihood of
-// crashes in code that somehow dangled a StringImpl.
-// https://bugs.webkit.org/show_bug.cgi?id=150137
-struct IdentifierRepHash : PtrHash<RefPtr<UniquedStringImpl>> {
- static unsigned hash(const RefPtr<UniquedStringImpl>& key) { return key->existingSymbolAwareHash(); }
- static unsigned hash(UniquedStringImpl* key) { return key->existingSymbolAwareHash(); }
-};
-
-struct IdentifierMapIndexHashTraits : HashTraits<int> {
- static int emptyValue() { return std::numeric_limits<int>::max(); }
- static const bool emptyValueIsZero = false;
-};
-
-typedef HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> IdentifierSet;
-typedef HashMap<RefPtr<UniquedStringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
-typedef HashMap<UniquedStringImpl*, int, IdentifierRepHash, HashTraits<UniquedStringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
} // namespace JSC