Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (92568 => 92569)
--- trunk/Source/_javascript_Core/ChangeLog 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-08-07 03:44:45 UTC (rev 92569)
@@ -1,3 +1,32 @@
+2011-08-06 Gavin Barraclough <[email protected]>
+
+ https://bugs.webkit.org/show_bug.cgi?id=65821
+ Don't form identifiers the first time a string is used as a property name.
+
+ Reviewed by Oliver Hunt.
+
+ This is a 1% win on SunSpider.
+
+ * dfg/DFGOperations.cpp:
+ - Use fastGetOwnProperty.
+ * jit/JITStubs.cpp:
+ (JSC::DEFINE_STUB_FUNCTION):
+ - Use fastGetOwnProperty.
+ * runtime/JSCell.h:
+ * runtime/JSObject.h:
+ (JSC::JSCell::fastGetOwnProperty):
+ - Fast call to get a property without creating an identifier the first time.
+ * runtime/PropertyMapHashTable.h:
+ (JSC::PropertyTable::find):
+ (JSC::PropertyTable::findWithString):
+ - Add interface to look up by either strinsg or identifiers.
+ * runtime/Structure.h:
+ (JSC::Structure::get):
+ - Add a get() call that takes a UString, not an Identifier.
+ * wtf/text/StringImpl.h:
+ (WTF::StringImpl::hasHash):
+ - Add a call to check if the has has been set (to detect the first use as a property name).
+
2011-08-06 Aron Rosenberg <[email protected]>
Reviewed by Benjamin Poulain.
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (92568 => 92569)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-08-07 03:44:45 UTC (rev 92569)
@@ -210,10 +210,8 @@
if (propertyAsUInt32 == propertyAsDouble)
return getByVal(exec, base, propertyAsUInt32);
} else if (property.isString()) {
- Identifier propertyName(exec, asString(property)->value(exec));
- PropertySlot slot(base);
- if (base->fastGetOwnPropertySlot(exec, propertyName, slot))
- return JSValue::encode(slot.getValue(exec, propertyName));
+ if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec)))
+ return JSValue::encode(result);
}
}
Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (92568 => 92569)
--- trunk/Source/_javascript_Core/jit/JITStubs.cpp 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp 2011-08-07 03:44:45 UTC (rev 92569)
@@ -2249,12 +2249,7 @@
JSValue subscript = stackFrame.args[1].jsValue();
if (LIKELY(baseValue.isCell() && subscript.isString())) {
- Identifier propertyName(callFrame, asString(subscript)->value(callFrame));
- PropertySlot slot(baseValue.asCell());
- // JSString::value may have thrown, but we shouldn't find a property with a null identifier,
- // so we should miss this case and wind up in the CHECK_FOR_EXCEPTION_AT_END, below.
- if (baseValue.asCell()->fastGetOwnPropertySlot(callFrame, propertyName, slot)) {
- JSValue result = slot.getValue(callFrame, propertyName);
+ if (JSValue result = baseValue.asCell()->fastGetOwnProperty(callFrame, asString(subscript)->value(callFrame))) {
CHECK_FOR_EXCEPTION();
return JSValue::encode(result);
}
Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (92568 => 92569)
--- trunk/Source/_javascript_Core/runtime/JSCell.h 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h 2011-08-07 03:44:45 UTC (rev 92569)
@@ -137,6 +137,7 @@
// call this function, not its slower virtual counterpart. (For integer
// property names, we want a similar interface with appropriate optimizations.)
bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+ JSValue fastGetOwnProperty(ExecState*, const UString&);
static ptrdiff_t structureOffset()
{
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (92568 => 92569)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2011-08-07 03:44:45 UTC (rev 92569)
@@ -536,6 +536,22 @@
return getOwnPropertySlot(exec, propertyName, slot);
}
+// Fast call to get a property where we may not yet have converted the string to an
+// identifier. The first time we perform a property access with a given string, try
+// performing the property map lookup without forming an identifier. We detect this
+// case by checking whether the hash has yet been set for this string.
+ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const UString& name)
+{
+ if (!m_structure->typeInfo().overridesGetOwnPropertySlot() && !m_structure->hasGetterSetterProperties()) {
+ size_t offset = name.impl()->hasHash()
+ ? m_structure->get(exec->globalData(), Identifier(exec, name))
+ : m_structure->get(exec->globalData(), name);
+ if (offset != WTF::notFound)
+ return asObject(this)->locationForOffset(offset)->get();
+ }
+ return JSValue();
+}
+
// It may seem crazy to inline a function this large but it makes a big difference
// since this is function very hot in variable lookup
ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
Modified: trunk/Source/_javascript_Core/runtime/PropertyMapHashTable.h (92568 => 92569)
--- trunk/Source/_javascript_Core/runtime/PropertyMapHashTable.h 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/runtime/PropertyMapHashTable.h 2011-08-07 03:44:45 UTC (rev 92569)
@@ -154,7 +154,8 @@
const_iterator end() const;
// Find a value in the table.
- find_iterator find(const KeyType& key);
+ find_iterator find(const KeyType&);
+ find_iterator findWithString(const KeyType&);
// Add a value to the table
std::pair<find_iterator, bool> add(const ValueType& entry);
// Remove a value from the table.
@@ -324,6 +325,7 @@
inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
{
ASSERT(key);
+ ASSERT(key->isIdentifier());
unsigned hash = key->existingHash();
unsigned step = 0;
@@ -343,7 +345,7 @@
#endif
if (!step)
- step =WTF::doubleHash(key->existingHash()) | 1;
+ step = WTF::doubleHash(key->existingHash()) | 1;
hash += step;
#if DUMP_PROPERTYMAP_STATS
@@ -352,6 +354,38 @@
}
}
+inline PropertyTable::find_iterator PropertyTable::findWithString(const KeyType& key)
+{
+ ASSERT(key);
+ ASSERT(!key->isIdentifier() && !key->hasHash());
+ unsigned hash = key->hash();
+ unsigned step = 0;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ while (true) {
+ unsigned entryIndex = m_index[hash & m_indexMask];
+ if (entryIndex == EmptyEntryIndex)
+ return std::make_pair((ValueType*)0, hash & m_indexMask);
+ if (equal(key, table()[entryIndex - 1].key))
+ return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ if (!step)
+ step = WTF::doubleHash(key->existingHash()) | 1;
+ hash += step;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+}
+
inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const ValueType& entry)
{
// Look for a value with a matching key already in the array.
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (92568 => 92569)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2011-08-07 03:44:45 UTC (rev 92569)
@@ -112,6 +112,7 @@
bool isUsingInlineStorage() const;
size_t get(JSGlobalData&, const Identifier& propertyName);
+ size_t get(JSGlobalData&, const UString& name);
size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
{
@@ -265,6 +266,18 @@
return entry ? entry->offset : notFound;
}
+ inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return notFound;
+
+ PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
+ ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
+ return entry ? entry->offset : notFound;
+ }
+
inline bool JSCell::isObject() const
{
return m_structure->typeInfo().type() == ObjectType;
Modified: trunk/Source/_javascript_Core/wtf/text/StringImpl.h (92568 => 92569)
--- trunk/Source/_javascript_Core/wtf/text/StringImpl.h 2011-08-07 01:09:23 UTC (rev 92568)
+++ trunk/Source/_javascript_Core/wtf/text/StringImpl.h 2011-08-07 03:44:45 UTC (rev 92569)
@@ -238,6 +238,7 @@
unsigned hash() const { if (!m_hash) m_hash = StringHasher::computeHash(m_data, m_length); return m_hash; }
unsigned existingHash() const { ASSERT(m_hash); return m_hash; }
+ bool hasHash() const { return m_hash; }
ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; }
ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic)) == s_refCountIncrement; }