Changeset 133975 in webkit


Ignore:
Timestamp:
Nov 8, 2012 5:12:47 PM (11 years ago)
Author:
oliver@apple.com
Message:

Improve effectiveness of function-level caching
https://bugs.webkit.org/show_bug.cgi?id=101667

Reviewed by Filip Pizlo.

Added a random-eviction based cache for unlinked functions, and switch
UnlinkedFunctionExecutable's code references to Weak<>, thereby letting
us remove the explicit UnlinkedFunctionExecutable::clearCode() calls that
were being triggered by GC.

Refactored the random eviction part of the CodeCache into a separate data
structure so that I didn't have to duplicate the code again, and then used
that for the new function cache.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedFunctionExecutable::visitChildren):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedFunctionExecutable::clearCodeForRecompilation):
(UnlinkedFunctionExecutable):

  • debugger/Debugger.cpp:
  • runtime/CodeCache.cpp:

(JSC::CodeCache::getCodeBlock):
(JSC::CodeCache::generateFunctionCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):
(JSC::CodeCache::usedFunctionCode):
(JSC):

  • runtime/Executable.cpp:

(JSC::FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling):
(JSC::FunctionExecutable::clearCode):

  • runtime/Executable.h:

(FunctionExecutable):

Location:
trunk/Source/JavaScriptCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r133971 r133975  
     12012-11-08  Oliver Hunt  <oliver@apple.com>
     2
     3        Improve effectiveness of function-level caching
     4        https://bugs.webkit.org/show_bug.cgi?id=101667
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Added a random-eviction based cache for unlinked functions, and switch
     9        UnlinkedFunctionExecutable's code references to Weak<>, thereby letting
     10        us remove the explicit UnlinkedFunctionExecutable::clearCode() calls that
     11        were being triggered by GC.
     12
     13        Refactored the random eviction part of the CodeCache into a separate data
     14        structure so that I didn't have to duplicate the code again, and then used
     15        that for the new function cache.
     16
     17        * bytecode/UnlinkedCodeBlock.cpp:
     18        (JSC::UnlinkedFunctionExecutable::visitChildren):
     19        (JSC::UnlinkedFunctionExecutable::codeBlockFor):
     20        * bytecode/UnlinkedCodeBlock.h:
     21        (JSC::UnlinkedFunctionExecutable::clearCodeForRecompilation):
     22        (UnlinkedFunctionExecutable):
     23        * debugger/Debugger.cpp:
     24        * runtime/CodeCache.cpp:
     25        (JSC::CodeCache::getCodeBlock):
     26        (JSC::CodeCache::generateFunctionCodeBlock):
     27        (JSC::CodeCache::getFunctionExecutableFromGlobalCode):
     28        (JSC::CodeCache::usedFunctionCode):
     29        (JSC):
     30        * runtime/Executable.cpp:
     31        (JSC::FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling):
     32        (JSC::FunctionExecutable::clearCode):
     33        * runtime/Executable.h:
     34        (FunctionExecutable):
     35
    1362012-11-07  Filip Pizlo  <fpizlo@apple.com>
    237
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp

    r133953 r133975  
    8181    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
    8282    Base::visitChildren(thisObject, visitor);
    83     visitor.append(&thisObject->m_codeBlockForCall);
    84     visitor.append(&thisObject->m_codeBlockForConstruct);
    8583    visitor.append(&thisObject->m_nameValue);
    8684    visitor.append(&thisObject->m_symbolTableForCall);
     
    113111    switch (specializationKind) {
    114112    case CodeForCall:
    115         if (m_codeBlockForCall)
    116             return m_codeBlockForCall.get();
     113        if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) {
     114            globalData.codeCache()->usedFunctionCode(globalData, codeBlock);
     115            return codeBlock;
     116        }
    117117        break;
    118118    case CodeForConstruct:
    119         if (m_codeBlockForConstruct)
    120             return m_codeBlockForConstruct.get();
     119        if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) {
     120            globalData.codeCache()->usedFunctionCode(globalData, codeBlock);
     121            return codeBlock;
     122        }
    121123        break;
    122124    }
     
    129131    switch (specializationKind) {
    130132    case CodeForCall:
    131         m_codeBlockForCall.set(globalData, this, result);
     133        m_codeBlockForCall = PassWeak<UnlinkedFunctionCodeBlock>(result);
    132134        m_symbolTableForCall.set(globalData, this, result->symbolTable());
    133135        break;
    134136    case CodeForConstruct:
    135         m_codeBlockForConstruct.set(globalData, this, result);
     137        m_codeBlockForConstruct = PassWeak<UnlinkedFunctionCodeBlock>(result);
    136138        m_symbolTableForConstruct.set(globalData, this, result->symbolTable());
    137139        break;
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h

    r133953 r133975  
    3737#include "RegExp.h"
    3838#include "SpecialPointer.h"
     39#include "Weak.h"
    3940
    4041#include <wtf/RefCountedArray.h>
     
    109110    FunctionExecutable* link(JSGlobalData&, const SourceCode&, size_t lineOffset, size_t sourceOffset);
    110111
    111     void clearCode()
     112    void clearCodeForRecompilation()
    112113    {
    113114        m_symbolTableForCall.clear();
     
    137138private:
    138139    UnlinkedFunctionExecutable(JSGlobalData*, Structure*, const SourceCode&, FunctionBodyNode*);
    139     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
    140     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
     140    Weak<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
     141    Weak<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
    141142
    142143    unsigned m_numCapturedVariables : 29;
  • trunk/Source/JavaScriptCore/debugger/Debugger.cpp

    r133688 r133975  
    8181    ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec();
    8282    executable->clearCodeIfNotCompiling();
    83     executable->clearUnlinkedCodeIfNotCompiling();
     83    executable->clearUnlinkedCodeForRecompilationIfNotCompiling();
    8484    if (m_debugger == function->scope()->globalObject()->debugger())
    8585        m_sourceProviders.add(executable->source().provider(), exec);
  • trunk/Source/JavaScriptCore/runtime/CodeCache.cpp

    r133688 r133975  
    3737
    3838CodeCache::CodeCache()
    39     : m_randomGenerator(static_cast<uint32_t>(randomNumber() * UINT32_MAX))
    4039{
    4140}
     
    6867    bool storeInCache = false;
    6968    if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) {
    70         CodeBlockIndicesMap::iterator result = m_cachedCodeBlockIndices.find(key);
    71         if (result != m_cachedCodeBlockIndices.end()) {
    72             UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(m_cachedCodeBlocks[result->value].second.get());
     69        const Strong<UnlinkedCodeBlock>* result = m_cachedCodeBlocks.find(key);
     70        if (result) {
     71            UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get());
    7372            unsigned firstLine = source.firstLine() + unlinkedCode->firstLine();
    7473            executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount());
     
    9291        return 0;
    9392
    94     if (storeInCache) {
    95         size_t index = m_randomGenerator.getUint32() % kMaxCodeBlockEntries;
    96         if (m_cachedCodeBlocks[index].second)
    97             m_cachedCodeBlockIndices.remove(m_cachedCodeBlocks[index].first);
    98         m_cachedCodeBlockIndices.set(key, index);
    99         m_cachedCodeBlocks[index].second.set(globalData, unlinkedCode);
    100         m_cachedCodeBlocks[index].first = key;
    101     }
     93    if (storeInCache)
     94        m_cachedCodeBlocks.add(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode));
    10295
    10396    return unlinkedCode;
     
    134127    if (error.m_type != ParserError::ErrorNone)
    135128        return 0;
     129    m_cachedFunctionCode.add(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result));
    136130    return result;
    137131}
     
    150144{
    151145    GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string());
    152     GlobalFunctionIndicesMap::iterator result = m_cachedGlobalFunctionIndices.find(key);
    153     if (result != m_cachedGlobalFunctionIndices.end())
    154         return m_cachedGlobalFunctions[result->value].second.get();
     146    const Strong<UnlinkedFunctionExecutable>* result = m_cachedGlobalFunctions.find(key);
     147    if (result)
     148        return result->get();
    155149
    156150    RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error);
     
    174168    functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string()));
    175169
    176     size_t index = m_randomGenerator.getUint32() % kMaxGlobalFunctionEntries;
    177     if (m_cachedGlobalFunctions[index].second)
    178         m_cachedGlobalFunctionIndices.remove(m_cachedGlobalFunctions[index].first);
    179     m_cachedGlobalFunctionIndices.set(key, index);
    180     m_cachedGlobalFunctions[index].second.set(globalData, functionExecutable);
    181     m_cachedGlobalFunctions[index].first = key;
    182 
     170    m_cachedGlobalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable));
    183171    return functionExecutable;
    184172}
    185173
     174void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock)
     175{
     176    m_cachedFunctionCode.add(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock));
    186177}
     178
     179}
  • trunk/Source/JavaScriptCore/runtime/CodeCache.h

    r133688 r133975  
    3535#include <wtf/Forward.h>
    3636#include <wtf/PassOwnPtr.h>
     37#include <wtf/RandomNumber.h>
    3738#include <wtf/text/WTFString.h>
    3839
     
    5253class SourceProvider;
    5354
     55template <typename KeyType, typename EntryType, int CacheSize> class Thingy {
     56    typedef typename HashMap<KeyType, unsigned>::iterator iterator;
     57public:
     58    Thingy()
     59    : m_randomGenerator((static_cast<uint32_t>(randomNumber() * UINT32_MAX)))
     60    {
     61    }
     62    const EntryType* find(const KeyType& key)
     63    {
     64        iterator result = m_map.find(key);
     65        if (result == m_map.end())
     66            return 0;
     67        return &m_data[result->value].second;
     68    }
     69    void add(const KeyType& key, const EntryType& value)
     70    {
     71        iterator result = m_map.find(key);
     72        if (result != m_map.end()) {
     73            m_data[result->value].second = value;
     74            return;
     75        }
     76        size_t newIndex = m_randomGenerator.getUint32() % CacheSize;
     77        if (m_data[newIndex].second)
     78            m_map.remove(m_data[newIndex].first);
     79        m_map.add(key, newIndex);
     80        m_data[newIndex].first = key;
     81        m_data[newIndex].second = value;
     82        ASSERT(m_map.size() <= CacheSize);
     83    }
     84private:
     85    HashMap<KeyType, unsigned> m_map;
     86    FixedArray<std::pair<KeyType, EntryType>, CacheSize> m_data;
     87    WeakRandom m_randomGenerator;
     88};
     89
    5490class CodeCache {
    5591public:
     
    6096    UnlinkedFunctionCodeBlock* getFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
    6197    UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&);
     98    void usedFunctionCode(JSGlobalData&, UnlinkedFunctionCodeBlock*);
    6299    ~CodeCache();
    63100
    64101    enum CodeType { EvalType, ProgramType, FunctionType };
    65102    typedef std::pair<String, unsigned> CodeBlockKey;
    66     typedef HashMap<CodeBlockKey, unsigned> CodeBlockIndicesMap;
    67103    typedef std::pair<String, String> GlobalFunctionKey;
    68     typedef HashMap<GlobalFunctionKey, unsigned> GlobalFunctionIndicesMap;
    69104
    70105private:
     
    75110    template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
    76111    CodeBlockKey makeCodeBlockKey(const SourceCode&, CodeType, JSParserStrictness);
    77     CodeBlockIndicesMap m_cachedCodeBlockIndices;
    78112    GlobalFunctionKey makeGlobalFunctionKey(const SourceCode&, const String&);
    79     GlobalFunctionIndicesMap m_cachedGlobalFunctionIndices;
    80113
    81114    enum {
    82115        kMaxCodeBlockEntries = 1024,
    83         kMaxGlobalFunctionEntries = 1024
     116        kMaxGlobalFunctionEntries = 1024,
     117        kMaxFunctionCodeBlocks = 1024
    84118    };
    85119
    86     FixedArray<std::pair<CodeBlockKey, Strong<UnlinkedCodeBlock> >, kMaxCodeBlockEntries> m_cachedCodeBlocks;
    87     FixedArray<std::pair<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable> >, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
    88     WeakRandom m_randomGenerator;
     120    Thingy<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks;
     121    Thingy<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
     122    Thingy<UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock>, kMaxFunctionCodeBlocks> m_cachedFunctionCode;
    89123};
    90124
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r133688 r133975  
    621621}
    622622
    623 void FunctionExecutable::clearUnlinkedCodeIfNotCompiling()
     623void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling()
    624624{
    625625    if (isCompiling())
    626626        return;
    627     m_unlinkedExecutable->clearCode();
     627    m_unlinkedExecutable->clearCodeForRecompilation();
    628628}
    629629
     
    632632    m_codeBlockForCall.clear();
    633633    m_codeBlockForConstruct.clear();
    634     m_unlinkedExecutable->clearCode();
    635634    Base::clearCode();
    636635}
  • trunk/Source/JavaScriptCore/runtime/Executable.h

    r133688 r133975  
    705705
    706706        void clearCodeIfNotCompiling();
    707         void clearUnlinkedCodeIfNotCompiling();
     707        void clearUnlinkedCodeForRecompilationIfNotCompiling();
    708708        static void visitChildren(JSCell*, SlotVisitor&);
    709709        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
Note: See TracChangeset for help on using the changeset viewer.