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.h481
1 files changed, 265 insertions, 216 deletions
diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h
index 75b68b6e1..4fb1a2ffa 100644
--- a/Source/JavaScriptCore/runtime/Identifier.h
+++ b/Source/JavaScriptCore/runtime/Identifier.h
@@ -22,239 +22,288 @@
#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;
-
- 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* characters() const { return m_string.characters(); }
- int length() const { return m_string.length(); }
-
- CString ascii() const { return m_string.ascii(); }
-
- 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;
- }
-
- template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
- {
- return (c <= maxSingleCharacterString);
- }
-
- 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;
- }
-
- 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);
+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;
}
- inline bool operator==(const Identifier& a, const LChar* b)
+ 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)
{
- 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);
- }
+ template <typename CharType>
+ ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
- 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);
- }
+ 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 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(); }
- };
+ 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);
- struct IdentifierMapIndexHashTraits : HashTraits<int> {
- static int emptyValue() { return std::numeric_limits<int>::max(); }
- static const bool emptyValueIsZero = false;
- };
+ static Ref<StringImpl> add(ExecState*, StringImpl*);
+ static Ref<StringImpl> add(VM*, StringImpl*);
- typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap;
-
- 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;
+#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);
}
+ 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