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()57 FeedbackCell feedback_cell() const {
58 DCHECK(is_compiled_scope_.is_compiled());
59 return feedback_cell_;
60 }
shared()61 SharedFunctionInfo shared() const {
62 DCHECK(is_compiled_scope_.is_compiled());
63 return shared_;
64 }
65
has_feedback_cell()66 bool has_feedback_cell() const {
67 return !feedback_cell_.is_null() && is_compiled_scope_.is_compiled();
68 }
has_shared()69 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
EXTERN_DECLARE_HASH_TABLE(CompilationCacheTable,CompilationCacheShape)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