[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