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 HashForObject(ReadOnlyRoots roots, Object object);
38
39 static const int kPrefixSize = 0;
40 // An 'entry' is essentially a grouped collection of slots. Entries are used
41 // in various ways by the different caches; most store the actual key in the
42 // first entry slot, but it may also be used differently.
43 // Why 3 slots? Because of the eval cache.
44 static const int kEntrySize = 3;
45 static const bool kMatchNeedsHoleCheck = true;
46 };
47
48 class InfoCellPair {
49 public:
50 InfoCellPair() = default;
51 inline InfoCellPair(Isolate* isolate, SharedFunctionInfo shared,
52 FeedbackCell feedback_cell);
53
feedback_cell()54 FeedbackCell feedback_cell() const {
55 DCHECK(is_compiled_scope_.is_compiled());
56 return feedback_cell_;
57 }
shared()58 SharedFunctionInfo shared() const {
59 DCHECK(is_compiled_scope_.is_compiled());
60 return shared_;
61 }
62
has_feedback_cell()63 bool has_feedback_cell() const {
64 return !feedback_cell_.is_null() && is_compiled_scope_.is_compiled();
65 }
has_shared()66 bool has_shared() const {
67 // Only return true if SFI is compiled - the bytecode could have been
68 // flushed while it's in the compilation cache, and not yet have been
69 // removed form the compilation cache.
70 return !shared_.is_null() && is_compiled_scope_.is_compiled();
71 }
72
73 private:
74 IsCompiledScope is_compiled_scope_;
75 SharedFunctionInfo shared_;
76 FeedbackCell feedback_cell_;
77 };
78
EXTERN_DECLARE_HASH_TABLE(CompilationCacheTable,CompilationCacheShape)79 EXTERN_DECLARE_HASH_TABLE(CompilationCacheTable, CompilationCacheShape)
80
81 class CompilationCacheTable
82 : public HashTable<CompilationCacheTable, CompilationCacheShape> {
83 public:
84 NEVER_READ_ONLY_SPACE
85
86 // The 'script' cache contains SharedFunctionInfos.
87 static MaybeHandle<SharedFunctionInfo> LookupScript(
88 Handle<CompilationCacheTable> table, Handle<String> src,
89 Handle<Context> native_context, LanguageMode language_mode);
90 static Handle<CompilationCacheTable> PutScript(
91 Handle<CompilationCacheTable> cache, Handle<String> src,
92 Handle<Context> native_context, LanguageMode language_mode,
93 Handle<SharedFunctionInfo> value);
94
95 // Eval code only gets cached after a second probe for the
96 // code object. To do so, on first "put" only a hash identifying the
97 // source is entered into the cache, mapping it to a lifetime count of
98 // the hash. On each call to Age all such lifetimes get reduced, and
99 // removed once they reach zero. If a second put is called while such
100 // a hash is live in the cache, the hash gets replaced by an actual
101 // cache entry. Age also removes stale live entries from the cache.
102 // Such entries are identified by SharedFunctionInfos pointing to
103 // either the recompilation stub, or to "old" code. This avoids memory
104 // leaks due to premature caching of eval strings that are
105 // never needed later.
106 static InfoCellPair LookupEval(Handle<CompilationCacheTable> table,
107 Handle<String> src,
108 Handle<SharedFunctionInfo> shared,
109 Handle<Context> native_context,
110 LanguageMode language_mode, int position);
111 static Handle<CompilationCacheTable> PutEval(
112 Handle<CompilationCacheTable> cache, Handle<String> src,
113 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
114 Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
115 int position);
116
117 // The RegExp cache contains JSRegExp::data fixed arrays.
118 Handle<Object> LookupRegExp(Handle<String> source, JSRegExp::Flags flags);
119 static Handle<CompilationCacheTable> PutRegExp(
120 Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
121 JSRegExp::Flags flags, Handle<FixedArray> value);
122
123 // The Code cache shares native-context-independent (NCI) code between
124 // contexts.
125 MaybeHandle<Code> LookupCode(Handle<SharedFunctionInfo> key);
126 static Handle<CompilationCacheTable> PutCode(
127 Isolate* isolate, Handle<CompilationCacheTable> cache,
128 Handle<SharedFunctionInfo> key, Handle<Code> value);
129
130 void Remove(Object value);
131 void Age();
132
133 DECL_CAST(CompilationCacheTable)
134
135 private:
136 void RemoveEntry(int entry_index);
137
138 OBJECT_CONSTRUCTORS(CompilationCacheTable,
139 HashTable<CompilationCacheTable, CompilationCacheShape>);
140 };
141
142 } // namespace internal
143 } // namespace v8
144
145 #include "src/objects/object-macros-undef.h"
146
147 #endif // V8_OBJECTS_COMPILATION_CACHE_TABLE_H_
148