[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373
oliver at apple.com
oliver at apple.com
Wed Apr 7 23:28:02 UTC 2010
The following commit has been merged in the webkit-1.2 branch:
commit bd8e770a6be16888f07dc7e4f430071ad97e907c
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Tue Nov 10 02:19:04 2009 +0000
Can cache prototype lookups on uncacheable dictionaries.
https://bugs.webkit.org/show_bug.cgi?id=31198
Reviewed by Gavin Barraclough.
Replace fromDictionaryTransition with flattenDictionaryObject and
flattenDictionaryStructure. This change is necessary as we need to
guarantee that our attempt to convert away from a dictionary structure
will definitely succeed, and in some cases this requires mutating the
object storage itself.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@50704 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 5f2d59f..3b13490 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,32 @@
+2009-11-09 Oliver Hunt <oliver at apple.com>
+
+ Reviewed by Gavin Barraclough.
+
+ Can cache prototype lookups on uncacheable dictionaries.
+ https://bugs.webkit.org/show_bug.cgi?id=31198
+
+ Replace fromDictionaryTransition with flattenDictionaryObject and
+ flattenDictionaryStructure. This change is necessary as we need to
+ guarantee that our attempt to convert away from a dictionary structure
+ will definitely succeed, and in some cases this requires mutating the
+ object storage itself.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::tryCacheGetByID):
+ * jit/JITStubs.cpp:
+ (JSC::JITThunks::tryCacheGetByID):
+ (JSC::DEFINE_STUB_FUNCTION):
+ * runtime/BatchedTransitionOptimizer.h:
+ (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer):
+ * runtime/JSObject.h:
+ (JSC::JSObject::flattenDictionaryObject):
+ * runtime/Operations.h:
+ (JSC::normalizePrototypeChain):
+ * runtime/Structure.cpp:
+ (JSC::Structure::flattenDictionaryStructure):
+ (JSC::comparePropertyMapEntryIndices):
+ * runtime/Structure.h:
+
2009-11-09 Laszlo Gombos <laszlo.1.gombos at nokia.com>
Not reviewed, build fix.
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 229dffc..8d32342 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -1042,7 +1042,7 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock*
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (baseObject->structure()->isDictionary())
- baseObject->setStructure(Structure::fromDictionaryTransition(baseObject->structure()));
+ baseObject->flattenDictionaryObject();
ASSERT(!baseObject->structure()->isUncacheableDictionary());
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index 7acd04c..b33319d 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -771,7 +771,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (slotBaseObject->structure()->isDictionary())
- slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
+ slotBaseObject->flattenDictionaryObject();
stubInfo->initGetByIdProto(structure, slotBaseObject->structure());
@@ -1181,7 +1181,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check)
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (slotBaseObject->structure()->isDictionary())
- slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
+ slotBaseObject->flattenDictionaryObject();
// The result fetched should always be the callee!
ASSERT(result == JSValue(callee));
@@ -1334,7 +1334,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (slotBaseObject->structure()->isDictionary())
- slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
+ slotBaseObject->flattenDictionaryObject();
int listIndex;
PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
diff --git a/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
index 929a5e7..74089a5 100644
--- a/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
+++ b/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
@@ -43,7 +43,7 @@ namespace JSC {
~BatchedTransitionOptimizer()
{
- m_object->setStructure(Structure::fromDictionaryTransition(m_object->structure()));
+ m_object->flattenDictionaryObject();
}
private:
diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h
index 5a89c40..d8375ac 100644
--- a/JavaScriptCore/runtime/JSObject.h
+++ b/JavaScriptCore/runtime/JSObject.h
@@ -210,6 +210,11 @@ namespace JSC {
return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
}
+ void flattenDictionaryObject()
+ {
+ m_structure->flattenDictionaryStructure(this);
+ }
+
protected:
static const unsigned StructureFlags = 0;
diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h
index 1aa68b3..3bfb982 100644
--- a/JavaScriptCore/runtime/Operations.h
+++ b/JavaScriptCore/runtime/Operations.h
@@ -243,7 +243,7 @@ namespace JSC {
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (cell->structure()->isDictionary())
- asObject(cell)->setStructure(Structure::fromDictionaryTransition(cell->structure()));
+ asObject(cell)->flattenDictionaryObject();
++count;
}
@@ -265,7 +265,7 @@ namespace JSC {
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (base->structure()->isDictionary())
- asObject(base)->setStructure(Structure::fromDictionaryTransition(base->structure()));
+ asObject(base)->flattenDictionaryObject();
++count;
}
diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp
index 2f3331f..e4c9ac3 100644
--- a/JavaScriptCore/runtime/Structure.cpp
+++ b/JavaScriptCore/runtime/Structure.cpp
@@ -77,6 +77,8 @@ static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>);
static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
#endif
+static int comparePropertyMapEntryIndices(const void* a, const void* b);
+
void Structure::dumpStatistics()
{
#if DUMP_STRUCTURE_ID_STATISTICS
@@ -534,20 +536,47 @@ PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* st
return toDictionaryTransition(structure, UncachedDictionaryKind);
}
-PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure)
+PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object)
{
- ASSERT(structure->isDictionary());
-
- // Since dictionary Structures are not shared, and no opcodes specialize
- // for them, we don't need to allocate a new Structure when transitioning
- // to non-dictionary status.
-
- // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the
- // deleted offsets vector) before transitioning from dictionary.
- if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty())
- structure->m_dictionaryKind = NoneDictionaryKind;
+ ASSERT(isDictionary());
+ if (isUncacheableDictionary()) {
+ ASSERT(m_propertyTable);
+ Vector<PropertyMapEntry*> sortedPropertyEntries(m_propertyTable->keyCount);
+ PropertyMapEntry** p = sortedPropertyEntries.data();
+ unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; i++) {
+ if (m_propertyTable->entries()[i].key)
+ *p++ = &m_propertyTable->entries()[i];
+ }
+ size_t propertyCount = p - sortedPropertyEntries.data();
+ qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);
+ sortedPropertyEntries.resize(propertyCount);
+
+ // We now have the properties currently defined on this object
+ // in the order that they are expected to be in, but we need to
+ // reorder the storage, so we have to copy the current values out
+ Vector<JSValue> values(propertyCount);
+ unsigned anonymousSlotCount = m_propertyTable->anonymousSlotCount;
+ for (unsigned i = 0; i < propertyCount; i++) {
+ PropertyMapEntry* entry = sortedPropertyEntries[i];
+ values[i] = object->getDirectOffset(entry->offset);
+ // Update property table to have the new property offsets
+ entry->offset = anonymousSlotCount + i;
+ entry->index = i;
+ }
+
+ // Copy the original property values into their final locations
+ for (unsigned i = 0; i < propertyCount; i++)
+ object->putDirectOffset(anonymousSlotCount + i, values[i]);
+
+ if (m_propertyTable->deletedOffsets) {
+ delete m_propertyTable->deletedOffsets;
+ m_propertyTable->deletedOffsets = 0;
+ }
+ }
- return structure;
+ m_dictionaryKind = NoneDictionaryKind;
+ return this;
}
size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
@@ -1004,7 +1033,7 @@ void Structure::rehashPropertyMapHashTable(unsigned newTableSize)
checkConsistency();
}
-static int comparePropertyMapEntryIndices(const void* a, const void* b)
+int comparePropertyMapEntryIndices(const void* a, const void* b)
{
unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;
unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index;
diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h
index f355c53..e8356f1 100644
--- a/JavaScriptCore/runtime/Structure.h
+++ b/JavaScriptCore/runtime/Structure.h
@@ -74,7 +74,8 @@ namespace JSC {
static PassRefPtr<Structure> getterSetterTransition(Structure*);
static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
- static PassRefPtr<Structure> fromDictionaryTransition(Structure*);
+
+ PassRefPtr<Structure> flattenDictionaryStructure(JSObject*);
~Structure();
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 9404c67..2197fad 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,17 @@
+2009-11-09 Oliver Hunt <oliver at apple.com>
+
+ Reviewed by Gavin Barraclough.
+
+ Can cache prototype lookups on uncacheable dictionaries.
+ https://bugs.webkit.org/show_bug.cgi?id=31198
+
+ Add tests for lookup on uncacheable prototype.
+
+ * fast/js/dictionary-prototype-caching-expected.txt: Added.
+ * fast/js/dictionary-prototype-caching.html: Added.
+ * fast/js/script-tests/dictionary-prototype-caching.js: Added.
+ (protoTest):
+
2009-11-09 Anders Carlsson <andersca at apple.com>
Reviewed by Darin Adler and Dan Bernstein.
diff --git a/LayoutTests/fast/js/dictionary-prototype-caching-expected.txt b/LayoutTests/fast/js/dictionary-prototype-caching-expected.txt
new file mode 100644
index 0000000..b35f5e1
--- /dev/null
+++ b/LayoutTests/fast/js/dictionary-prototype-caching-expected.txt
@@ -0,0 +1,11 @@
+Test to ensure correct behaviour of prototype caching with dictionary prototypes
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS protoTest(o) is 'PASS'
+PASS protoTest(o) is undefined.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dictionary-prototype-caching.html b/LayoutTests/fast/js/dictionary-prototype-caching.html
new file mode 100644
index 0000000..cc6b88f
--- /dev/null
+++ b/LayoutTests/fast/js/dictionary-prototype-caching.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/dictionary-prototype-caching.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/dictionary-prototype-caching.js b/LayoutTests/fast/js/script-tests/dictionary-prototype-caching.js
new file mode 100644
index 0000000..68ba1c6
--- /dev/null
+++ b/LayoutTests/fast/js/script-tests/dictionary-prototype-caching.js
@@ -0,0 +1,57 @@
+description("Test to ensure correct behaviour of prototype caching with dictionary prototypes");
+
+function protoTest(o) {
+ return o.protoProp;
+}
+
+var proto = {protoProp: "PASS", propToRemove: "foo"};
+var o = { __proto__: proto };
+
+delete proto.propToRemove;
+
+// Prototype lookup caching will attempt to convert proto back to an ordinary structure
+protoTest(o);
+protoTest(o);
+protoTest(o);
+shouldBe("protoTest(o)", "'PASS'");
+delete proto.protoProp;
+proto.fakeProtoProp = "FAIL";
+shouldBeUndefined("protoTest(o)");
+
+function protoTest2(o) {
+ return o.b;
+}
+
+var proto = {a:1, b:"meh", c:2};
+var o = { __proto__: proto };
+
+delete proto.b;
+proto.d = 3;
+protoTest2(o);
+protoTest2(o);
+protoTest2(o);
+var protoKeys = [];
+for (var i in proto)
+ protoKeys.push(proto[i]);
+
+shouldBe("protoKeys", "[1,2,3]");
+
+function protoTest3(o) {
+ return o.b;
+}
+
+var proto = {a:1, b:"meh", c:2};
+var o = { __proto__: proto };
+
+delete proto.b;
+protoTest2(o);
+protoTest2(o);
+protoTest2(o);
+proto.d = 3;
+var protoKeys = [];
+for (var i in proto)
+ protoKeys.push(proto[i]);
+
+shouldBe("protoKeys", "[1,2,3]");
+
+successfullyParsed = true;
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list