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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache); | 94 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache); |
95 }; | 95 }; |
96 | 96 |
97 | 97 |
98 // Sub-cache for scripts. | 98 // Sub-cache for scripts. |
99 class CompilationCacheScript : public CompilationSubCache { | 99 class CompilationCacheScript : public CompilationSubCache { |
100 public: | 100 public: |
101 explicit CompilationCacheScript(int generations) | 101 explicit CompilationCacheScript(int generations) |
102 : CompilationSubCache(generations) { } | 102 : CompilationSubCache(generations) { } |
103 | 103 |
104 Handle<JSFunction> Lookup(Handle<String> source, | 104 Handle<SharedFunctionInfo> Lookup(Handle<String> source, |
105 Handle<Object> name, | 105 Handle<Object> name, |
106 int line_offset, | 106 int line_offset, |
107 int column_offset); | 107 int column_offset); |
108 void Put(Handle<String> source, Handle<JSFunction> boilerplate); | 108 void Put(Handle<String> source, Handle<SharedFunctionInfo> function_info); |
109 | 109 |
110 private: | 110 private: |
111 // Note: Returns a new hash table if operation results in expansion. | 111 // Note: Returns a new hash table if operation results in expansion. |
112 Handle<CompilationCacheTable> TablePut(Handle<String> source, | 112 Handle<CompilationCacheTable> TablePut( |
113 Handle<JSFunction> boilerplate); | 113 Handle<String> source, Handle<SharedFunctionInfo> function_info); |
114 | 114 |
115 bool HasOrigin(Handle<JSFunction> boilerplate, | 115 bool HasOrigin(Handle<SharedFunctionInfo> function_info, |
116 Handle<Object> name, | 116 Handle<Object> name, |
117 int line_offset, | 117 int line_offset, |
118 int column_offset); | 118 int column_offset); |
119 | 119 |
120 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript); | 120 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript); |
121 }; | 121 }; |
122 | 122 |
123 | 123 |
124 // Sub-cache for eval scripts. | 124 // Sub-cache for eval scripts. |
125 class CompilationCacheEval: public CompilationSubCache { | 125 class CompilationCacheEval: public CompilationSubCache { |
126 public: | 126 public: |
127 explicit CompilationCacheEval(int generations) | 127 explicit CompilationCacheEval(int generations) |
128 : CompilationSubCache(generations) { } | 128 : CompilationSubCache(generations) { } |
129 | 129 |
130 Handle<JSFunction> Lookup(Handle<String> source, Handle<Context> context); | 130 Handle<SharedFunctionInfo> Lookup(Handle<String> source, |
| 131 Handle<Context> context); |
131 | 132 |
132 void Put(Handle<String> source, | 133 void Put(Handle<String> source, |
133 Handle<Context> context, | 134 Handle<Context> context, |
134 Handle<JSFunction> boilerplate); | 135 Handle<SharedFunctionInfo> function_info); |
135 | 136 |
136 private: | 137 private: |
137 // Note: Returns a new hash table if operation results in expansion. | 138 // Note: Returns a new hash table if operation results in expansion. |
138 Handle<CompilationCacheTable> TablePut(Handle<String> source, | 139 Handle<CompilationCacheTable> TablePut( |
139 Handle<Context> context, | 140 Handle<String> source, |
140 Handle<JSFunction> boilerplate); | 141 Handle<Context> context, |
| 142 Handle<SharedFunctionInfo> function_info); |
141 | 143 |
142 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval); | 144 DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval); |
143 }; | 145 }; |
144 | 146 |
145 | 147 |
146 // Sub-cache for regular expressions. | 148 // Sub-cache for regular expressions. |
147 class CompilationCacheRegExp: public CompilationSubCache { | 149 class CompilationCacheRegExp: public CompilationSubCache { |
148 public: | 150 public: |
149 explicit CompilationCacheRegExp(int generations) | 151 explicit CompilationCacheRegExp(int generations) |
150 : CompilationSubCache(generations) { } | 152 : CompilationSubCache(generations) { } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 | 220 |
219 | 221 |
220 void CompilationSubCache::Clear() { | 222 void CompilationSubCache::Clear() { |
221 MemsetPointer(tables_, Heap::undefined_value(), generations_); | 223 MemsetPointer(tables_, Heap::undefined_value(), generations_); |
222 } | 224 } |
223 | 225 |
224 | 226 |
225 // We only re-use a cached function for some script source code if the | 227 // We only re-use a cached function for some script source code if the |
226 // script originates from the same place. This is to avoid issues | 228 // script originates from the same place. This is to avoid issues |
227 // when reporting errors, etc. | 229 // when reporting errors, etc. |
228 bool CompilationCacheScript::HasOrigin(Handle<JSFunction> boilerplate, | 230 bool CompilationCacheScript::HasOrigin( |
229 Handle<Object> name, | 231 Handle<SharedFunctionInfo> function_info, |
230 int line_offset, | 232 Handle<Object> name, |
231 int column_offset) { | 233 int line_offset, |
| 234 int column_offset) { |
232 Handle<Script> script = | 235 Handle<Script> script = |
233 Handle<Script>(Script::cast(boilerplate->shared()->script())); | 236 Handle<Script>(Script::cast(function_info->script())); |
234 // If the script name isn't set, the boilerplate script should have | 237 // If the script name isn't set, the boilerplate script should have |
235 // an undefined name to have the same origin. | 238 // an undefined name to have the same origin. |
236 if (name.is_null()) { | 239 if (name.is_null()) { |
237 return script->name()->IsUndefined(); | 240 return script->name()->IsUndefined(); |
238 } | 241 } |
239 // Do the fast bailout checks first. | 242 // Do the fast bailout checks first. |
240 if (line_offset != script->line_offset()->value()) return false; | 243 if (line_offset != script->line_offset()->value()) return false; |
241 if (column_offset != script->column_offset()->value()) return false; | 244 if (column_offset != script->column_offset()->value()) return false; |
242 // Check that both names are strings. If not, no match. | 245 // Check that both names are strings. If not, no match. |
243 if (!name->IsString() || !script->name()->IsString()) return false; | 246 if (!name->IsString() || !script->name()->IsString()) return false; |
244 // Compare the two name strings for equality. | 247 // Compare the two name strings for equality. |
245 return String::cast(*name)->Equals(String::cast(script->name())); | 248 return String::cast(*name)->Equals(String::cast(script->name())); |
246 } | 249 } |
247 | 250 |
248 | 251 |
249 // TODO(245): Need to allow identical code from different contexts to | 252 // TODO(245): Need to allow identical code from different contexts to |
250 // be cached in the same script generation. Currently the first use | 253 // be cached in the same script generation. Currently the first use |
251 // will be cached, but subsequent code from different source / line | 254 // will be cached, but subsequent code from different source / line |
252 // won't. | 255 // won't. |
253 Handle<JSFunction> CompilationCacheScript::Lookup(Handle<String> source, | 256 Handle<SharedFunctionInfo> CompilationCacheScript::Lookup(Handle<String> source, |
254 Handle<Object> name, | 257 Handle<Object> name, |
255 int line_offset, | 258 int line_offset, |
256 int column_offset) { | 259 int column_offset) { |
257 Object* result = NULL; | 260 Object* result = NULL; |
258 int generation; | 261 int generation; |
259 | 262 |
260 // Probe the script generation tables. Make sure not to leak handles | 263 // Probe the script generation tables. Make sure not to leak handles |
261 // into the caller's handle scope. | 264 // into the caller's handle scope. |
262 { HandleScope scope; | 265 { HandleScope scope; |
263 for (generation = 0; generation < generations(); generation++) { | 266 for (generation = 0; generation < generations(); generation++) { |
264 Handle<CompilationCacheTable> table = GetTable(generation); | 267 Handle<CompilationCacheTable> table = GetTable(generation); |
265 Handle<Object> probe(table->Lookup(*source)); | 268 Handle<Object> probe(table->Lookup(*source)); |
266 if (probe->IsJSFunction()) { | 269 if (probe->IsSharedFunctionInfo()) { |
267 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(probe); | 270 Handle<SharedFunctionInfo> function_info = |
| 271 Handle<SharedFunctionInfo>::cast(probe); |
268 // Break when we've found a suitable boilerplate function that | 272 // Break when we've found a suitable boilerplate function that |
269 // matches the origin. | 273 // matches the origin. |
270 if (HasOrigin(boilerplate, name, line_offset, column_offset)) { | 274 if (HasOrigin(function_info, name, line_offset, column_offset)) { |
271 result = *boilerplate; | 275 result = *function_info; |
272 break; | 276 break; |
273 } | 277 } |
274 } | 278 } |
275 } | 279 } |
276 } | 280 } |
277 | 281 |
278 static void* script_histogram = StatsTable::CreateHistogram( | 282 static void* script_histogram = StatsTable::CreateHistogram( |
279 "V8.ScriptCache", | 283 "V8.ScriptCache", |
280 0, | 284 0, |
281 kScriptGenerations, | 285 kScriptGenerations, |
282 kScriptGenerations + 1); | 286 kScriptGenerations + 1); |
283 | 287 |
284 if (script_histogram != NULL) { | 288 if (script_histogram != NULL) { |
285 // The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss. | 289 // The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss. |
286 StatsTable::AddHistogramSample(script_histogram, generation); | 290 StatsTable::AddHistogramSample(script_histogram, generation); |
287 } | 291 } |
288 | 292 |
289 // Once outside the manacles of the handle scope, we need to recheck | 293 // Once outside the manacles of the handle scope, we need to recheck |
290 // to see if we actually found a cached script. If so, we return a | 294 // to see if we actually found a cached script. If so, we return a |
291 // handle created in the caller's handle scope. | 295 // handle created in the caller's handle scope. |
292 if (result != NULL) { | 296 if (result != NULL) { |
293 Handle<JSFunction> boilerplate(JSFunction::cast(result)); | 297 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); |
294 ASSERT(HasOrigin(boilerplate, name, line_offset, column_offset)); | 298 ASSERT(HasOrigin(shared, name, line_offset, column_offset)); |
295 // If the script was found in a later generation, we promote it to | 299 // If the script was found in a later generation, we promote it to |
296 // the first generation to let it survive longer in the cache. | 300 // the first generation to let it survive longer in the cache. |
297 if (generation != 0) Put(source, boilerplate); | 301 if (generation != 0) Put(source, shared); |
298 Counters::compilation_cache_hits.Increment(); | 302 Counters::compilation_cache_hits.Increment(); |
299 return boilerplate; | 303 return shared; |
300 } else { | 304 } else { |
301 Counters::compilation_cache_misses.Increment(); | 305 Counters::compilation_cache_misses.Increment(); |
302 return Handle<JSFunction>::null(); | 306 return Handle<SharedFunctionInfo>::null(); |
303 } | 307 } |
304 } | 308 } |
305 | 309 |
306 | 310 |
307 Handle<CompilationCacheTable> CompilationCacheScript::TablePut( | 311 Handle<CompilationCacheTable> CompilationCacheScript::TablePut( |
308 Handle<String> source, | 312 Handle<String> source, |
309 Handle<JSFunction> boilerplate) { | 313 Handle<SharedFunctionInfo> function_info) { |
310 CALL_HEAP_FUNCTION(GetFirstTable()->Put(*source, *boilerplate), | 314 CALL_HEAP_FUNCTION(GetFirstTable()->Put(*source, *function_info), |
311 CompilationCacheTable); | 315 CompilationCacheTable); |
312 } | 316 } |
313 | 317 |
314 | 318 |
315 void CompilationCacheScript::Put(Handle<String> source, | 319 void CompilationCacheScript::Put(Handle<String> source, |
316 Handle<JSFunction> boilerplate) { | 320 Handle<SharedFunctionInfo> function_info) { |
317 HandleScope scope; | 321 HandleScope scope; |
318 ASSERT(boilerplate->IsBoilerplate()); | 322 SetFirstTable(TablePut(source, function_info)); |
319 SetFirstTable(TablePut(source, boilerplate)); | |
320 } | 323 } |
321 | 324 |
322 | 325 |
323 Handle<JSFunction> CompilationCacheEval::Lookup(Handle<String> source, | 326 Handle<SharedFunctionInfo> CompilationCacheEval::Lookup( |
324 Handle<Context> context) { | 327 Handle<String> source, Handle<Context> context) { |
325 // Make sure not to leak the table into the surrounding handle | 328 // Make sure not to leak the table into the surrounding handle |
326 // scope. Otherwise, we risk keeping old tables around even after | 329 // scope. Otherwise, we risk keeping old tables around even after |
327 // having cleared the cache. | 330 // having cleared the cache. |
328 Object* result = NULL; | 331 Object* result = NULL; |
329 int generation; | 332 int generation; |
330 { HandleScope scope; | 333 { HandleScope scope; |
331 for (generation = 0; generation < generations(); generation++) { | 334 for (generation = 0; generation < generations(); generation++) { |
332 Handle<CompilationCacheTable> table = GetTable(generation); | 335 Handle<CompilationCacheTable> table = GetTable(generation); |
333 result = table->LookupEval(*source, *context); | 336 result = table->LookupEval(*source, *context); |
334 if (result->IsJSFunction()) { | 337 if (result->IsSharedFunctionInfo()) { |
335 break; | 338 break; |
336 } | 339 } |
337 } | 340 } |
338 } | 341 } |
339 if (result->IsJSFunction()) { | 342 if (result->IsSharedFunctionInfo()) { |
340 Handle<JSFunction> boilerplate(JSFunction::cast(result)); | 343 Handle<SharedFunctionInfo> |
| 344 function_info(SharedFunctionInfo::cast(result)); |
341 if (generation != 0) { | 345 if (generation != 0) { |
342 Put(source, context, boilerplate); | 346 Put(source, context, function_info); |
343 } | 347 } |
344 Counters::compilation_cache_hits.Increment(); | 348 Counters::compilation_cache_hits.Increment(); |
345 return boilerplate; | 349 return function_info; |
346 } else { | 350 } else { |
347 Counters::compilation_cache_misses.Increment(); | 351 Counters::compilation_cache_misses.Increment(); |
348 return Handle<JSFunction>::null(); | 352 return Handle<SharedFunctionInfo>::null(); |
349 } | 353 } |
350 } | 354 } |
351 | 355 |
352 | 356 |
353 Handle<CompilationCacheTable> CompilationCacheEval::TablePut( | 357 Handle<CompilationCacheTable> CompilationCacheEval::TablePut( |
354 Handle<String> source, | 358 Handle<String> source, |
355 Handle<Context> context, | 359 Handle<Context> context, |
356 Handle<JSFunction> boilerplate) { | 360 Handle<SharedFunctionInfo> function_info) { |
357 CALL_HEAP_FUNCTION(GetFirstTable()->PutEval(*source, *context, *boilerplate), | 361 CALL_HEAP_FUNCTION(GetFirstTable()->PutEval(*source, |
| 362 *context, |
| 363 *function_info), |
358 CompilationCacheTable); | 364 CompilationCacheTable); |
359 } | 365 } |
360 | 366 |
361 | 367 |
362 void CompilationCacheEval::Put(Handle<String> source, | 368 void CompilationCacheEval::Put(Handle<String> source, |
363 Handle<Context> context, | 369 Handle<Context> context, |
364 Handle<JSFunction> boilerplate) { | 370 Handle<SharedFunctionInfo> function_info) { |
365 HandleScope scope; | 371 HandleScope scope; |
366 ASSERT(boilerplate->IsBoilerplate()); | 372 SetFirstTable(TablePut(source, context, function_info)); |
367 SetFirstTable(TablePut(source, context, boilerplate)); | |
368 } | 373 } |
369 | 374 |
370 | 375 |
371 Handle<FixedArray> CompilationCacheRegExp::Lookup(Handle<String> source, | 376 Handle<FixedArray> CompilationCacheRegExp::Lookup(Handle<String> source, |
372 JSRegExp::Flags flags) { | 377 JSRegExp::Flags flags) { |
373 // Make sure not to leak the table into the surrounding handle | 378 // Make sure not to leak the table into the surrounding handle |
374 // scope. Otherwise, we risk keeping old tables around even after | 379 // scope. Otherwise, we risk keeping old tables around even after |
375 // having cleared the cache. | 380 // having cleared the cache. |
376 Object* result = NULL; | 381 Object* result = NULL; |
377 int generation; | 382 int generation; |
(...skipping 30 matching lines...) Expand all Loading... |
408 | 413 |
409 | 414 |
410 void CompilationCacheRegExp::Put(Handle<String> source, | 415 void CompilationCacheRegExp::Put(Handle<String> source, |
411 JSRegExp::Flags flags, | 416 JSRegExp::Flags flags, |
412 Handle<FixedArray> data) { | 417 Handle<FixedArray> data) { |
413 HandleScope scope; | 418 HandleScope scope; |
414 SetFirstTable(TablePut(source, flags, data)); | 419 SetFirstTable(TablePut(source, flags, data)); |
415 } | 420 } |
416 | 421 |
417 | 422 |
418 Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source, | 423 Handle<SharedFunctionInfo> CompilationCache::LookupScript(Handle<String> source, |
419 Handle<Object> name, | 424 Handle<Object> name, |
420 int line_offset, | 425 int line_offset, |
421 int column_offset) { | 426 int column_offset) { |
422 if (!IsEnabled()) { | 427 if (!IsEnabled()) { |
423 return Handle<JSFunction>::null(); | 428 return Handle<SharedFunctionInfo>::null(); |
424 } | 429 } |
425 | 430 |
426 return script.Lookup(source, name, line_offset, column_offset); | 431 return script.Lookup(source, name, line_offset, column_offset); |
427 } | 432 } |
428 | 433 |
429 | 434 |
430 Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source, | 435 Handle<SharedFunctionInfo> CompilationCache::LookupEval(Handle<String> source, |
431 Handle<Context> context, | 436 Handle<Context> context, |
432 bool is_global) { | 437 bool is_global) { |
433 if (!IsEnabled()) { | 438 if (!IsEnabled()) { |
434 return Handle<JSFunction>::null(); | 439 return Handle<SharedFunctionInfo>::null(); |
435 } | 440 } |
436 | 441 |
437 Handle<JSFunction> result; | 442 Handle<SharedFunctionInfo> result; |
438 if (is_global) { | 443 if (is_global) { |
439 result = eval_global.Lookup(source, context); | 444 result = eval_global.Lookup(source, context); |
440 } else { | 445 } else { |
441 result = eval_contextual.Lookup(source, context); | 446 result = eval_contextual.Lookup(source, context); |
442 } | 447 } |
443 return result; | 448 return result; |
444 } | 449 } |
445 | 450 |
446 | 451 |
447 Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, | 452 Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, |
448 JSRegExp::Flags flags) { | 453 JSRegExp::Flags flags) { |
449 if (!IsEnabled()) { | 454 if (!IsEnabled()) { |
450 return Handle<FixedArray>::null(); | 455 return Handle<FixedArray>::null(); |
451 } | 456 } |
452 | 457 |
453 return reg_exp.Lookup(source, flags); | 458 return reg_exp.Lookup(source, flags); |
454 } | 459 } |
455 | 460 |
456 | 461 |
457 void CompilationCache::PutScript(Handle<String> source, | 462 void CompilationCache::PutScript(Handle<String> source, |
458 Handle<JSFunction> boilerplate) { | 463 Handle<SharedFunctionInfo> function_info) { |
459 if (!IsEnabled()) { | 464 if (!IsEnabled()) { |
460 return; | 465 return; |
461 } | 466 } |
462 | 467 |
463 ASSERT(boilerplate->IsBoilerplate()); | 468 script.Put(source, function_info); |
464 script.Put(source, boilerplate); | |
465 } | 469 } |
466 | 470 |
467 | 471 |
468 void CompilationCache::PutEval(Handle<String> source, | 472 void CompilationCache::PutEval(Handle<String> source, |
469 Handle<Context> context, | 473 Handle<Context> context, |
470 bool is_global, | 474 bool is_global, |
471 Handle<JSFunction> boilerplate) { | 475 Handle<SharedFunctionInfo> function_info) { |
472 if (!IsEnabled()) { | 476 if (!IsEnabled()) { |
473 return; | 477 return; |
474 } | 478 } |
475 | 479 |
476 HandleScope scope; | 480 HandleScope scope; |
477 ASSERT(boilerplate->IsBoilerplate()); | |
478 if (is_global) { | 481 if (is_global) { |
479 eval_global.Put(source, context, boilerplate); | 482 eval_global.Put(source, context, function_info); |
480 } else { | 483 } else { |
481 eval_contextual.Put(source, context, boilerplate); | 484 eval_contextual.Put(source, context, function_info); |
482 } | 485 } |
483 } | 486 } |
484 | 487 |
485 | 488 |
486 | 489 |
487 void CompilationCache::PutRegExp(Handle<String> source, | 490 void CompilationCache::PutRegExp(Handle<String> source, |
488 JSRegExp::Flags flags, | 491 JSRegExp::Flags flags, |
489 Handle<FixedArray> data) { | 492 Handle<FixedArray> data) { |
490 if (!IsEnabled()) { | 493 if (!IsEnabled()) { |
491 return; | 494 return; |
(...skipping 29 matching lines...) Expand all Loading... |
521 } | 524 } |
522 | 525 |
523 | 526 |
524 void CompilationCache::Disable() { | 527 void CompilationCache::Disable() { |
525 enabled = false; | 528 enabled = false; |
526 Clear(); | 529 Clear(); |
527 } | 530 } |
528 | 531 |
529 | 532 |
530 } } // namespace v8::internal | 533 } } // namespace v8::internal |
OLD | NEW |