2010-09-10 Oliver Hunt <oliver@apple.com>
Reviewed by Darin Adler.
Speed up deserialisation of strings
https://bugs.webkit.org/show_bug.cgi?id=45555
Rather than building a list of Identifiers for the string pool
we now build a list of a tuple of UString and JSString*. This
doesn't hurt the property name case as ustring->identifier conversion
is essentially free if the ustring has already been converted to
an Identifier, but saves an unnecessary Identifier creation for
strings we only ever use to create JSStrings. We also reduce
GC pressure for duplicate strings by caching the JSStrings.
* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::CachedString::CachedString):
(WebCore::CloneDeserializer::CachedString::jsString):
(WebCore::CloneDeserializer::CachedString::ustring):
(WebCore::CloneDeserializer::readStringData):
(WebCore::CloneDeserializer::putProperty):
(WebCore::CloneDeserializer::readFile):
(WebCore::CloneDeserializer::readTerminal):
(WebCore::CloneDeserializer::deserialize):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@67222 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/bindings/js/SerializedScriptValue.cpp b/WebCore/bindings/js/SerializedScriptValue.cpp
index fa8a1ed..2146632 100644
--- a/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -762,6 +762,25 @@
}
private:
+ struct CachedString {
+ CachedString(const UString& string)
+ : m_string(string)
+ {
+ }
+
+ JSValue jsString(ExecState* exec)
+ {
+ if (!m_jsString)
+ m_jsString = JSC::jsString(exec, m_string);
+ return m_jsString;
+ }
+ const UString& ustring() { return m_string; }
+
+ private:
+ UString m_string;
+ JSValue m_jsString;
+ };
+
CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
: CloneBase(exec)
, m_globalObject(globalObject)
@@ -903,13 +922,13 @@
return true;
}
- bool readStringData(Identifier& ident)
+ bool readStringData(CachedString*& cachedString)
{
bool scratch;
- return readStringData(ident, scratch);
+ return readStringData(cachedString, scratch);
}
- bool readStringData(Identifier& ident, bool& wasTerminator)
+ bool readStringData(CachedString*& cachedString, bool& wasTerminator)
{
if (m_failed)
return false;
@@ -930,7 +949,7 @@
fail();
return false;
}
- ident = m_constantPool[index];
+ cachedString = &m_constantPool[index];
return true;
}
UString str;
@@ -938,8 +957,8 @@
fail();
return false;
}
- ident = Identifier(m_exec, str);
- m_constantPool.append(ident);
+ m_constantPool.append(str);
+ cachedString = &m_constantPool.last();
return true;
}
@@ -958,24 +977,24 @@
array->put(m_exec, index, value);
}
- void putProperty(JSObject* object, Identifier& property, JSValue value)
+ void putProperty(JSObject* object, const Identifier& property, JSValue value)
{
object->putDirect(property, value);
}
bool readFile(RefPtr<File>& file)
{
- Identifier path;
+ CachedString* path;
if (!readStringData(path))
return 0;
- Identifier url;
+ CachedString* url;
if (!readStringData(url))
return 0;
- Identifier type;
+ CachedString* type;
if (!readStringData(type))
return 0;
if (m_isDOMGlobalObject)
- file = File::create(String(path.ustring().impl()), KURL(KURL(), String(url.ustring().impl())), String(type.ustring().impl()));
+ file = File::create(String(path->ustring().impl()), KURL(KURL(), String(url->ustring().impl())), String(type->ustring().impl()));
return true;
}
@@ -1061,10 +1080,10 @@
return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
}
case BlobTag: {
- Identifier url;
+ CachedString* url;
if (!readStringData(url))
return JSValue();
- Identifier type;
+ CachedString* type;
if (!readStringData(type))
return JSValue();
unsigned long long size = 0;
@@ -1072,24 +1091,24 @@
return JSValue();
if (!m_isDOMGlobalObject)
return jsNull();
- return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(KURL(KURL(), url.ustring().impl()), String(type.ustring().impl()), size));
+ return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(KURL(KURL(), url->ustring().impl()), String(type->ustring().impl()), size));
}
case StringTag: {
- Identifier ident;
- if (!readStringData(ident))
+ CachedString* cachedString;
+ if (!readStringData(cachedString))
return JSValue();
- return jsString(m_exec, ident.ustring());
+ return cachedString->jsString(m_exec);
}
case EmptyStringTag:
return jsEmptyString(&m_exec->globalData());
case RegExpTag: {
- Identifier pattern;
+ CachedString* pattern;
if (!readStringData(pattern))
return JSValue();
- Identifier flags;
+ CachedString* flags;
if (!readStringData(flags))
return JSValue();
- RefPtr<RegExp> regExp = RegExp::create(&m_exec->globalData(), pattern.ustring(), flags.ustring());
+ RefPtr<RegExp> regExp = RegExp::create(&m_exec->globalData(), pattern->ustring(), flags->ustring());
return new (m_exec) RegExpObject(m_exec->lexicalGlobalObject(), m_globalObject->regExpStructure(), regExp);
}
default:
@@ -1103,7 +1122,7 @@
const uint8_t* m_ptr;
const uint8_t* m_end;
unsigned m_version;
- Vector<Identifier> m_constantPool;
+ Vector<CachedString> m_constantPool;
};
JSValue CloneDeserializer::deserialize()
@@ -1192,9 +1211,9 @@
tickCount = ticksUntilNextCheck();
}
- Identifier ident;
+ CachedString* cachedString;
bool wasTerminator = false;
- if (!readStringData(ident, wasTerminator)) {
+ if (!readStringData(cachedString, wasTerminator)) {
if (!wasTerminator)
goto error;
JSObject* outObject = outputObjectStack.last();
@@ -1205,11 +1224,11 @@
}
if (JSValue terminal = readTerminal()) {
- putProperty(outputObjectStack.last(), ident, terminal);
+ putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->ustring()), terminal);
goto objectStartVisitMember;
}
stateStack.append(ObjectEndVisitMember);
- propertyNameStack.append(ident);
+ propertyNameStack.append(Identifier(m_exec, cachedString->ustring()));
goto stateUnknown;
}
case ObjectEndVisitMember: {