| 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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 result = AllocateTable(kInitialCacheSize); | 53 result = AllocateTable(kInitialCacheSize); |
| 54 tables[entry] = *result; | 54 tables[entry] = *result; |
| 55 } else { | 55 } else { |
| 56 CompilationCacheTable* table = CompilationCacheTable::cast(tables[entry]); | 56 CompilationCacheTable* table = CompilationCacheTable::cast(tables[entry]); |
| 57 result = Handle<CompilationCacheTable>(table); | 57 result = Handle<CompilationCacheTable>(table); |
| 58 } | 58 } |
| 59 return result; | 59 return result; |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 // We only re-use a cached function for some script source code if the | |
| 64 // script originates from the same places. This is to avoid issues | |
| 65 // when reporting errors, etc. | |
| 66 static bool HasOrigin(Handle<JSFunction> boilerplate, | |
| 67 Handle<Object> name, | |
| 68 int line_offset, | |
| 69 int column_offset) { | |
| 70 Handle<Script> script = | |
| 71 Handle<Script>(Script::cast(boilerplate->shared()->script())); | |
| 72 // If the script name isn't set, the boilerplate script should have | |
| 73 // an undefined name to have the same origin. | |
| 74 if (name.is_null()) { | |
| 75 return script->name()->IsUndefined(); | |
| 76 } | |
| 77 // Do the fast bailout checks first. | |
| 78 if (line_offset != script->line_offset()->value()) return false; | |
| 79 if (column_offset != script->column_offset()->value()) return false; | |
| 80 // Check that both names are strings. If not, no match. | |
| 81 if (!name->IsString() || !script->name()->IsString()) return false; | |
| 82 // Compare the two name strings for equality. | |
| 83 return String::cast(*name)->Equals(String::cast(script->name())); | |
| 84 } | |
| 85 | |
| 86 | |
| 87 static Handle<JSFunction> Lookup(Handle<String> source, | 63 static Handle<JSFunction> Lookup(Handle<String> source, |
| 64 Handle<Context> context, |
| 88 CompilationCache::Entry entry) { | 65 CompilationCache::Entry entry) { |
| 89 // Make sure not to leak the table into the surrounding handle | 66 // Make sure not to leak the table into the surrounding handle |
| 90 // scope. Otherwise, we risk keeping old tables around even after | 67 // scope. Otherwise, we risk keeping old tables around even after |
| 91 // having cleared the cache. | 68 // having cleared the cache. |
| 92 Object* result; | 69 Object* result; |
| 93 { HandleScope scope; | 70 { HandleScope scope; |
| 94 Handle<CompilationCacheTable> table = GetTable(entry); | 71 Handle<CompilationCacheTable> table = GetTable(entry); |
| 95 result = table->Lookup(*source); | 72 result = table->LookupEval(*source, *context); |
| 96 } | 73 } |
| 97 if (result->IsJSFunction()) { | 74 if (result->IsJSFunction()) { |
| 98 return Handle<JSFunction>(JSFunction::cast(result)); | 75 return Handle<JSFunction>(JSFunction::cast(result)); |
| 99 } else { | 76 } else { |
| 100 return Handle<JSFunction>::null(); | 77 return Handle<JSFunction>::null(); |
| 101 } | 78 } |
| 102 } | 79 } |
| 103 | 80 |
| 104 | 81 |
| 105 static Handle<JSFunction> Lookup(Handle<String> source, | 82 static Handle<FixedArray> Lookup(Handle<String> source, |
| 106 Handle<Context> context, | 83 JSRegExp::Flags flags) { |
| 107 CompilationCache::Entry entry) { | |
| 108 // Make sure not to leak the table into the surrounding handle | 84 // Make sure not to leak the table into the surrounding handle |
| 109 // scope. Otherwise, we risk keeping old tables around even after | 85 // scope. Otherwise, we risk keeping old tables around even after |
| 110 // having cleared the cache. | 86 // having cleared the cache. |
| 111 Object* result; | 87 Object* result; |
| 112 { HandleScope scope; | 88 { HandleScope scope; |
| 113 Handle<CompilationCacheTable> table = GetTable(entry); | 89 Handle<CompilationCacheTable> table = GetTable(CompilationCache::REGEXP); |
| 114 result = table->LookupEval(*source, *context); | 90 result = table->LookupRegExp(*source, flags); |
| 115 } | 91 } |
| 116 if (result->IsJSFunction()) { | 92 if (result->IsFixedArray()) { |
| 117 return Handle<JSFunction>(JSFunction::cast(result)); | 93 return Handle<FixedArray>(FixedArray::cast(result)); |
| 118 } else { | 94 } else { |
| 119 return Handle<JSFunction>::null(); | 95 return Handle<FixedArray>::null(); |
| 120 } | 96 } |
| 121 } | 97 } |
| 122 | 98 |
| 123 | 99 |
| 124 Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source, | 100 Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source, |
| 125 Handle<Object> name, | 101 Handle<Object> name, |
| 126 int line_offset, | 102 int line_offset, |
| 127 int column_offset) { | 103 int column_offset) { |
| 128 Handle<JSFunction> result = Lookup(source, SCRIPT); | 104 // TODO(xxx): Start caching scripts again but make it local to a |
| 129 if (result.is_null()) { | 105 // global context to avoid sharing code between independent |
| 130 Counters::compilation_cache_misses.Increment(); | 106 // environments. |
| 131 } else if (HasOrigin(result, name, line_offset, column_offset)) { | 107 return Handle<JSFunction>::null(); |
| 132 Counters::compilation_cache_hits.Increment(); | |
| 133 } else { | |
| 134 result = Handle<JSFunction>::null(); | |
| 135 Counters::compilation_cache_misses.Increment(); | |
| 136 } | |
| 137 return result; | |
| 138 } | 108 } |
| 139 | 109 |
| 140 | 110 |
| 141 Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source, | 111 Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source, |
| 142 Handle<Context> context, | 112 Handle<Context> context, |
| 143 Entry entry) { | 113 Entry entry) { |
| 144 ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL); | 114 ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL); |
| 145 Handle<JSFunction> result = Lookup(source, context, entry); | 115 Handle<JSFunction> result = Lookup(source, context, entry); |
| 146 if (result.is_null()) { | 116 if (result.is_null()) { |
| 147 Counters::compilation_cache_misses.Increment(); | 117 Counters::compilation_cache_misses.Increment(); |
| 148 } else { | 118 } else { |
| 149 Counters::compilation_cache_hits.Increment(); | 119 Counters::compilation_cache_hits.Increment(); |
| 150 } | 120 } |
| 151 return result; | 121 return result; |
| 152 } | 122 } |
| 153 | 123 |
| 154 | 124 |
| 155 void CompilationCache::PutFunction(Handle<String> source, | 125 Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, |
| 156 Entry entry, | 126 JSRegExp::Flags flags) { |
| 157 Handle<JSFunction> boilerplate) { | 127 Handle<FixedArray> result = Lookup(source, flags); |
| 128 if (result.is_null()) { |
| 129 Counters::compilation_cache_misses.Increment(); |
| 130 } else { |
| 131 Counters::compilation_cache_hits.Increment(); |
| 132 } |
| 133 return result; |
| 134 } |
| 135 |
| 136 |
| 137 void CompilationCache::PutScript(Handle<String> source, |
| 138 Entry entry, |
| 139 Handle<JSFunction> boilerplate) { |
| 140 // TODO(xxx): Start caching scripts again but make it local to a |
| 141 // global context to avoid sharing code between independent |
| 142 // environments. |
| 143 } |
| 144 |
| 145 |
| 146 void CompilationCache::PutEval(Handle<String> source, |
| 147 Handle<Context> context, |
| 148 Entry entry, |
| 149 Handle<JSFunction> boilerplate) { |
| 158 HandleScope scope; | 150 HandleScope scope; |
| 159 ASSERT(boilerplate->IsBoilerplate()); | 151 ASSERT(boilerplate->IsBoilerplate()); |
| 160 Handle<CompilationCacheTable> table = GetTable(entry); | 152 Handle<CompilationCacheTable> table = GetTable(entry); |
| 161 CALL_HEAP_FUNCTION_VOID(table->Put(*source, *boilerplate)); | |
| 162 } | |
| 163 | |
| 164 | |
| 165 void CompilationCache::PutEvalFunction(Handle<String> source, | |
| 166 Handle<Context> context, | |
| 167 Entry entry, | |
| 168 Handle<JSFunction> boilerplate) { | |
| 169 HandleScope scope; | |
| 170 ASSERT(boilerplate->IsBoilerplate()); | |
| 171 Handle<CompilationCacheTable> table = GetTable(entry); | |
| 172 CALL_HEAP_FUNCTION_VOID(table->PutEval(*source, *context, *boilerplate)); | 153 CALL_HEAP_FUNCTION_VOID(table->PutEval(*source, *context, *boilerplate)); |
| 173 } | 154 } |
| 174 | 155 |
| 175 | 156 |
| 176 Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source, | |
| 177 JSRegExp::Flags flags) { | |
| 178 Handle<CompilationCacheTable> table = GetTable(REGEXP); | |
| 179 Object* result = table->LookupRegExp(*source, flags); | |
| 180 if (result->IsFixedArray()) { | |
| 181 Counters::regexp_cache_hits.Increment(); | |
| 182 return Handle<FixedArray>(FixedArray::cast(result)); | |
| 183 } else { | |
| 184 Counters::regexp_cache_misses.Increment(); | |
| 185 return Handle<FixedArray>(); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 | 157 |
| 190 void CompilationCache::PutRegExp(Handle<String> source, | 158 void CompilationCache::PutRegExp(Handle<String> source, |
| 191 JSRegExp::Flags flags, | 159 JSRegExp::Flags flags, |
| 192 Handle<FixedArray> data) { | 160 Handle<FixedArray> data) { |
| 193 HandleScope scope; | 161 HandleScope scope; |
| 194 Handle<CompilationCacheTable> table = GetTable(REGEXP); | 162 Handle<CompilationCacheTable> table = GetTable(REGEXP); |
| 195 CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data)); | 163 CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data)); |
| 196 } | 164 } |
| 197 | 165 |
| 198 | 166 |
| 199 void CompilationCache::Clear() { | 167 void CompilationCache::Clear() { |
| 200 for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) { | 168 for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) { |
| 201 tables[i] = Heap::undefined_value(); | 169 tables[i] = Heap::undefined_value(); |
| 202 } | 170 } |
| 203 } | 171 } |
| 204 | 172 |
| 205 | 173 |
| 206 void CompilationCache::Iterate(ObjectVisitor* v) { | 174 void CompilationCache::Iterate(ObjectVisitor* v) { |
| 207 v->VisitPointers(&tables[0], &tables[NUMBER_OF_ENTRY_KINDS]); | 175 v->VisitPointers(&tables[0], &tables[NUMBER_OF_ENTRY_KINDS]); |
| 208 } | 176 } |
| 209 | 177 |
| 210 | 178 |
| 211 } } // namespace v8::internal | 179 } } // namespace v8::internal |
| OLD | NEW |