Changeset 142966 in webkit
- Timestamp:
- Feb 14, 2013 10:41:10 PM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r142923 r142966 1 2013-02-14 Geoffrey Garen <ggaren@apple.com> 2 3 Merged the global function cache into the source code cache 4 https://bugs.webkit.org/show_bug.cgi?id=108660 5 6 Reviewed by Sam Weinig. 7 8 This has a few benefits: 9 10 (*) Saves a few kB by removing a second cache data structure. 11 12 (*) Reduces the worst case memory usage of the cache by 1.75X. (Heavy 13 use of 'new Function' and other techniques could cause us to fill 14 both root caches, and they didn't trade off against each other.) 15 16 (*) Paves the way for future improvements based on a non-trivial 17 cache key (for example, shrinkable pointer to the key string, and 18 more precise cache size accounting). 19 20 Also cleaned up the cache implementation and simplified it a bit. 21 22 * heap/Handle.h: 23 (HandleBase): 24 * heap/Strong.h: 25 (Strong): Build! 26 27 * runtime/CodeCache.cpp: 28 (JSC): 29 (JSC::CodeCache::getCodeBlock): 30 (JSC::CodeCache::generateFunctionCodeBlock): 31 (JSC::CodeCache::getFunctionExecutableFromGlobalCode): 32 (JSC::CodeCache::usedFunctionCode): Updated for three interface changes: 33 34 (*) SourceCodeKey is a class, not a pair. 35 36 (*) Table values are abstract pointers, since they can be executables 37 or code blocks. (In a future patch, I'd like to change this so we 38 always store only code blocks. But that's too much for one patch.) 39 40 (*) The cache function is named "set" because it always overwrites 41 unconditionally. 42 43 * runtime/CodeCache.h: 44 (CacheMap): 45 (JSC::CacheMap::find): 46 (JSC::CacheMap::set): 47 (JSC::CacheMap::clear): Added support for specifying hash traits, so we 48 can use a SourceCodeKey. 49 50 Removed side table and random number generator to save space and reduce 51 complexity. Hash tables are already random, so we don't need another source 52 of randomness. 53 54 (SourceCodeKey): 55 (JSC::SourceCodeKey::SourceCodeKey): 56 (JSC::SourceCodeKey::isHashTableDeletedValue): 57 (JSC::SourceCodeKey::hash): 58 (JSC::SourceCodeKey::isNull): 59 (JSC::SourceCodeKey::operator==): 60 (JSC::SourceCodeKeyHash::hash): 61 (JSC::SourceCodeKeyHash::equal): 62 (SourceCodeKeyHash): 63 (SourceCodeKeyHashTraits): 64 (JSC::SourceCodeKeyHashTraits::isEmptyValue): A SourceCodeKey is just a 65 fancy triplet: source code string; function name (or null, for non-functions); 66 and flags. Flags and function name distinguish between functions and programs 67 with identical code, so they can live in the same cache. 68 69 I chose to use the source code string as the primary hashing reference 70 because it's likely to be unique. We can use profiling to choose another 71 technique in future, if collisions between functions and programs prove 72 to be hot. I suspect they won't. 73 74 (JSC::CodeCache::clear): 75 (CodeCache): Removed the second cache. 76 77 * heap/Handle.h: 78 (HandleBase): 79 * heap/Strong.h: 80 (Strong): 81 * runtime/CodeCache.cpp: 82 (JSC): 83 (JSC::CodeCache::getCodeBlock): 84 (JSC::CodeCache::generateFunctionCodeBlock): 85 (JSC::CodeCache::getFunctionExecutableFromGlobalCode): 86 (JSC::CodeCache::usedFunctionCode): 87 * runtime/CodeCache.h: 88 (JSC): 89 (CacheMap): 90 (JSC::CacheMap::find): 91 (JSC::CacheMap::set): 92 (JSC::CacheMap::clear): 93 (SourceCodeKey): 94 (JSC::SourceCodeKey::SourceCodeKey): 95 (JSC::SourceCodeKey::isHashTableDeletedValue): 96 (JSC::SourceCodeKey::hash): 97 (JSC::SourceCodeKey::isNull): 98 (JSC::SourceCodeKey::operator==): 99 (JSC::SourceCodeKeyHash::hash): 100 (JSC::SourceCodeKeyHash::equal): 101 (SourceCodeKeyHash): 102 (SourceCodeKeyHashTraits): 103 (JSC::SourceCodeKeyHashTraits::isEmptyValue): 104 (JSC::CodeCache::clear): 105 (CodeCache): 106 1 107 2013-02-14 Tony Chang <tony@chromium.org> 2 108 -
trunk/Source/JavaScriptCore/heap/Handle.h
r140194 r142966 46 46 class HandleBase { 47 47 template <typename T> friend class Weak; 48 template <typename T> friend class Strong; 48 49 friend class HandleSet; 49 50 friend struct JSCallbackObjectData; -
trunk/Source/JavaScriptCore/heap/Strong.h
r113508 r142966 39 39 using Handle<T>::slot; 40 40 using Handle<T>::setSlot; 41 template <typename U> friend class Strong; 41 42 42 43 public: -
trunk/Source/JavaScriptCore/runtime/CodeCache.cpp
r140619 r142966 45 45 } 46 46 47 CodeCache::SourceCodeKey CodeCache::makeSourceCodeKey(const SourceCode& source, CodeCache::CodeType type, JSParserStrictness strictness)48 {49 return std::make_pair(source.toString(), (type << 1) | strictness);50 }51 52 47 template <typename T> struct CacheTypes { }; 53 48 54 49 template <> struct CacheTypes<UnlinkedProgramCodeBlock> { 55 50 typedef JSC::ProgramNode RootNode; 56 static const CodeCache::CodeType codeType = CodeCache::ProgramType;51 static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType; 57 52 }; 58 53 59 54 template <> struct CacheTypes<UnlinkedEvalCodeBlock> { 60 55 typedef JSC::EvalNode RootNode; 61 static const CodeCache::CodeType codeType = CodeCache::EvalType;56 static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType; 62 57 }; 63 58 … … 65 60 UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) 66 61 { 67 SourceCodeKey key = makeSourceCodeKey(source, CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);62 SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness); 68 63 bool storeInCache = false; 69 64 if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) { 70 const Strong< UnlinkedCodeBlock>* result = m_sourceCode.find(key);65 const Strong<JSCell>* result = m_sourceCode.find(key); 71 66 if (result) { 72 67 UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get()); … … 93 88 94 89 if (storeInCache) 95 m_sourceCode. add(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode));90 m_sourceCode.set(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode)); 96 91 97 92 return unlinkedCode; … … 128 123 if (error.m_type != ParserError::ErrorNone) 129 124 return 0; 130 m_recentlyUsedFunctions. add(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result));125 m_recentlyUsedFunctions.set(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result)); 131 126 return result; 132 127 } … … 137 132 } 138 133 139 CodeCache::FunctionKey CodeCache::makeFunctionKey(const SourceCode& source, const String& name)140 {141 return FunctionKey(source.toString(), name);142 }143 144 134 UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error) 145 135 { 146 FunctionKey key = makeFunctionKey(source, name.string());147 const Strong< UnlinkedFunctionExecutable>* result = m_globalFunctions.find(key);136 SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionCallType, JSParseNormal); 137 const Strong<JSCell>* result = m_sourceCode.find(key); 148 138 if (result) 149 return result->get();139 return jsCast<UnlinkedFunctionExecutable*>(result->get()); 150 140 151 141 RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); … … 169 159 functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); 170 160 171 m_ globalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable));161 m_sourceCode.set(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable)); 172 162 return functionExecutable; 173 163 } … … 175 165 void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock) 176 166 { 177 m_recentlyUsedFunctions. add(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock));167 m_recentlyUsedFunctions.set(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock)); 178 168 } 179 169 -
trunk/Source/JavaScriptCore/runtime/CodeCache.h
r140619 r142966 29 29 #include "CodeSpecializationKind.h" 30 30 #include "ParserModes.h" 31 #include "SourceCode.h" 31 32 #include "Strong.h" 32 33 #include "WeakRandom.h" 33 34 34 #include <wtf/FixedArray.h> 35 35 #include <wtf/Forward.h> … … 54 54 class SourceProvider; 55 55 56 template <typename KeyType, typename EntryType, int CacheSize> class CacheMap { 57 typedef typename HashMap<KeyType, unsigned>::iterator iterator; 56 template <int CacheSize, typename KeyType, typename EntryType, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> > 57 class CacheMap { 58 typedef HashMap<KeyType, EntryType, HashArg, KeyTraitsArg> MapType; 59 typedef typename MapType::iterator iterator; 60 58 61 public: 59 CacheMap()60 : m_randomGenerator((static_cast<uint32_t>(randomNumber() * std::numeric_limits<uint32_t>::max())))61 {62 }63 62 const EntryType* find(const KeyType& key) 64 63 { … … 66 65 if (result == m_map.end()) 67 66 return 0; 68 return &m_data[result->value].second; 69 } 70 void add(const KeyType& key, const EntryType& value) 71 { 72 iterator result = m_map.find(key); 73 if (result != m_map.end()) { 74 m_data[result->value].second = value; 75 return; 76 } 77 size_t newIndex = m_randomGenerator.getUint32() % CacheSize; 78 if (m_data[newIndex].second) 79 m_map.remove(m_data[newIndex].first); 80 m_map.add(key, newIndex); 81 m_data[newIndex].first = key; 82 m_data[newIndex].second = value; 83 RELEASE_ASSERT(m_map.size() <= CacheSize); 67 return &result->value; 84 68 } 85 69 86 void clear()70 void set(const KeyType& key, const EntryType& value) 87 71 { 88 m_map.clear(); 89 for (size_t i = 0; i < CacheSize; i++) { 90 m_data[i].first = KeyType(); 91 m_data[i].second = EntryType(); 92 } 72 if (m_map.size() >= CacheSize) 73 m_map.remove(m_map.begin()); 74 75 m_map.set(key, value); 93 76 } 94 77 78 void clear() { m_map.clear(); } 95 79 96 80 private: 97 HashMap<KeyType, unsigned> m_map; 98 FixedArray<std::pair<KeyType, EntryType>, CacheSize> m_data; 99 WeakRandom m_randomGenerator; 81 MapType m_map; 82 }; 83 84 class SourceCodeKey { 85 public: 86 enum CodeType { EvalType, ProgramType, FunctionCallType, FunctionConstructType }; 87 88 SourceCodeKey() 89 : m_flags(0) 90 { 91 } 92 93 SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserStrictness jsParserStrictness) 94 : m_sourceString(sourceCode.toString()) 95 , m_name(name) 96 , m_flags((codeType << 1) | jsParserStrictness) 97 { 98 } 99 100 SourceCodeKey(WTF::HashTableDeletedValueType) 101 : m_sourceString(WTF::HashTableDeletedValue) 102 , m_name(WTF::HashTableDeletedValue) 103 , m_flags(0) 104 { 105 } 106 107 bool isHashTableDeletedValue() const { return m_sourceString.isHashTableDeletedValue(); } 108 109 unsigned hash() const { return m_sourceString.impl()->hash(); } 110 111 bool isNull() const { return m_sourceString.isNull(); } 112 113 bool operator==(const SourceCodeKey& other) const 114 { 115 return m_flags == other.m_flags 116 && m_name == other.m_name 117 && m_sourceString == other.m_sourceString; 118 } 119 120 private: 121 String m_sourceString; 122 String m_name; 123 unsigned m_flags; 124 }; 125 126 struct SourceCodeKeyHash { 127 static unsigned hash(const SourceCodeKey& key) { return key.hash(); } 128 static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; } 129 static const bool safeToCompareToEmptyOrDeleted = false; 130 }; 131 132 struct SourceCodeKeyHashTraits : WTF::SimpleClassHashTraits<SourceCodeKey> { 133 static const bool hasIsEmptyValueFunction = true; 134 static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); } 100 135 }; 101 136 … … 114 149 { 115 150 m_sourceCode.clear(); 116 m_globalFunctions.clear();117 151 m_recentlyUsedFunctions.clear(); 118 152 } 119 120 enum CodeType { EvalType, ProgramType, FunctionCallType, FunctionConstructType };121 typedef std::pair<String, unsigned> SourceCodeKey;122 typedef std::pair<String, String> FunctionKey;123 153 124 154 private: … … 128 158 129 159 template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); 130 SourceCodeKey makeSourceCodeKey(const SourceCode&, CodeType, JSParserStrictness);131 FunctionKey makeFunctionKey(const SourceCode&, const String&);132 160 133 161 enum { 134 MaxRootEntries = 1 024, // Top-level code such as <script>, eval(), JSEvaluateScript(), etc.162 MaxRootEntries = 1280, // Top-level code such as <script>, eval(), JSEvaluateScript(), etc. 135 163 MaxChildFunctionEntries = MaxRootEntries * 8 // Sampling shows that each root holds about 6 functions. 8 is enough to usually cache all the child functions for each top-level entry. 136 164 }; 137 165 138 CacheMap<SourceCodeKey, Strong<UnlinkedCodeBlock>, MaxRootEntries> m_sourceCode; 139 CacheMap<FunctionKey, Strong<UnlinkedFunctionExecutable>, MaxRootEntries> m_globalFunctions; 140 CacheMap<UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock>, MaxChildFunctionEntries> m_recentlyUsedFunctions; 166 CacheMap<MaxRootEntries, SourceCodeKey, Strong<JSCell>, SourceCodeKeyHash, SourceCodeKeyHashTraits> m_sourceCode; 167 CacheMap<MaxChildFunctionEntries, UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock> > m_recentlyUsedFunctions; 141 168 }; 142 169 143 170 } 144 171 145 #endif 172 #endif // CodeCache_h
Note: See TracChangeset
for help on using the changeset viewer.