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 |