Changeset 76177 in webkit


Ignore:
Timestamp:
Jan 19, 2011 4:13:03 PM (13 years ago)
Author:
Antti Koivisto
Message:

Cache function offsets to speed up javascript parsing
https://bugs.webkit.org/show_bug.cgi?id=52622

Reviewed by Oliver Hunt.

Use cache to save function offsets and some other info.
This avoids quite a bit of work when reparsing the source.

Source/JavaScriptCore:

  • parser/ASTBuilder.h:
  • parser/JSParser.cpp:

(JSC::JSParser::CachedFunctionInfo::CachedFunctionInfo):
(JSC::JSParser::CachedFunctionInfo::approximateByteSize):
(JSC::JSParser::CachedFunctionInfo::closeBraceToken):
(JSC::JSParser::Scope::copyCapturedVariablesToVector):
(JSC::JSParser::Scope::saveFunctionInfo):
(JSC::JSParser::Scope::restoreFunctionInfo):
(JSC::JSParser::findCachedFunctionInfo):
(JSC::JSParser::JSParser):
(JSC::JSParser::parseProgram):
(JSC::JSParser::parseFunctionInfo):

  • parser/Lexer.h:

(JSC::Lexer::setOffset):
(JSC::Lexer::setLineNumber):
(JSC::Lexer::sourceProvider):

  • parser/SourceProvider.h:

(JSC::SourceProviderCache::SourceProviderCache):
(JSC::SourceProviderCache::~SourceProviderCache):
(JSC::SourceProviderCache::byteSize):
(JSC::SourceProviderCache::add):
(JSC::SourceProviderCache::get):
(JSC::SourceProvider::SourceProvider):
(JSC::SourceProvider::~SourceProvider):
(JSC::SourceProvider::cache):
(JSC::SourceProvider::notifyCacheSizeChanged):
(JSC::SourceProvider::cacheSizeChanged):

  • parser/SyntaxChecker.h:

Source/WebCore:

  • bindings/js/CachedScriptSourceProvider.h:

(WebCore::CachedScriptSourceProvider::cache):
(WebCore::CachedScriptSourceProvider::cacheSizeChanged):
(WebCore::CachedScriptSourceProvider::CachedScriptSourceProvider):

  • bindings/js/ScriptSourceProvider.h:

(WebCore::ScriptSourceProvider::ScriptSourceProvider):

  • loader/cache/CachedScript.cpp:

(WebCore::CachedScript::destroyDecodedData):
(WebCore::CachedScript::sourceProviderCache):
(WebCore::CachedScript::sourceProviderCacheSizeChanged):

  • loader/cache/CachedScript.h:
