| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/api.h" | 7 #include "src/api.h" |
| 8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
| 9 #include "src/ast.h" | 9 #include "src/ast.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 : isolate_(isolate) { } | 26 : isolate_(isolate) { } |
| 27 | 27 |
| 28 | 28 |
| 29 void StubCache::Initialize() { | 29 void StubCache::Initialize() { |
| 30 ASSERT(IsPowerOf2(kPrimaryTableSize)); | 30 ASSERT(IsPowerOf2(kPrimaryTableSize)); |
| 31 ASSERT(IsPowerOf2(kSecondaryTableSize)); | 31 ASSERT(IsPowerOf2(kSecondaryTableSize)); |
| 32 Clear(); | 32 Clear(); |
| 33 } | 33 } |
| 34 | 34 |
| 35 | 35 |
| 36 Code* StubCache::Set(Name* name, Map* map, Code* code) { | 36 static Code::Flags CommonStubCacheChecks(Name* name, Map* map, |
| 37 // Get the flags from the code. | 37 Code::Flags flags, Heap* heap) { |
| 38 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); | 38 flags = Code::RemoveTypeAndHolderFromFlags(flags); |
| 39 | 39 |
| 40 // Validate that the name does not move on scavenge, and that we | 40 // Validate that the name does not move on scavenge, and that we |
| 41 // can use identity checks instead of structural equality checks. | 41 // can use identity checks instead of structural equality checks. |
| 42 ASSERT(!heap()->InNewSpace(name)); | 42 ASSERT(!heap->InNewSpace(name)); |
| 43 ASSERT(name->IsUniqueName()); | 43 ASSERT(name->IsUniqueName()); |
| 44 | 44 |
| 45 // The state bits are not important to the hash function because | 45 // The state bits are not important to the hash function because |
| 46 // the stub cache only contains monomorphic stubs. Make sure that | 46 // the stub cache only contains monomorphic stubs. Make sure that |
| 47 // the bits are the least significant so they will be the ones | 47 // the bits are the least significant so they will be the ones |
| 48 // masked out. | 48 // masked out. |
| 49 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); | 49 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); |
| 50 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1); | 50 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1); |
| 51 | 51 |
| 52 // Make sure that the code type is not included in the hash. | 52 // Make sure that the code type and cache holder are not included in the hash. |
| 53 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); | 53 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); |
| 54 ASSERT(Code::ExtractCacheHolderFromFlags(flags) == 0); |
| 55 |
| 56 return flags; |
| 57 } |
| 58 |
| 59 |
| 60 Code* StubCache::Set(Name* name, Map* map, Code* code) { |
| 61 Code::Flags flags = CommonStubCacheChecks(name, map, code->flags(), heap()); |
| 54 | 62 |
| 55 // Compute the primary entry. | 63 // Compute the primary entry. |
| 56 int primary_offset = PrimaryOffset(name, flags, map); | 64 int primary_offset = PrimaryOffset(name, flags, map); |
| 57 Entry* primary = entry(primary_, primary_offset); | 65 Entry* primary = entry(primary_, primary_offset); |
| 58 Code* old_code = primary->value; | 66 Code* old_code = primary->value; |
| 59 | 67 |
| 60 // If the primary entry has useful data in it, we retire it to the | 68 // If the primary entry has useful data in it, we retire it to the |
| 61 // secondary cache before overwriting it. | 69 // secondary cache before overwriting it. |
| 62 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) { | 70 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) { |
| 63 Map* old_map = primary->map; | 71 Map* old_map = primary->map; |
| 64 Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags()); | 72 Code::Flags old_flags = |
| 73 Code::RemoveTypeAndHolderFromFlags(old_code->flags()); |
| 65 int seed = PrimaryOffset(primary->key, old_flags, old_map); | 74 int seed = PrimaryOffset(primary->key, old_flags, old_map); |
| 66 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed); | 75 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed); |
| 67 Entry* secondary = entry(secondary_, secondary_offset); | 76 Entry* secondary = entry(secondary_, secondary_offset); |
| 68 *secondary = *primary; | 77 *secondary = *primary; |
| 69 } | 78 } |
| 70 | 79 |
| 71 // Update primary cache. | 80 // Update primary cache. |
| 72 primary->key = name; | 81 primary->key = name; |
| 73 primary->value = code; | 82 primary->value = code; |
| 74 primary->map = map; | 83 primary->map = map; |
| 75 isolate()->counters()->megamorphic_stub_cache_updates()->Increment(); | 84 isolate()->counters()->megamorphic_stub_cache_updates()->Increment(); |
| 76 return code; | 85 return code; |
| 77 } | 86 } |
| 78 | 87 |
| 79 | 88 |
| 80 Handle<Code> StubCache::FindIC(Handle<Name> name, | 89 Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) { |
| 81 Handle<Map> stub_holder, | 90 flags = CommonStubCacheChecks(name, map, flags, heap()); |
| 82 Code::Kind kind, | 91 int primary_offset = PrimaryOffset(name, flags, map); |
| 83 ExtraICState extra_state, | 92 Entry* primary = entry(primary_, primary_offset); |
| 84 InlineCacheHolderFlag cache_holder) { | 93 if (primary->key == name && primary->map == map) { |
| 94 return primary->value; |
| 95 } |
| 96 int secondary_offset = SecondaryOffset(name, flags, primary_offset); |
| 97 Entry* secondary = entry(secondary_, secondary_offset); |
| 98 if (secondary->key == name && secondary->map == map) { |
| 99 return secondary->value; |
| 100 } |
| 101 return NULL; |
| 102 } |
| 103 |
| 104 |
| 105 Handle<Code> StubCache::FindIC(Handle<Name> name, Handle<Map> stub_holder, |
| 106 Code::Kind kind, ExtraICState extra_state, |
| 107 CacheHolderFlag cache_holder) { |
| 85 Code::Flags flags = Code::ComputeMonomorphicFlags( | 108 Code::Flags flags = Code::ComputeMonomorphicFlags( |
| 86 kind, extra_state, cache_holder); | 109 kind, extra_state, cache_holder); |
| 87 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); | 110 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); |
| 88 if (probe->IsCode()) return Handle<Code>::cast(probe); | 111 if (probe->IsCode()) return Handle<Code>::cast(probe); |
| 89 return Handle<Code>::null(); | 112 return Handle<Code>::null(); |
| 90 } | 113 } |
| 91 | 114 |
| 92 | 115 |
| 93 Handle<Code> StubCache::FindHandler(Handle<Name> name, | 116 Handle<Code> StubCache::FindHandler(Handle<Name> name, Handle<Map> stub_holder, |
| 94 Handle<Map> stub_holder, | |
| 95 Code::Kind kind, | 117 Code::Kind kind, |
| 96 InlineCacheHolderFlag cache_holder, | 118 CacheHolderFlag cache_holder, |
| 97 Code::StubType type) { | 119 Code::StubType type) { |
| 98 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); | 120 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); |
| 99 | 121 |
| 100 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); | 122 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); |
| 101 if (probe->IsCode()) return Handle<Code>::cast(probe); | 123 if (probe->IsCode()) return Handle<Code>::cast(probe); |
| 102 return Handle<Code>::null(); | 124 return Handle<Code>::null(); |
| 103 } | 125 } |
| 104 | 126 |
| 105 | 127 |
| 106 Handle<Code> StubCache::ComputeMonomorphicIC( | 128 Handle<Code> StubCache::ComputeMonomorphicIC( |
| 107 Code::Kind kind, | 129 Code::Kind kind, |
| 108 Handle<Name> name, | 130 Handle<Name> name, |
| 109 Handle<HeapType> type, | 131 Handle<HeapType> type, |
| 110 Handle<Code> handler, | 132 Handle<Code> handler, |
| 111 ExtraICState extra_ic_state) { | 133 ExtraICState extra_ic_state) { |
| 112 InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); | 134 CacheHolderFlag flag; |
| 135 Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate(), &flag); |
| 113 | 136 |
| 114 Handle<Map> stub_holder; | |
| 115 Handle<Code> ic; | 137 Handle<Code> ic; |
| 116 // There are multiple string maps that all use the same prototype. That | 138 // There are multiple string maps that all use the same prototype. That |
| 117 // prototype cannot hold multiple handlers, one for each of the string maps, | 139 // prototype cannot hold multiple handlers, one for each of the string maps, |
| 118 // for a single name. Hence, turn off caching of the IC. | 140 // for a single name. Hence, turn off caching of the IC. |
| 119 bool can_be_cached = !type->Is(HeapType::String()); | 141 bool can_be_cached = !type->Is(HeapType::String()); |
| 120 if (can_be_cached) { | 142 if (can_be_cached) { |
| 121 stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); | |
| 122 ic = FindIC(name, stub_holder, kind, extra_ic_state, flag); | 143 ic = FindIC(name, stub_holder, kind, extra_ic_state, flag); |
| 123 if (!ic.is_null()) return ic; | 144 if (!ic.is_null()) return ic; |
| 124 } | 145 } |
| 125 | 146 |
| 126 if (kind == Code::LOAD_IC) { | 147 if (kind == Code::LOAD_IC) { |
| 127 LoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag); | 148 LoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag); |
| 128 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); | 149 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); |
| 129 } else if (kind == Code::KEYED_LOAD_IC) { | 150 } else if (kind == Code::KEYED_LOAD_IC) { |
| 130 KeyedLoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag); | 151 KeyedLoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag); |
| 131 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); | 152 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); |
| 132 } else if (kind == Code::STORE_IC) { | 153 } else if (kind == Code::STORE_IC) { |
| 133 StoreStubCompiler ic_compiler(isolate(), extra_ic_state); | 154 StoreStubCompiler ic_compiler(isolate(), extra_ic_state); |
| 134 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); | 155 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); |
| 135 } else { | 156 } else { |
| 136 ASSERT(kind == Code::KEYED_STORE_IC); | 157 ASSERT(kind == Code::KEYED_STORE_IC); |
| 137 ASSERT(STANDARD_STORE == | 158 ASSERT(STANDARD_STORE == |
| 138 KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state)); | 159 KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state)); |
| 139 KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state); | 160 KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state); |
| 140 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); | 161 ic = ic_compiler.CompileMonomorphicIC(type, handler, name); |
| 141 } | 162 } |
| 142 | 163 |
| 143 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); | 164 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); |
| 144 return ic; | 165 return ic; |
| 145 } | 166 } |
| 146 | 167 |
| 147 | 168 |
| 148 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, | 169 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, |
| 149 Handle<HeapType> type) { | 170 Handle<HeapType> type) { |
| 150 InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); | 171 Handle<Map> receiver_map = IC::TypeToMap(*type, isolate()); |
| 151 Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); | 172 if (receiver_map->prototype()->IsNull()) { |
| 173 // TODO(jkummerow/verwaest): If there is no prototype and the property |
| 174 // is nonexistent, introduce a builtin to handle this (fast properties |
| 175 // -> return undefined, dictionary properties -> do negative lookup). |
| 176 return Handle<Code>(); |
| 177 } |
| 178 CacheHolderFlag flag; |
| 179 Handle<Map> stub_holder_map = |
| 180 IC::GetHandlerCacheHolder(*type, false, isolate(), &flag); |
| 181 |
| 152 // If no dictionary mode objects are present in the prototype chain, the load | 182 // If no dictionary mode objects are present in the prototype chain, the load |
| 153 // nonexistent IC stub can be shared for all names for a given map and we use | 183 // nonexistent IC stub can be shared for all names for a given map and we use |
| 154 // the empty string for the map cache in that case. If there are dictionary | 184 // the empty string for the map cache in that case. If there are dictionary |
| 155 // mode objects involved, we need to do negative lookups in the stub and | 185 // mode objects involved, we need to do negative lookups in the stub and |
| 156 // therefore the stub will be specific to the name. | 186 // therefore the stub will be specific to the name. |
| 157 Handle<Map> current_map = stub_holder; | 187 Handle<Name> cache_name = |
| 158 Handle<Name> cache_name = current_map->is_dictionary_map() | 188 receiver_map->is_dictionary_map() |
| 159 ? name : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol()); | 189 ? name |
| 160 Handle<Object> next(current_map->prototype(), isolate()); | 190 : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol()); |
| 161 Handle<JSObject> last = Handle<JSObject>::null(); | 191 Handle<Map> current_map = stub_holder_map; |
| 162 while (!next->IsNull()) { | 192 Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); |
| 163 last = Handle<JSObject>::cast(next); | 193 while (true) { |
| 164 next = handle(current_map->prototype(), isolate()); | |
| 165 current_map = handle(Handle<HeapObject>::cast(next)->map()); | |
| 166 if (current_map->is_dictionary_map()) cache_name = name; | 194 if (current_map->is_dictionary_map()) cache_name = name; |
| 195 if (current_map->prototype()->IsNull()) break; |
| 196 last = handle(JSObject::cast(current_map->prototype())); |
| 197 current_map = handle(last->map()); |
| 167 } | 198 } |
| 168 | |
| 169 // Compile the stub that is either shared for all names or | 199 // Compile the stub that is either shared for all names or |
| 170 // name specific if there are global objects involved. | 200 // name specific if there are global objects involved. |
| 171 Handle<Code> handler = FindHandler( | 201 Handle<Code> handler = |
| 172 cache_name, stub_holder, Code::LOAD_IC, flag, Code::FAST); | 202 FindHandler(cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST); |
| 173 if (!handler.is_null()) { | 203 if (!handler.is_null()) { |
| 174 return handler; | 204 return handler; |
| 175 } | 205 } |
| 176 | 206 |
| 177 LoadStubCompiler compiler(isolate_, kNoExtraICState, flag); | 207 LoadStubCompiler compiler(isolate_, kNoExtraICState, flag); |
| 178 handler = compiler.CompileLoadNonexistent(type, last, cache_name); | 208 handler = compiler.CompileLoadNonexistent(type, last, cache_name); |
| 179 Map::UpdateCodeCache(stub_holder, cache_name, handler); | 209 Map::UpdateCodeCache(stub_holder_map, cache_name, handler); |
| 180 return handler; | 210 return handler; |
| 181 } | 211 } |
| 182 | 212 |
| 183 | 213 |
| 184 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) { | 214 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) { |
| 185 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); | 215 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); |
| 186 Handle<Name> name = | 216 Handle<Name> name = |
| 187 isolate()->factory()->KeyedLoadElementMonomorphic_string(); | 217 isolate()->factory()->KeyedLoadElementMonomorphic_string(); |
| 188 | 218 |
| 189 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); | 219 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); |
| 190 if (probe->IsCode()) return Handle<Code>::cast(probe); | 220 if (probe->IsCode()) return Handle<Code>::cast(probe); |
| 191 | 221 |
| 192 KeyedLoadStubCompiler compiler(isolate()); | 222 KeyedLoadStubCompiler compiler(isolate()); |
| 193 Handle<Code> code = compiler.CompileLoadElement(receiver_map); | 223 Handle<Code> code = compiler.CompileLoadElement(receiver_map); |
| 194 | 224 |
| 195 Map::UpdateCodeCache(receiver_map, name, code); | 225 Map::UpdateCodeCache(receiver_map, name, code); |
| 196 return code; | 226 return code; |
| 197 } | 227 } |
| 198 | 228 |
| 199 | 229 |
| 200 Handle<Code> StubCache::ComputeKeyedStoreElement( | 230 Handle<Code> StubCache::ComputeKeyedStoreElement( |
| 201 Handle<Map> receiver_map, | 231 Handle<Map> receiver_map, |
| 202 StrictMode strict_mode, | 232 StrictMode strict_mode, |
| 203 KeyedAccessStoreMode store_mode) { | 233 KeyedAccessStoreMode store_mode) { |
| 204 ExtraICState extra_state = | 234 ExtraICState extra_state = |
| 205 KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode); | 235 KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode); |
| 206 Code::Flags flags = Code::ComputeMonomorphicFlags( | 236 Code::Flags flags = |
| 207 Code::KEYED_STORE_IC, extra_state); | 237 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state); |
| 208 | 238 |
| 209 ASSERT(store_mode == STANDARD_STORE || | 239 ASSERT(store_mode == STANDARD_STORE || |
| 210 store_mode == STORE_AND_GROW_NO_TRANSITION || | 240 store_mode == STORE_AND_GROW_NO_TRANSITION || |
| 211 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || | 241 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || |
| 212 store_mode == STORE_NO_TRANSITION_HANDLE_COW); | 242 store_mode == STORE_NO_TRANSITION_HANDLE_COW); |
| 213 | 243 |
| 214 Handle<String> name = | 244 Handle<String> name = |
| 215 isolate()->factory()->KeyedStoreElementMonomorphic_string(); | 245 isolate()->factory()->KeyedStoreElementMonomorphic_string(); |
| 216 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); | 246 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); |
| 217 if (probe->IsCode()) return Handle<Code>::cast(probe); | 247 if (probe->IsCode()) return Handle<Code>::cast(probe); |
| (...skipping 1185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 Handle<FunctionTemplateInfo>( | 1433 Handle<FunctionTemplateInfo>( |
| 1404 FunctionTemplateInfo::cast(signature->receiver())); | 1434 FunctionTemplateInfo::cast(signature->receiver())); |
| 1405 } | 1435 } |
| 1406 } | 1436 } |
| 1407 | 1437 |
| 1408 is_simple_api_call_ = true; | 1438 is_simple_api_call_ = true; |
| 1409 } | 1439 } |
| 1410 | 1440 |
| 1411 | 1441 |
| 1412 } } // namespace v8::internal | 1442 } } // namespace v8::internal |
| OLD | NEW |