OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compilation-cache.h" | 5 #include "src/compilation-cache.h" |
6 | 6 |
7 #include "src/counters.h" | 7 #include "src/counters.h" |
8 #include "src/factory.h" | 8 #include "src/factory.h" |
9 #include "src/globals.h" | 9 #include "src/globals.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 | 15 |
16 // The number of generations for each sub cache. | 16 // The number of generations for each sub cache. |
17 static const int kRegExpGenerations = 2; | 17 static const int kRegExpGenerations = 2; |
18 | 18 |
19 // Initial size of each compilation cache table allocated. | 19 // Initial size of each compilation cache table allocated. |
20 static const int kInitialCacheSize = 64; | 20 static const int kInitialCacheSize = 64; |
21 | 21 |
22 | |
23 CompilationCache::CompilationCache(Isolate* isolate) | 22 CompilationCache::CompilationCache(Isolate* isolate) |
24 : isolate_(isolate), | 23 : isolate_(isolate), |
25 script_(isolate, 1), | 24 script_(isolate), |
26 eval_global_(isolate, 1), | 25 eval_global_(isolate), |
27 eval_contextual_(isolate, 1), | 26 eval_contextual_(isolate), |
28 reg_exp_(isolate, kRegExpGenerations), | 27 reg_exp_(isolate, kRegExpGenerations), |
29 enabled_(true) { | 28 enabled_(true) { |
30 CompilationSubCache* subcaches[kSubCacheCount] = | 29 CompilationSubCache* subcaches[kSubCacheCount] = |
31 {&script_, &eval_global_, &eval_contextual_, ®_exp_}; | 30 {&script_, &eval_global_, &eval_contextual_, ®_exp_}; |
32 for (int i = 0; i < kSubCacheCount; ++i) { | 31 for (int i = 0; i < kSubCacheCount; ++i) { |
33 subcaches_[i] = subcaches[i]; | 32 subcaches_[i] = subcaches[i]; |
34 } | 33 } |
35 } | 34 } |
36 | 35 |
37 | 36 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 // Probe the script generation tables. Make sure not to leak handles | 95 // Probe the script generation tables. Make sure not to leak handles |
97 // into the caller's handle scope. | 96 // into the caller's handle scope. |
98 { HandleScope scope(isolate()); | 97 { HandleScope scope(isolate()); |
99 for (int generation = 0; generation < generations(); generation++) { | 98 for (int generation = 0; generation < generations(); generation++) { |
100 Handle<CompilationCacheTable> table = GetTable(generation); | 99 Handle<CompilationCacheTable> table = GetTable(generation); |
101 table->Remove(*function_info); | 100 table->Remove(*function_info); |
102 } | 101 } |
103 } | 102 } |
104 } | 103 } |
105 | 104 |
106 | 105 CompilationCacheScript::CompilationCacheScript(Isolate* isolate) |
107 CompilationCacheScript::CompilationCacheScript(Isolate* isolate, | 106 : CompilationSubCache(isolate, 1) {} |
108 int generations) | |
109 : CompilationSubCache(isolate, generations) {} | |
110 | |
111 | 107 |
112 // We only re-use a cached function for some script source code if the | 108 // We only re-use a cached function for some script source code if the |
113 // script originates from the same place. This is to avoid issues | 109 // script originates from the same place. This is to avoid issues |
114 // when reporting errors, etc. | 110 // when reporting errors, etc. |
115 bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info, | 111 bool CompilationCacheScript::HasOrigin(Handle<SharedFunctionInfo> function_info, |
116 Handle<Object> name, int line_offset, | 112 Handle<Object> name, int line_offset, |
117 int column_offset, | 113 int column_offset, |
118 ScriptOriginOptions resource_options) { | 114 ScriptOriginOptions resource_options) { |
119 Handle<Script> script = | 115 Handle<Script> script = |
120 Handle<Script>(Script::cast(function_info->script()), isolate()); | 116 Handle<Script>(Script::cast(function_info->script()), isolate()); |
(...skipping 13 matching lines...) Expand all Loading... |
134 // Compare the two name strings for equality. | 130 // Compare the two name strings for equality. |
135 return String::Equals(Handle<String>::cast(name), | 131 return String::Equals(Handle<String>::cast(name), |
136 Handle<String>(String::cast(script->name()))); | 132 Handle<String>(String::cast(script->name()))); |
137 } | 133 } |
138 | 134 |
139 | 135 |
140 // TODO(245): Need to allow identical code from different contexts to | 136 // TODO(245): Need to allow identical code from different contexts to |
141 // be cached in the same script generation. Currently the first use | 137 // be cached in the same script generation. Currently the first use |
142 // will be cached, but subsequent code from different source / line | 138 // will be cached, but subsequent code from different source / line |
143 // won't. | 139 // won't. |
144 Handle<SharedFunctionInfo> CompilationCacheScript::Lookup( | 140 InfoVectorPair CompilationCacheScript::Lookup( |
145 Handle<String> source, Handle<Object> name, int line_offset, | 141 Handle<String> source, Handle<Object> name, int line_offset, |
146 int column_offset, ScriptOriginOptions resource_options, | 142 int column_offset, ScriptOriginOptions resource_options, |
147 Handle<Context> context, LanguageMode language_mode) { | 143 Handle<Context> context, LanguageMode language_mode) { |
148 Object* result = NULL; | 144 InfoVectorPair result; |
149 int generation; | |
150 | 145 |
151 // Probe the script generation tables. Make sure not to leak handles | 146 // Probe the script generation tables. Make sure not to leak handles |
152 // into the caller's handle scope. | 147 // into the caller's handle scope. |
153 { HandleScope scope(isolate()); | 148 { HandleScope scope(isolate()); |
154 for (generation = 0; generation < generations(); generation++) { | 149 const int generation = 0; |
155 Handle<CompilationCacheTable> table = GetTable(generation); | 150 DCHECK(generations() == 1); |
156 Handle<Object> probe = table->Lookup(source, context, language_mode); | 151 Handle<CompilationCacheTable> table = GetTable(generation); |
157 if (probe->IsSharedFunctionInfo()) { | 152 InfoVectorPair probe = table->LookupScript(source, context, language_mode); |
158 Handle<SharedFunctionInfo> function_info = | 153 if (probe.has_shared()) { |
159 Handle<SharedFunctionInfo>::cast(probe); | 154 Handle<SharedFunctionInfo> function_info(probe.shared(), isolate()); |
160 // Break when we've found a suitable shared function info that | 155 Handle<Cell> vector_handle; |
161 // matches the origin. | 156 if (probe.has_vector()) { |
162 if (HasOrigin(function_info, name, line_offset, column_offset, | 157 vector_handle = Handle<Cell>(probe.vector(), isolate()); |
163 resource_options)) { | 158 } |
164 result = *function_info; | 159 // Break when we've found a suitable shared function info that |
165 break; | 160 // matches the origin. |
166 } | 161 if (HasOrigin(function_info, name, line_offset, column_offset, |
| 162 resource_options)) { |
| 163 result = InfoVectorPair(*function_info, |
| 164 probe.has_vector() ? *vector_handle : nullptr); |
167 } | 165 } |
168 } | 166 } |
169 } | 167 } |
170 | 168 |
171 // Once outside the manacles of the handle scope, we need to recheck | 169 // Once outside the manacles of the handle scope, we need to recheck |
172 // to see if we actually found a cached script. If so, we return a | 170 // to see if we actually found a cached script. If so, we return a |
173 // handle created in the caller's handle scope. | 171 // handle created in the caller's handle scope. |
174 if (result != NULL) { | 172 if (result.has_shared()) { |
175 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result), | 173 Handle<SharedFunctionInfo> shared(result.shared(), isolate()); |
176 isolate()); | 174 // TODO(mvstanton): Make sure HasOrigin can't allocate, or it will |
| 175 // mess up our InfoVectorPair. |
177 DCHECK( | 176 DCHECK( |
178 HasOrigin(shared, name, line_offset, column_offset, resource_options)); | 177 HasOrigin(shared, name, line_offset, column_offset, resource_options)); |
179 // If the script was found in a later generation, we promote it to | |
180 // the first generation to let it survive longer in the cache. | |
181 if (generation != 0) Put(source, context, language_mode, shared); | |
182 isolate()->counters()->compilation_cache_hits()->Increment(); | 178 isolate()->counters()->compilation_cache_hits()->Increment(); |
183 return shared; | |
184 } else { | 179 } else { |
185 isolate()->counters()->compilation_cache_misses()->Increment(); | 180 isolate()->counters()->compilation_cache_misses()->Increment(); |
186 return Handle<SharedFunctionInfo>::null(); | |
187 } | 181 } |
| 182 return result; |
188 } | 183 } |
189 | 184 |
190 | 185 void CompilationCacheScript::Put(Handle<String> source, Handle<Context> context, |
191 void CompilationCacheScript::Put(Handle<String> source, | |
192 Handle<Context> context, | |
193 LanguageMode language_mode, | 186 LanguageMode language_mode, |
194 Handle<SharedFunctionInfo> function_info) { | 187 Handle<SharedFunctionInfo> function_info, |
| 188 Handle<Cell> literals) { |
195 HandleScope scope(isolate()); | 189 HandleScope scope(isolate()); |
196 Handle<CompilationCacheTable> table = GetFirstTable(); | 190 Handle<CompilationCacheTable> table = GetFirstTable(); |
197 SetFirstTable(CompilationCacheTable::Put(table, source, context, | 191 SetFirstTable(CompilationCacheTable::PutScript( |
198 language_mode, function_info)); | 192 table, source, context, language_mode, function_info, literals)); |
199 } | 193 } |
200 | 194 |
201 | 195 InfoVectorPair CompilationCacheEval::Lookup( |
202 MaybeHandle<SharedFunctionInfo> CompilationCacheEval::Lookup( | |
203 Handle<String> source, Handle<SharedFunctionInfo> outer_info, | 196 Handle<String> source, Handle<SharedFunctionInfo> outer_info, |
204 LanguageMode language_mode, int scope_position) { | 197 Handle<Context> native_context, LanguageMode language_mode, |
| 198 int scope_position) { |
205 HandleScope scope(isolate()); | 199 HandleScope scope(isolate()); |
206 // Make sure not to leak the table into the surrounding handle | 200 // Make sure not to leak the table into the surrounding handle |
207 // scope. Otherwise, we risk keeping old tables around even after | 201 // scope. Otherwise, we risk keeping old tables around even after |
208 // having cleared the cache. | 202 // having cleared the cache. |
209 Handle<Object> result = isolate()->factory()->undefined_value(); | 203 InfoVectorPair result; |
210 int generation; | 204 const int generation = 0; |
211 for (generation = 0; generation < generations(); generation++) { | 205 DCHECK(generations() == 1); |
212 Handle<CompilationCacheTable> table = GetTable(generation); | 206 Handle<CompilationCacheTable> table = GetTable(generation); |
213 result = | 207 result = table->LookupEval(source, outer_info, native_context, language_mode, |
214 table->LookupEval(source, outer_info, language_mode, scope_position); | 208 scope_position); |
215 if (result->IsSharedFunctionInfo()) break; | 209 if (result.has_shared()) { |
216 } | |
217 if (result->IsSharedFunctionInfo()) { | |
218 Handle<SharedFunctionInfo> function_info = | |
219 Handle<SharedFunctionInfo>::cast(result); | |
220 if (generation != 0) { | |
221 Put(source, outer_info, function_info, scope_position); | |
222 } | |
223 isolate()->counters()->compilation_cache_hits()->Increment(); | 210 isolate()->counters()->compilation_cache_hits()->Increment(); |
224 return scope.CloseAndEscape(function_info); | |
225 } else { | 211 } else { |
226 isolate()->counters()->compilation_cache_misses()->Increment(); | 212 isolate()->counters()->compilation_cache_misses()->Increment(); |
227 return MaybeHandle<SharedFunctionInfo>(); | |
228 } | 213 } |
| 214 return result; |
229 } | 215 } |
230 | 216 |
231 | |
232 void CompilationCacheEval::Put(Handle<String> source, | 217 void CompilationCacheEval::Put(Handle<String> source, |
233 Handle<SharedFunctionInfo> outer_info, | 218 Handle<SharedFunctionInfo> outer_info, |
234 Handle<SharedFunctionInfo> function_info, | 219 Handle<SharedFunctionInfo> function_info, |
235 int scope_position) { | 220 Handle<Context> native_context, |
| 221 Handle<Cell> literals, int scope_position) { |
236 HandleScope scope(isolate()); | 222 HandleScope scope(isolate()); |
237 Handle<CompilationCacheTable> table = GetFirstTable(); | 223 Handle<CompilationCacheTable> table = GetFirstTable(); |
238 table = CompilationCacheTable::PutEval(table, source, outer_info, | 224 table = |
239 function_info, scope_position); | 225 CompilationCacheTable::PutEval(table, source, outer_info, function_info, |
| 226 native_context, literals, scope_position); |
240 SetFirstTable(table); | 227 SetFirstTable(table); |
241 } | 228 } |
242 | 229 |
243 | 230 |
244 MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup( | 231 MaybeHandle<FixedArray> CompilationCacheRegExp::Lookup( |
245 Handle<String> source, | 232 Handle<String> source, |
246 JSRegExp::Flags flags) { | 233 JSRegExp::Flags flags) { |
247 HandleScope scope(isolate()); | 234 HandleScope scope(isolate()); |
248 // Make sure not to leak the table into the surrounding handle | 235 // Make sure not to leak the table into the surrounding handle |
249 // scope. Otherwise, we risk keeping old tables around even after | 236 // scope. Otherwise, we risk keeping old tables around even after |
(...skipping 29 matching lines...) Expand all Loading... |
279 | 266 |
280 | 267 |
281 void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) { | 268 void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) { |
282 if (!IsEnabled()) return; | 269 if (!IsEnabled()) return; |
283 | 270 |
284 eval_global_.Remove(function_info); | 271 eval_global_.Remove(function_info); |
285 eval_contextual_.Remove(function_info); | 272 eval_contextual_.Remove(function_info); |
286 script_.Remove(function_info); | 273 script_.Remove(function_info); |
287 } | 274 } |
288 | 275 |
289 | 276 InfoVectorPair CompilationCache::LookupScript( |
290 MaybeHandle<SharedFunctionInfo> CompilationCache::LookupScript( | |
291 Handle<String> source, Handle<Object> name, int line_offset, | 277 Handle<String> source, Handle<Object> name, int line_offset, |
292 int column_offset, ScriptOriginOptions resource_options, | 278 int column_offset, ScriptOriginOptions resource_options, |
293 Handle<Context> context, LanguageMode language_mode) { | 279 Handle<Context> context, LanguageMode language_mode) { |
294 if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>(); | 280 InfoVectorPair empty_result; |
| 281 if (!IsEnabled()) return empty_result; |
295 | 282 |
296 return script_.Lookup(source, name, line_offset, column_offset, | 283 return script_.Lookup(source, name, line_offset, column_offset, |
297 resource_options, context, language_mode); | 284 resource_options, context, language_mode); |
298 } | 285 } |
299 | 286 |
300 | 287 InfoVectorPair CompilationCache::LookupEval( |
301 MaybeHandle<SharedFunctionInfo> CompilationCache::LookupEval( | |
302 Handle<String> source, Handle<SharedFunctionInfo> outer_info, | 288 Handle<String> source, Handle<SharedFunctionInfo> outer_info, |
303 Handle<Context> context, LanguageMode language_mode, int scope_position) { | 289 Handle<Context> context, LanguageMode language_mode, int scope_position) { |
304 if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>(); | 290 InfoVectorPair result; |
| 291 if (!IsEnabled()) return result; |
305 | 292 |
306 MaybeHandle<SharedFunctionInfo> result; | |
307 if (context->IsNativeContext()) { | 293 if (context->IsNativeContext()) { |
308 result = | 294 result = eval_global_.Lookup(source, outer_info, context, language_mode, |
309 eval_global_.Lookup(source, outer_info, language_mode, scope_position); | 295 scope_position); |
310 } else { | 296 } else { |
311 DCHECK(scope_position != kNoSourcePosition); | 297 DCHECK(scope_position != kNoSourcePosition); |
312 result = eval_contextual_.Lookup(source, outer_info, language_mode, | 298 Handle<Context> native_context(context->native_context(), isolate()); |
313 scope_position); | 299 result = eval_contextual_.Lookup(source, outer_info, native_context, |
| 300 language_mode, scope_position); |
314 } | 301 } |
| 302 |
315 return result; | 303 return result; |
316 } | 304 } |
317 | 305 |
318 | 306 |
319 MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, | 307 MaybeHandle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, |
320 JSRegExp::Flags flags) { | 308 JSRegExp::Flags flags) { |
321 if (!IsEnabled()) return MaybeHandle<FixedArray>(); | 309 if (!IsEnabled()) return MaybeHandle<FixedArray>(); |
322 | 310 |
323 return reg_exp_.Lookup(source, flags); | 311 return reg_exp_.Lookup(source, flags); |
324 } | 312 } |
325 | 313 |
326 | 314 void CompilationCache::PutScript(Handle<String> source, Handle<Context> context, |
327 void CompilationCache::PutScript(Handle<String> source, | |
328 Handle<Context> context, | |
329 LanguageMode language_mode, | 315 LanguageMode language_mode, |
330 Handle<SharedFunctionInfo> function_info) { | 316 Handle<SharedFunctionInfo> function_info, |
| 317 Handle<Cell> literals) { |
331 if (!IsEnabled()) return; | 318 if (!IsEnabled()) return; |
332 | 319 |
333 script_.Put(source, context, language_mode, function_info); | 320 script_.Put(source, context, language_mode, function_info, literals); |
334 } | 321 } |
335 | 322 |
336 | |
337 void CompilationCache::PutEval(Handle<String> source, | 323 void CompilationCache::PutEval(Handle<String> source, |
338 Handle<SharedFunctionInfo> outer_info, | 324 Handle<SharedFunctionInfo> outer_info, |
339 Handle<Context> context, | 325 Handle<Context> context, |
340 Handle<SharedFunctionInfo> function_info, | 326 Handle<SharedFunctionInfo> function_info, |
341 int scope_position) { | 327 Handle<Cell> literals, int scope_position) { |
342 if (!IsEnabled()) return; | 328 if (!IsEnabled()) return; |
343 | 329 |
344 HandleScope scope(isolate()); | 330 HandleScope scope(isolate()); |
345 if (context->IsNativeContext()) { | 331 if (context->IsNativeContext()) { |
346 eval_global_.Put(source, outer_info, function_info, scope_position); | 332 eval_global_.Put(source, outer_info, function_info, context, literals, |
| 333 scope_position); |
347 } else { | 334 } else { |
348 DCHECK(scope_position != kNoSourcePosition); | 335 DCHECK(scope_position != kNoSourcePosition); |
349 eval_contextual_.Put(source, outer_info, function_info, scope_position); | 336 Handle<Context> native_context(context->native_context(), isolate()); |
| 337 eval_contextual_.Put(source, outer_info, function_info, native_context, |
| 338 literals, scope_position); |
350 } | 339 } |
351 } | 340 } |
352 | 341 |
353 | 342 |
354 | 343 |
355 void CompilationCache::PutRegExp(Handle<String> source, | 344 void CompilationCache::PutRegExp(Handle<String> source, |
356 JSRegExp::Flags flags, | 345 JSRegExp::Flags flags, |
357 Handle<FixedArray> data) { | 346 Handle<FixedArray> data) { |
358 if (!IsEnabled()) { | 347 if (!IsEnabled()) { |
359 return; | 348 return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 | 386 |
398 | 387 |
399 void CompilationCache::Disable() { | 388 void CompilationCache::Disable() { |
400 enabled_ = false; | 389 enabled_ = false; |
401 Clear(); | 390 Clear(); |
402 } | 391 } |
403 | 392 |
404 | 393 |
405 } // namespace internal | 394 } // namespace internal |
406 } // namespace v8 | 395 } // namespace v8 |
OLD | NEW |