Location:
trunk/Source
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r76176 r76177  
     12011-01-19  Antti Koivisto  <antti@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        Cache function offsets to speed up javascript parsing
     6        https://bugs.webkit.org/show_bug.cgi?id=52622
     7       
     8        Use cache to save function offsets and some other info.
     9        This avoids quite a bit of work when reparsing the source.
     10
     11        * parser/ASTBuilder.h:
     12        * parser/JSParser.cpp:
     13        (JSC::JSParser::CachedFunctionInfo::CachedFunctionInfo):
     14        (JSC::JSParser::CachedFunctionInfo::approximateByteSize):
     15        (JSC::JSParser::CachedFunctionInfo::closeBraceToken):
     16        (JSC::JSParser::Scope::copyCapturedVariablesToVector):
     17        (JSC::JSParser::Scope::saveFunctionInfo):
     18        (JSC::JSParser::Scope::restoreFunctionInfo):
     19        (JSC::JSParser::findCachedFunctionInfo):
     20        (JSC::JSParser::JSParser):
     21        (JSC::JSParser::parseProgram):
     22        (JSC::JSParser::parseFunctionInfo):
     23        * parser/Lexer.h:
     24        (JSC::Lexer::setOffset):
     25        (JSC::Lexer::setLineNumber):
     26        (JSC::Lexer::sourceProvider):
     27        * parser/SourceProvider.h:
     28        (JSC::SourceProviderCache::SourceProviderCache):
     29        (JSC::SourceProviderCache::~SourceProviderCache):
     30        (JSC::SourceProviderCache::byteSize):
     31        (JSC::SourceProviderCache::add):
     32        (JSC::SourceProviderCache::get):
     33        (JSC::SourceProvider::SourceProvider):
     34        (JSC::SourceProvider::~SourceProvider):
     35        (JSC::SourceProvider::cache):
     36        (JSC::SourceProvider::notifyCacheSizeChanged):
     37        (JSC::SourceProvider::cacheSizeChanged):
     38        * parser/SyntaxChecker.h:
     39
    1402011-01-19  Mark Rowe  <mrowe@apple.com>
    241
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r75896 r76177  
    109109    static const bool CreatesAST = true;
    110110    static const bool NeedsFreeVariableInfo = true;
     111    static const bool CanUseFunctionCache = true;
    111112
    112113    ExpressionNode* makeBinaryNode(int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
  • trunk/Source/JavaScriptCore/parser/JSParser.cpp

    r76148 r76177  
    3434#include "NodeInfo.h"
    3535#include "ASTBuilder.h"
     36#include "SourceProvider.h"
    3637#include <wtf/HashFunctions.h>
    3738#include <wtf/WTFThreadData.h>
     
    9495        StringImpl* m_ident;
    9596        bool m_isLoop;
     97    };
     98   
     99    struct CachedFunctionInfo : public SourceProviderCache::Item {
     100        CachedFunctionInfo(int closeBraceLine, int closeBracePos)
     101            : closeBraceLine(closeBraceLine)
     102            , closeBracePos(closeBracePos)
     103        {
     104        }
     105        unsigned approximateByteSize() const
     106        {
     107            // The identifiers are uniqued strings so most likely there are few names that actually use any additional memory.
     108            static const unsigned assummedAverageIdentifierSize = sizeof(RefPtr<StringImpl>) + 2;
     109            unsigned size = sizeof(*this);
     110            size += usedVariables.size() * assummedAverageIdentifierSize;
     111            size += writtenVariables.size() * assummedAverageIdentifierSize;
     112            return size;
     113        }
     114        JSToken closeBraceToken() const
     115        {
     116            JSToken token;
     117            token.m_type = CLOSEBRACE;
     118            token.m_data.intValue = closeBracePos;
     119            token.m_info.startOffset = closeBracePos;
     120            token.m_info.endOffset = closeBracePos + 1;
     121            token.m_info.line = closeBraceLine;
     122            return token;
     123        }
     124
     125        int closeBraceLine;
     126        int closeBracePos;
     127        bool usesEval;
     128        Vector<RefPtr<StringImpl> > usedVariables;
     129        Vector<RefPtr<StringImpl> > writtenVariables;
    96130    };
    97131
     
    418452        bool isValidStrictMode() const { return m_isValidStrictMode; }
    419453        bool shadowsArguments() const { return m_shadowsArguments; }
     454       
     455        void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
     456        {
     457            IdentifierSet::iterator end = capturedVariables.end();
     458            for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
     459                if (m_declaredVariables.contains(*it))
     460                    continue;
     461                vector.append(*it);
     462            }
     463            vector.shrinkToFit();
     464        }
     465
     466        void saveFunctionInfo(CachedFunctionInfo* info)
     467        {
     468            ASSERT(m_isFunction);
     469            info->usesEval = m_usesEval;
     470            copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
     471            copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
     472        }
     473
     474        void restoreFunctionInfo(const CachedFunctionInfo* info)
     475        {
     476            ASSERT(m_isFunction);
     477            m_usesEval = info->usesEval;
     478            unsigned size = info->usedVariables.size();
     479            for (unsigned i = 0; i < size; ++i)
     480                m_usedVariables.add(info->usedVariables[i]);
     481            size = info->writtenVariables.size();
     482            for (unsigned i = 0; i < size; ++i)
     483                m_writtenVariables.add(info->writtenVariables[i]);
     484        }
    420485
    421486    private:
     
    544609
    545610    ScopeStack m_scopeStack;
     611
     612    const CachedFunctionInfo* findCachedFunctionInfo(int openBracePos)
     613    {
     614        return m_functionCache ? static_cast<const CachedFunctionInfo*>(m_functionCache->get(openBracePos)) : 0;
     615    }
     616
     617    SourceProviderCache* m_functionCache;
    546618};
    547619
     
    567639    , m_nonTrivialExpressionCount(0)
    568640    , m_lastIdentifier(0)
     641    , m_functionCache(m_lexer->sourceProvider()->cache())
    569642{
    570643    ScopeRef scope = pushScope();
     
    583656const char* JSParser::parseProgram()
    584657{
     658    unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
    585659    ASTBuilder context(m_globalData, m_lexer);
    586660    if (m_lexer->isReparsing())
     
    597671    if (scope->shadowsArguments())
    598672        features |= ShadowsArgumentsFeature;
     673   
     674    unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
     675    if (functionCacheSize != oldFunctionCacheSize)
     676        m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
    599677
    600678    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
     
    12401318    openBracePos = m_token.m_data.intValue;
    12411319    bodyStartLine = tokenLine();
     1320
     1321    if (const CachedFunctionInfo* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
     1322        // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
     1323        body = context.createFunctionBody(strictMode());
     1324
     1325        functionScope->restoreFunctionInfo(cachedInfo);
     1326        failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
     1327
     1328        closeBracePos = cachedInfo->closeBracePos;
     1329        m_token = cachedInfo->closeBraceToken();
     1330        m_lexer->setOffset(m_token.m_info.endOffset);
     1331        m_lexer->setLineNumber(m_token.m_info.line);
     1332
     1333        next();
     1334        return true;
     1335    }
     1336
    12421337    next();
    12431338
     
    12481343        failIfTrue(m_globalData->propertyNames->eval == *name);
    12491344    }
     1345    closeBracePos = m_token.m_data.intValue;
     1346   
     1347    // Cache the tokenizer state and the function scope the first time the function is parsed.
     1348    // Any future reparsing can then skip the function.
     1349    static const int minimumFunctionLengthToCache = 64;
     1350    OwnPtr<CachedFunctionInfo> newInfo;
     1351    int functionLength = closeBracePos - openBracePos;
     1352    if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
     1353        newInfo = adoptPtr(new CachedFunctionInfo(m_token.m_info.line, closeBracePos));
     1354        functionScope->saveFunctionInfo(newInfo.get());
     1355    }
     1356   
    12501357    failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
    12511358    matchOrFail(CLOSEBRACE);
    1252     closeBracePos = m_token.m_data.intValue;
     1359
     1360    if (newInfo)
     1361        m_functionCache->add(openBracePos, newInfo.release(), newInfo->approximateByteSize());
     1362
    12531363    next();
    12541364    return true;
  • trunk/Source/JavaScriptCore/parser/Lexer.h

    r75862 r76177  
    7474            m_buffer8.resize(0);
    7575            m_buffer16.resize(0);
     76            if (UNLIKELY(m_code == m_codeEnd))
     77                m_current = -1;
    7678        }
     79        void setLineNumber(int line)
     80        {
     81            m_lineNumber = line;
     82        }
     83
     84        SourceProvider* sourceProvider() const { return m_source->provider(); }
    7785
    7886    private:
  • trunk/Source/JavaScriptCore/parser/SourceProvider.h

    r76129 r76177  
    3131
    3232#include "UString.h"
     33#include <wtf/HashMap.h>
     34#include <wtf/PassOwnPtr.h>
    3335#include <wtf/RefCounted.h>
     36#include <wtf/UnusedParam.h>
    3437#include <wtf/text/TextPosition.h>
     38
    3539
    3640namespace JSC {
    3741
     42    class SourceProviderCache {
     43    public:
     44        struct Item {};
     45
     46        SourceProviderCache() : m_contentByteSize(0) {}
     47        ~SourceProviderCache() { deleteAllValues(m_map); }
     48       
     49        unsigned byteSize() const { return m_contentByteSize + sizeof(*this) + m_map.capacity() * sizeof(Item*); }
     50        void add(int sourcePosition, PassOwnPtr<Item> item, unsigned size) { m_map.add(sourcePosition, item.leakPtr()); m_contentByteSize += size; }
     51        const Item* get(int sourcePosition) const { return m_map.get(sourcePosition); }
     52
     53    private:
     54        HashMap<int, Item*> m_map;
     55        unsigned m_contentByteSize;
     56    };
     57
    3858    class SourceProvider : public RefCounted<SourceProvider> {
    3959    public:
    40         SourceProvider(const UString& url)
     60        SourceProvider(const UString& url, SourceProviderCache* cache = 0)
    4161            : m_url(url)
    4262            , m_validated(false)
     63            , m_cache(cache ? cache : new SourceProviderCache)
     64            , m_cacheOwned(!cache)
    4365        {
    4466        }
    45         virtual ~SourceProvider() { }
     67        virtual ~SourceProvider()
     68        {
     69            if (m_cacheOwned)
     70                delete m_cache;
     71        }
    4672
    4773        virtual UString getRange(int start, int end) const = 0;
     
    5682        void setValid() { m_validated = true; }
    5783
     84        SourceProviderCache* cache() const { return m_cache; }
     85        void notifyCacheSizeChanged(int delta) { if (!m_cacheOwned) cacheSizeChanged(delta); }
     86       
    5887    private:
     88        virtual void cacheSizeChanged(int delta) { UNUSED_PARAM(delta); }
     89
    5990        UString m_url;
    6091        bool m_validated;
     92        SourceProviderCache* m_cache;
     93        bool m_cacheOwned;
    6194    };
    6295
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r75896 r76177  
    113113    static const bool CreatesAST = false;
    114114    static const bool NeedsFreeVariableInfo = false;
     115    static const bool CanUseFunctionCache = true;
    115116
    116117    int createSourceElements() { return 1; }
  • trunk/Source/WebCore/ChangeLog

    r76175 r76177  
     12011-01-19  Antti Koivisto  <antti@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        Cache function offsets to speed up javascript parsing
     6        https://bugs.webkit.org/show_bug.cgi?id=52622
     7       
     8        Use cache to save function offsets and some other info.
     9        This avoids quite a bit of work when reparsing the source.
     10
     11        * bindings/js/CachedScriptSourceProvider.h:
     12        (WebCore::CachedScriptSourceProvider::cache):
     13        (WebCore::CachedScriptSourceProvider::cacheSizeChanged):
     14        (WebCore::CachedScriptSourceProvider::CachedScriptSourceProvider):
     15        * bindings/js/ScriptSourceProvider.h:
     16        (WebCore::ScriptSourceProvider::ScriptSourceProvider):
     17        * loader/cache/CachedScript.cpp:
     18        (WebCore::CachedScript::destroyDecodedData):
     19        (WebCore::CachedScript::sourceProviderCache):
     20        (WebCore::CachedScript::sourceProviderCacheSizeChanged):
     21        * loader/cache/CachedScript.h:
     22
    1232011-01-11  Martin Robinson  <mrobinson@igalia.com>
    224
  • trunk/Source/WebCore/bindings/js/CachedScriptSourceProvider.h

    r60275 r76177  
    5050        const String& source() const { return m_cachedScript->script(); }
    5151
     52        virtual void cacheSizeChanged(int delta)
     53        {
     54            m_cachedScript->sourceProviderCacheSizeChanged(delta);
     55        }
     56
    5257    private:
    5358        CachedScriptSourceProvider(CachedScript* cachedScript)
    54             : ScriptSourceProvider(stringToUString(cachedScript->url()))
     59            : ScriptSourceProvider(stringToUString(cachedScript->url()), cachedScript->sourceProviderCache())
    5560            , m_cachedScript(cachedScript)
    5661        {
  • trunk/Source/WebCore/bindings/js/ScriptSourceProvider.h

    r65021 r76177  
    3535    class ScriptSourceProvider : public JSC::SourceProvider {
    3636    public:
    37         ScriptSourceProvider(const JSC::UString& url)
    38             : SourceProvider(url)
     37        ScriptSourceProvider(const JSC::UString& url, JSC::SourceProviderCache* cache = 0)
     38            : SourceProvider(url, cache)
    3939        {
    4040        }
  • trunk/Source/WebCore/loader/cache/CachedScript.cpp

    r72230 r76177  
    3434#include "TextResourceDecoder.h"
    3535#include <wtf/Vector.h>
     36
     37#if USE(JSC) 
     38#include <parser/SourceProvider.h>
     39#endif
    3640
    3741namespace WebCore {
     
    112116{
    113117    m_script = String();
    114     setDecodedSize(0);
     118    unsigned extraSize = 0;
     119#if USE(JSC)
     120    // FIXME: SourceInfoCache should be wiped out too but not this easily.
     121    extraSize = m_sourceProviderCache ? m_sourceProviderCache->byteSize() : 0;
     122#endif
     123    setDecodedSize(extraSize);
    115124    if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
    116125        makePurgeable(true);
     
    122131}
    123132
     133#if USE(JSC)
     134JSC::SourceProviderCache* CachedScript::sourceProviderCache() const
     135{   
     136    if (!m_sourceProviderCache)
     137        m_sourceProviderCache = adoptPtr(new JSC::SourceProviderCache);
     138    return m_sourceProviderCache.get();
     139}
     140
     141void CachedScript::sourceProviderCacheSizeChanged(int delta)
     142{
     143    setDecodedSize(decodedSize() + delta);
     144}
     145#endif
     146
    124147} // namespace WebCore
  • trunk/Source/WebCore/loader/cache/CachedScript.h

    r72230 r76177  
    3030#include "Timer.h"
    3131
     32#if USE(JSC)
     33namespace JSC {
     34    class SourceProviderCache;
     35}
     36#endif
     37
    3238namespace WebCore {
    3339
     
    5258
    5359        virtual void destroyDecodedData();
    54 
     60#if USE(JSC)       
     61        // Allows JSC to cache additional information about the source.
     62        JSC::SourceProviderCache* sourceProviderCache() const;
     63        void sourceProviderCacheSizeChanged(int delta);
     64#endif
    5565    private:
    5666        void decodedDataDeletionTimerFired(Timer<CachedScript>*);
     
    6070        RefPtr<TextResourceDecoder> m_decoder;
    6171        Timer<CachedScript> m_decodedDataDeletionTimer;
     72#if USE(JSC)       
     73        mutable OwnPtr<JSC::SourceProviderCache> m_sourceProviderCache;
     74#endif
    6275    };
    6376}
Note: See TracChangeset for help on using the changeset viewer.