1 // Copyright 2017 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_OBJECTS_COMPILATION_CACHE_TABLE_H_ 6 #define V8_OBJECTS_COMPILATION_CACHE_TABLE_H_ 7 8 #include "src/objects/feedback-cell.h" 9 #include "src/objects/hash-table.h" 10 #include "src/objects/js-regexp.h" 11 #include "src/objects/shared-function-info.h" 12 #include "src/roots/roots.h" 13 14 // Has to be the last include (doesn't have include guards): 15 #include "src/objects/object-macros.h" 16 17 namespace v8 { 18 namespace internal { 19 20 class CompilationCacheShape : public BaseShape<HashTableKey*> { 21 public: IsMatch(HashTableKey* key, Object value)22 static inline bool IsMatch(HashTableKey* key, Object value) { 23 return key->IsMatch(value); 24 } 25 Hash(ReadOnlyRoots roots, HashTableKey* key)26 static inline uint32_t Hash(ReadOnlyRoots roots, HashTableKey* key) { 27 return key->Hash(); 28 } 29 30 static inline uint32_t RegExpHash(String string, Smi flags); 31 32 static inline uint32_t StringSharedHash(String source, 33 SharedFunctionInfo shared, 34 LanguageMode language_mode, 35 int position); 36 37 static inline uint32_t StringSharedHash(String source, 38 LanguageMode language_mode); 39 40 static inline uint32_t HashForObject(ReadOnlyRoots roots, Object object); 41 42 static const int kPrefixSize = 0; 43 // An 'entry' is essentially a grouped collection of slots. Entries are used 44 // in various ways by the different caches; most store the actual key in the 45 // first entry slot, but it may also be used differently. 46 // Why 3 slots? Because of the eval cache. 47 static const int kEntrySize = 3; 48 static const bool kMatchNeedsHoleCheck = true; 49 }; 50 51 class InfoCellPair { 52 public: 53 InfoCellPair() = default; 54 inline InfoCellPair(Isolate* isolate, SharedFunctionInfo shared, 55 FeedbackCell feedback_cell); 56 feedback_cell() const57 FeedbackCell feedback_cell() const { 58 DCHECK(is_compiled_scope_.is_compiled()); 59 return feedback_cell_; 60 } shared() const61 SharedFunctionInfo shared() const { 62 DCHECK(is_compiled_scope_.is_compiled()); 63 return shared_; 64 } 65 has_feedback_cell() const66 bool has_feedback_cell() const { 67 return !feedback_cell_.is_null() && is_compiled_scope_.is_compiled(); 68 } has_shared() const69 bool has_shared() const { 70 // Only return true if SFI is compiled - the bytecode could have been 71 // flushed while it's in the compilation cache, and not yet have been 72 // removed form the compilation cache. 73 return !shared_.is_null() && is_compiled_scope_.is_compiled(); 74 } 75 76 private: 77 IsCompiledScope is_compiled_scope_; 78 SharedFunctionInfo shared_; 79 FeedbackCell feedback_cell_; 80 }; 81 82 EXTERN_DECLARE_HASH_TABLE(CompilationCacheTable, CompilationCacheShape) 83 84 class CompilationCacheTable 85 : public HashTable<CompilationCacheTable, CompilationCacheShape> { 86 public: 87 NEVER_READ_ONLY_SPACE 88 89 // The 'script' cache contains SharedFunctionInfos. 90 static MaybeHandle<SharedFunctionInfo> LookupScript( 91 Handle<CompilationCacheTable> table, Handle<String> src, 92 LanguageMode language_mode, Isolate* isolate); 93 static Handle<CompilationCacheTable> PutScript( 94 Handle<CompilationCacheTable> cache, Handle<String> src, 95 LanguageMode language_mode, Handle<SharedFunctionInfo> value, 96 Isolate* isolate); 97 98 // Eval code only gets cached after a second probe for the 99 // code object. To do so, on first "put" only a hash identifying the 100 // source is entered into the cache, mapping it to a lifetime count of 101 // the hash. On each call to Age all such lifetimes get reduced, and 102 // removed once they reach zero. If a second put is called while such 103 // a hash is live in the cache, the hash gets replaced by an actual 104 // cache entry. Age also removes stale live entries from the cache. 105 // Such entries are identified by SharedFunctionInfos pointing to 106 // either the recompilation stub, or to "old" code. This avoids memory 107 // leaks due to premature caching of eval strings that are 108 // never needed later. 109 static InfoCellPair LookupEval(Handle<CompilationCacheTable> table, 110 Handle<String> src, 111 Handle<SharedFunctionInfo> shared, 112 Handle<Context> native_context, 113 LanguageMode language_mode, int position); 114 static Handle<CompilationCacheTable> PutEval( 115 Handle<CompilationCacheTable> cache, Handle<String> src, 116 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, 117 Handle<Context> native_context, Handle<FeedbackCell> feedback_cell, 118 int position); 119 120 // The RegExp cache contains JSRegExp::data fixed arrays. 121 Handle<Object> LookupRegExp(Handle<String> source, JSRegExp::Flags flags); 122 static Handle<CompilationCacheTable> PutRegExp( 123 Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src, 124 JSRegExp::Flags flags, Handle<FixedArray> value); 125 126 void Remove(Object value); 127 void Age(Isolate* isolate); 128 129 DECL_CAST(CompilationCacheTable) 130 131 private: 132 void RemoveEntry(int entry_index); 133 134 OBJECT_CONSTRUCTORS(CompilationCacheTable, 135 HashTable<CompilationCacheTable, CompilationCacheShape>); 136 }; 137 138 } // namespace internal 139 } // namespace v8 140 141 #include "src/objects/object-macros-undef.h" 142 143 #endif // V8_OBJECTS_COMPILATION_CACHE_TABLE_H_ 144