[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: KDE/kdelibs/kjs
From: Maks Orlovich <maksim () kde ! org>
Date: 2009-04-26 21:34:53
Message-ID: 1240781693.184555.10422.nullmailer () svn ! kde ! org
[Download RAW message or body]
SVN commit 959716 by orlovich:
automatically merged revision 959712:
Cache and coalesce StringImp's for sufficiently short string literals.
This cuts heap usage by about 48% on vandenoever's heap demo;
also seems to be about ~2% speedup on SunSpider --- perhaps, it's noisy;
but with a clear 1.11x or so on string-unpack-code which is fairly
realistic piece of code, too
CCBUG:190609
M +0 -31 identifier.cpp
M +0 -2 identifier.h
M +45 -0 interpreter.cpp
M +18 -0 interpreter.h
M +3 -1 nodes.h
M +21 -5 nodes2bytecode.cpp
M +20 -0 ustring.h
--- trunk/KDE/kdelibs/kjs/identifier.cpp #959715:959716
@@ -27,23 +27,6 @@
#include <string.h> // for strlen
#include <new> // for placement new
-namespace WTF {
-
- template<typename T> struct DefaultHash;
- template<typename T> struct StrHash;
-
- template<> struct StrHash<KJS::UString::Rep *> {
- static unsigned hash(const KJS::UString::Rep *key) { return key->hash(); }
- static bool equal(const KJS::UString::Rep *a, const KJS::UString::Rep *b) { \
return KJS::Identifier::equal(a, b); }
- static const bool safeToCompareToEmptyOrDeleted = false;
- };
-
- template<> struct DefaultHash<KJS::UString::Rep *> {
- typedef StrHash<KJS::UString::Rep *> Hash;
- };
-
-}
-
namespace KJS {
typedef HashSet<UString::Rep *> IdentifierTable;
@@ -56,7 +39,6 @@
return *table;
}
-
bool Identifier::equal(const UString::Rep *r, const char *s)
{
int length = r->len;
@@ -78,19 +60,6 @@
return true;
}
-bool Identifier::equal(const UString::Rep *r, const UString::Rep *b)
-{
- int length = r->len;
- if (length != b->len)
- return false;
- const UChar *d = r->data();
- const UChar *s = b->data();
- for (int i = 0; i != length; ++i)
- if (d[i].uc != s[i].uc)
- return false;
- return true;
-}
-
struct CStringTranslator
{
static unsigned hash(const char *c)
--- trunk/KDE/kdelibs/kjs/identifier.h #959715:959716
@@ -98,10 +98,8 @@
friend bool operator==(const Identifier&, const char*);
static void remove(UString::Rep*);
-
static bool equal(const UString::Rep*, const char*);
static bool equal(const UString::Rep*, const UChar*, int length);
- static bool equal(const UString::Rep*, const UString::Rep*);
private:
UString _ustring;
--- trunk/KDE/kdelibs/kjs/interpreter.cpp #959715:959716
@@ -4,6 +4,7 @@
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003 Apple Computer, Inc.
+ * Copyright (C) 2008, 2009 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -226,6 +227,8 @@
{
JSLock lock;
+ initInternedStringsTable();
+
m_refCount = 0;
m_timeoutTime = 0;
m_recursion = 0;
@@ -753,6 +756,8 @@
// tendenacy to pin blocks, increasing their number and hence spreading out
// the objects somewhat
m_numCachedActivations = 0;
+
+ markInternedStringsTable();
}
#ifdef KJS_DEBUG_MEM
@@ -930,7 +935,47 @@
return retval;
}
+Interpreter::InternedStringsTable* Interpreter::s_internedStrings;
+void Interpreter::initInternedStringsTable()
+{
+ if (!s_internedStrings)
+ s_internedStrings = new InternedStringsTable();
+}
+
+StringImp* Interpreter::internString(const UString& literal)
+{
+ std::pair<InternedStringsTable::iterator, bool> p =
+ s_internedStrings->add(literal.rep(), std::make_pair((StringImp*)(0), 1));
+
+ if (p.second) // actually added..
+ p.first.values()->first = static_cast<StringImp*>(jsOwnedString(literal));
+ else
+ ++p.first.values()->second; // just bump the ref count
+
+ return p.first.values()->first;
+}
+
+void Interpreter::releaseInternedString(const UString& literal)
+{
+ InternedStringsTable::iterator i = s_internedStrings->find(literal.rep());
+
+ --i.values()->second;
+ if (i.values()->second == 0)
+ s_internedStrings->remove(i);
+}
+
+void Interpreter::markInternedStringsTable()
+{
+ for (InternedStringsTable::iterator i = s_internedStrings->begin();
+ i != s_internedStrings->end(); ++i) {
+ // Note: the StringImp* may be null here if we got called in the middle
+ // of internString.
+ if (i.values()->first && !i.values()->first->marked())
+ i.values()->first->mark();
+ }
+}
+
SavedBuiltins::SavedBuiltins() :
_internal(0)
{
--- trunk/KDE/kdelibs/kjs/interpreter.h #959715:959716
@@ -28,6 +28,7 @@
#include "protect.h"
#include "value.h"
#include "types.h"
+#include <wtf/HashMap.h>
namespace KJS {
class Debugger;
@@ -36,6 +37,7 @@
class Package;
class ActivationImp;
class JSGlobalObject;
+ class StringImp;
#if USE(BINDINGS)
namespace Bindings {
@@ -376,6 +378,22 @@
}
void recycleActivation(ActivationImp* act);
+
+ // Global string table management. This is used from StringNode
+ // to cache StringImp's for string literals. We keep refcounts
+ // to permit multiple ones to use the same value.
+ static StringImp* internString(const UString& literal);
+ static void releaseInternedString(const UString& literal);
+
+ typedef WTF::HashMap<UString::Rep*, std::pair<KJS::StringImp*, int> > \
InternedStringsTable; +private:
+ static void markInternedStringsTable();
+
+ // This creates a table if needed
+ static void initInternedStringsTable();
+
+ static InternedStringsTable* s_internedStrings;
+
protected:
virtual ~Interpreter(); // only deref should delete us
virtual bool shouldInterruptScript() const { return true; }
--- trunk/KDE/kdelibs/kjs/nodes.h #959715:959716
@@ -253,7 +253,8 @@
class StringNode : public Node {
public:
- StringNode(const UString *v) : val(*v) { }
+ StringNode(const UString *v) : val(*v), interned(0) { }
+ ~StringNode(); // in nodes2bytecode.cpp
UString value() const { return val; }
void setValue(const UString& v) { val = v; }
@@ -262,6 +263,7 @@
virtual void streamTo(SourceStream&) const;
private:
UString val;
+ StringImp* interned;
};
class RegExpNode : public Node {
--- trunk/KDE/kdelibs/kjs/nodes2bytecode.cpp #959715:959716
@@ -107,17 +107,33 @@
OpValue StringNode::generateEvalCode(CompileState* comp)
{
- // For now, just generate a register value pointer.
+ // For now, just generate a JSValue
// We may want to permit string pointers as well, to help overload resolution,
// but it's not clear whether that's useful, since we can't MM them. Perhaps
// a special StringInstance type may be of use eventually.
- OpValue inStr = OpValue::immString(&val);
+
+ if (interned) // we're re-compiling.. just reuse it
+ return OpValue::immValue(interned);
+
+ // Intern shorter strings
+ if (val.size() < 16) {
+ interned = Interpreter::internString(val);
+ return OpValue::immValue(interned);
+ } else {
+ OpValue inStr = OpValue::immString(&val);
- OpValue out;
- CodeGen::emitOp(comp, Op_OwnedString, &out, &inStr);
- return out;
+ OpValue out;
+ CodeGen::emitOp(comp, Op_OwnedString, &out, &inStr);
+ return out;
+ }
}
+StringNode::~StringNode()
+{
+ if (interned)
+ Interpreter::releaseInternedString(val);
+}
+
OpValue RegExpNode::generateEvalCode(CompileState* comp)
{
// ### TODO: cache the engine object?
--- trunk/KDE/kdelibs/kjs/ustring.h #959715:959716
@@ -264,6 +264,9 @@
* Constructs a string from a double.
*/
static UString from(double d);
+
+
+ static bool equal(const UString::Rep* a, const UString::Rep* b);
struct Range {
public:
@@ -507,4 +510,21 @@
} // namespace
+namespace WTF {
+
+ template<typename T> struct DefaultHash;
+ template<typename T> struct StrHash;
+
+ template<> struct StrHash<KJS::UString::Rep *> {
+ static unsigned hash(const KJS::UString::Rep *key) { return key->hash(); }
+ static bool equal(const KJS::UString::Rep *a, const KJS::UString::Rep *b) { \
return KJS::UString::equal(a, b); } + static const bool \
safeToCompareToEmptyOrDeleted = false; + };
+
+ template<> struct DefaultHash<KJS::UString::Rep *> {
+ typedef StrHash<KJS::UString::Rep *> Hash;
+ };
+} // namespace WTF
+
+
#endif
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic