OLD | NEW |
1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 14 matching lines...) Expand all Loading... |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "compilation-cache.h" | 30 #include "compilation-cache.h" |
31 | 31 |
32 namespace v8 { namespace internal { | 32 namespace v8 { namespace internal { |
33 | 33 |
34 enum { | 34 enum { |
35 NUMBER_OF_ENTRY_KINDS = CompilationCache::LAST_ENTRY + 1 | 35 // The number of script generations tell how many GCs a script can |
| 36 // survive in the compilation cache, before it will be flushed if it |
| 37 // hasn't been used. |
| 38 NUMBER_OF_SCRIPT_GENERATIONS = 5, |
| 39 |
| 40 // The compilation cache consists of tables - one for each entry |
| 41 // kind plus extras for the script generations. |
| 42 NUMBER_OF_TABLE_ENTRIES = |
| 43 CompilationCache::LAST_ENTRY + NUMBER_OF_SCRIPT_GENERATIONS |
36 }; | 44 }; |
37 | 45 |
38 | 46 |
39 // Keep separate tables for the different entry kinds. | 47 // Keep separate tables for the different entry kinds. |
40 static Object* tables[NUMBER_OF_ENTRY_KINDS] = { 0, }; | 48 static Object* tables[NUMBER_OF_TABLE_ENTRIES] = { 0, }; |
41 | 49 |
42 | 50 |
43 static Handle<CompilationCacheTable> AllocateTable(int size) { | 51 static Handle<CompilationCacheTable> AllocateTable(int size) { |
44 CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size), | 52 CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size), |
45 CompilationCacheTable); | 53 CompilationCacheTable); |
46 } | 54 } |
47 | 55 |
48 | 56 |
49 static Handle<CompilationCacheTable> GetTable(CompilationCache::Entry entry) { | 57 static Handle<CompilationCacheTable> GetTable(CompilationCache::Entry entry) { |
50 Handle<CompilationCacheTable> result; | 58 Handle<CompilationCacheTable> result; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 // Do the fast bailout checks first. | 122 // Do the fast bailout checks first. |
115 if (line_offset != script->line_offset()->value()) return false; | 123 if (line_offset != script->line_offset()->value()) return false; |
116 if (column_offset != script->column_offset()->value()) return false; | 124 if (column_offset != script->column_offset()->value()) return false; |
117 // Check that both names are strings. If not, no match. | 125 // Check that both names are strings. If not, no match. |
118 if (!name->IsString() || !script->name()->IsString()) return false; | 126 if (!name->IsString() || !script->name()->IsString()) return false; |
119 // Compare the two name strings for equality. | 127 // Compare the two name strings for equality. |
120 return String::cast(*name)->Equals(String::cast(script->name())); | 128 return String::cast(*name)->Equals(String::cast(script->name())); |
121 } | 129 } |
122 | 130 |
123 | 131 |
124 static Handle<JSFunction> Lookup(Handle<String> source, | 132 // TODO(245): Need to allow identical code from different contexts to |
125 CompilationCache::Entry entry) { | 133 // be cached in the same script generation. Currently the first use |
126 // Make sure not to leak the table into the surrounding handle | 134 // will be cached, but subsequent code from different source / line |
127 // scope. Otherwise, we risk keeping old tables around even after | 135 // won't. |
128 // having cleared the cache. | 136 Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source, |
129 Object* result; | 137 Handle<Object> name, |
| 138 int line_offset, |
| 139 int column_offset) { |
| 140 Object* result = NULL; |
| 141 Entry generation = SCRIPT; // First generation. |
| 142 |
| 143 // Probe the script generation tables. Make sure not to leak handles |
| 144 // into the caller's handle scope. |
130 { HandleScope scope; | 145 { HandleScope scope; |
131 Handle<CompilationCacheTable> table = GetTable(entry); | 146 while (generation < SCRIPT + NUMBER_OF_SCRIPT_GENERATIONS) { |
132 result = table->Lookup(*source); | 147 Handle<CompilationCacheTable> table = GetTable(generation); |
| 148 Handle<Object> probe(table->Lookup(*source)); |
| 149 if (probe->IsJSFunction()) { |
| 150 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(probe); |
| 151 // Break when we've found a suitable boilerplate function that |
| 152 // matches the origin. |
| 153 if (HasOrigin(boilerplate, name, line_offset, column_offset)) { |
| 154 result = *boilerplate; |
| 155 break; |
| 156 } |
| 157 } |
| 158 // Go to the next generation. |
| 159 generation = static_cast<Entry>(generation + 1); |
| 160 } |
133 } | 161 } |
134 if (result->IsJSFunction()) { | 162 |
135 return Handle<JSFunction>(JSFunction::cast(result)); | 163 // Once outside the menacles of the handle scope, we need to recheck |
| 164 // to see if we actually found a cached script. If so, we return a |
| 165 // handle created in the caller's handle scope. |
| 166 if (result != NULL) { |
| 167 Handle<JSFunction> boilerplate(JSFunction::cast(result)); |
| 168 ASSERT(HasOrigin(boilerplate, name, line_offset, column_offset)); |
| 169 // If the script was found in a later generation, we promote it to |
| 170 // the first generation to let it survive longer in the cache. |
| 171 if (generation != SCRIPT) PutScript(source, boilerplate); |
| 172 Counters::compilation_cache_hits.Increment(); |
| 173 return boilerplate; |
136 } else { | 174 } else { |
| 175 Counters::compilation_cache_misses.Increment(); |
137 return Handle<JSFunction>::null(); | 176 return Handle<JSFunction>::null(); |
138 } | 177 } |
139 } | 178 } |
140 | 179 |
141 | 180 |
142 // TODO(245): Need to allow identical code from different contexts to be | |
143 // cached. Currently the first use will be cached, but subsequent code | |
144 // from different source / line won't. | |
145 Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source, | |
146 Handle<Object> name, | |
147 int line_offset, | |
148 int column_offset) { | |
149 Handle<JSFunction> result = Lookup(source, SCRIPT); | |
150 if (result.is_null()) { | |
151 Counters::compilation_cache_misses.Increment(); | |
152 } else if (HasOrigin(result, name, line_offset, column_offset)) { | |
153 Counters::compilation_cache_hits.Increment(); | |
154 } else { | |
155 result = Handle<JSFunction>::null(); | |
156 Counters::compilation_cache_misses.Increment(); | |
157 } | |
158 return result; | |
159 } | |
160 | |
161 | |
162 Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source, | 181 Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source, |
163 Handle<Context> context, | 182 Handle<Context> context, |
164 Entry entry) { | 183 Entry entry) { |
165 ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL); | 184 ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL); |
166 Handle<JSFunction> result = Lookup(source, context, entry); | 185 Handle<JSFunction> result = Lookup(source, context, entry); |
167 if (result.is_null()) { | 186 if (result.is_null()) { |
168 Counters::compilation_cache_misses.Increment(); | 187 Counters::compilation_cache_misses.Increment(); |
169 } else { | 188 } else { |
170 Counters::compilation_cache_hits.Increment(); | 189 Counters::compilation_cache_hits.Increment(); |
171 } | 190 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 void CompilationCache::PutRegExp(Handle<String> source, | 228 void CompilationCache::PutRegExp(Handle<String> source, |
210 JSRegExp::Flags flags, | 229 JSRegExp::Flags flags, |
211 Handle<FixedArray> data) { | 230 Handle<FixedArray> data) { |
212 HandleScope scope; | 231 HandleScope scope; |
213 Handle<CompilationCacheTable> table = GetTable(REGEXP); | 232 Handle<CompilationCacheTable> table = GetTable(REGEXP); |
214 CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data)); | 233 CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data)); |
215 } | 234 } |
216 | 235 |
217 | 236 |
218 void CompilationCache::Clear() { | 237 void CompilationCache::Clear() { |
219 for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) { | 238 for (int i = 0; i < NUMBER_OF_TABLE_ENTRIES; i++) { |
220 tables[i] = Heap::undefined_value(); | 239 tables[i] = Heap::undefined_value(); |
221 } | 240 } |
222 } | 241 } |
223 | 242 |
224 | 243 |
225 void CompilationCache::Iterate(ObjectVisitor* v) { | 244 void CompilationCache::Iterate(ObjectVisitor* v) { |
226 v->VisitPointers(&tables[0], &tables[NUMBER_OF_ENTRY_KINDS]); | 245 v->VisitPointers(&tables[0], &tables[NUMBER_OF_TABLE_ENTRIES]); |
| 246 } |
| 247 |
| 248 |
| 249 void CompilationCache::MarkCompactPrologue() { |
| 250 ASSERT(LAST_ENTRY == SCRIPT); |
| 251 for (int i = NUMBER_OF_TABLE_ENTRIES - 1; i > SCRIPT; i--) { |
| 252 tables[i] = tables[i - 1]; |
| 253 } |
| 254 for (int j = 0; j <= LAST_ENTRY; j++) { |
| 255 tables[j] = Heap::undefined_value(); |
| 256 } |
227 } | 257 } |
228 | 258 |
229 | 259 |
230 } } // namespace v8::internal | 260 } } // namespace v8::internal |
OLD | NEW |