OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/object.h" | 5 #include "vm/object.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "vm/dart_entry.h" | 22 #include "vm/dart_entry.h" |
23 #include "vm/datastream.h" | 23 #include "vm/datastream.h" |
24 #include "vm/debugger.h" | 24 #include "vm/debugger.h" |
25 #include "vm/deopt_instructions.h" | 25 #include "vm/deopt_instructions.h" |
26 #include "vm/disassembler.h" | 26 #include "vm/disassembler.h" |
27 #include "vm/double_conversion.h" | 27 #include "vm/double_conversion.h" |
28 #include "vm/exceptions.h" | 28 #include "vm/exceptions.h" |
29 #include "vm/flow_graph_builder.h" | 29 #include "vm/flow_graph_builder.h" |
30 #include "vm/flow_graph_compiler.h" | 30 #include "vm/flow_graph_compiler.h" |
31 #include "vm/growable_array.h" | 31 #include "vm/growable_array.h" |
32 #include "vm/hash_table.h" | |
33 #include "vm/heap.h" | 32 #include "vm/heap.h" |
34 #include "vm/intermediate_language.h" | 33 #include "vm/intermediate_language.h" |
35 #include "vm/intrinsifier.h" | 34 #include "vm/intrinsifier.h" |
36 #include "vm/object_id_ring.h" | 35 #include "vm/object_id_ring.h" |
37 #include "vm/object_store.h" | 36 #include "vm/object_store.h" |
38 #include "vm/parser.h" | 37 #include "vm/parser.h" |
39 #include "vm/report.h" | 38 #include "vm/report.h" |
40 #include "vm/reusable_handles.h" | 39 #include "vm/reusable_handles.h" |
41 #include "vm/runtime_entry.h" | 40 #include "vm/runtime_entry.h" |
42 #include "vm/scopes.h" | 41 #include "vm/scopes.h" |
(...skipping 8608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8651 obj = LookupLocalObject(accessor_name); | 8650 obj = LookupLocalObject(accessor_name); |
8652 if (obj.IsNull()) { | 8651 if (obj.IsNull()) { |
8653 obj = LookupImportedObject(name); | 8652 obj = LookupImportedObject(name); |
8654 } | 8653 } |
8655 } | 8654 } |
8656 AddToResolvedNamesCache(name, obj); | 8655 AddToResolvedNamesCache(name, obj); |
8657 return obj.raw(); | 8656 return obj.raw(); |
8658 } | 8657 } |
8659 | 8658 |
8660 | 8659 |
8661 class StringEqualsTraits { | 8660 static intptr_t ResolvedNameCacheSize(const Array& cache) { |
8662 public: | 8661 return (cache.Length() - 1) / 2; |
8663 static bool IsMatch(const Object& a, const Object& b) { | 8662 } |
8664 return String::Cast(a).Equals(String::Cast(b)); | |
8665 } | |
8666 static uword Hash(const Object& obj) { | |
8667 return String::Cast(obj).Hash(); | |
8668 } | |
8669 }; | |
8670 typedef UnorderedHashMap<StringEqualsTraits> ResolvedNamesMap; | |
8671 | 8663 |
8672 | 8664 |
8673 // Returns true if the name is found in the cache, false no cache hit. | 8665 // Returns true if the name is found in the cache, false no cache hit. |
8674 // obj is set to the cached entry. It may be null, indicating that the | 8666 // obj is set to the cached entry. It may be null, indicating that the |
8675 // name does not resolve to anything in this library. | 8667 // name does not resolve to anything in this library. |
8676 bool Library::LookupResolvedNamesCache(const String& name, | 8668 bool Library::LookupResolvedNamesCache(const String& name, |
8677 Object* obj) const { | 8669 Object* obj) const { |
8678 ResolvedNamesMap cache(Array::Handle(resolved_names())); | 8670 const Array& cache = Array::Handle(resolved_names()); |
8679 bool present = false; | 8671 const intptr_t cache_size = ResolvedNameCacheSize(cache); |
8680 *obj = cache.GetOrNull(name, &present); | 8672 intptr_t index = name.Hash() % cache_size; |
8681 RawArray* array = cache.Release(); | 8673 String& entry_name = String::Handle(); |
8682 ASSERT(array == resolved_names()); | 8674 entry_name ^= cache.At(index); |
8683 return present; | 8675 while (!entry_name.IsNull()) { |
| 8676 if (entry_name.Equals(name)) { |
| 8677 CompilerStats::num_lib_cache_hit++; |
| 8678 *obj = cache.At(index + cache_size); |
| 8679 return true; |
| 8680 } |
| 8681 index = (index + 1) % cache_size; |
| 8682 entry_name ^= cache.At(index); |
| 8683 } |
| 8684 *obj = Object::null(); |
| 8685 return false; |
| 8686 } |
| 8687 |
| 8688 |
| 8689 void Library::GrowResolvedNamesCache() const { |
| 8690 const Array& old_cache = Array::Handle(resolved_names()); |
| 8691 const intptr_t old_cache_size = ResolvedNameCacheSize(old_cache); |
| 8692 |
| 8693 // Create empty new cache and add entries from the old cache. |
| 8694 const intptr_t new_cache_size = old_cache_size * 3 / 2; |
| 8695 InitResolvedNamesCache(new_cache_size); |
| 8696 String& name = String::Handle(); |
| 8697 Object& entry = Object::Handle(); |
| 8698 for (intptr_t i = 0; i < old_cache_size; i++) { |
| 8699 name ^= old_cache.At(i); |
| 8700 if (!name.IsNull()) { |
| 8701 entry = old_cache.At(i + old_cache_size); |
| 8702 AddToResolvedNamesCache(name, entry); |
| 8703 } |
| 8704 } |
8684 } | 8705 } |
8685 | 8706 |
8686 | 8707 |
8687 // Add a name to the resolved name cache. This name resolves to the | 8708 // Add a name to the resolved name cache. This name resolves to the |
8688 // given object in this library scope. obj may be null, which means | 8709 // given object in this library scope. obj may be null, which means |
8689 // the name does not resolve to anything in this library scope. | 8710 // the name does not resolve to anything in this library scope. |
8690 void Library::AddToResolvedNamesCache(const String& name, | 8711 void Library::AddToResolvedNamesCache(const String& name, |
8691 const Object& obj) const { | 8712 const Object& obj) const { |
8692 if (!FLAG_use_lib_cache) { | 8713 if (!FLAG_use_lib_cache) { |
8693 return; | 8714 return; |
8694 } | 8715 } |
8695 ResolvedNamesMap cache(Array::Handle(resolved_names())); | 8716 ASSERT(!Field::IsGetterName(name) && !Field::IsSetterName(name)); |
8696 cache.UpdateOrInsert(name, obj); | 8717 const Array& cache = Array::Handle(resolved_names()); |
8697 StorePointer(&raw_ptr()->resolved_names_, cache.Release()); | 8718 // let N = cache.Length(); |
| 8719 // The entry cache[N-1] is used as a counter |
| 8720 // The array entries [0..N-2] are used as cache entries. |
| 8721 // cache[i] contains the name of the entry |
| 8722 // cache[i+(N-1)/2] contains the resolved entity, or NULL if that name |
| 8723 // is not present in the library. |
| 8724 const intptr_t counter_index = cache.Length() - 1; |
| 8725 intptr_t cache_size = ResolvedNameCacheSize(cache); |
| 8726 intptr_t index = name.Hash() % cache_size; |
| 8727 String& entry_name = String::Handle(); |
| 8728 entry_name ^= cache.At(index); |
| 8729 // An empty spot will be found because we keep the hash set at most 75% full. |
| 8730 while (!entry_name.IsNull()) { |
| 8731 index = (index + 1) % cache_size; |
| 8732 entry_name ^= cache.At(index); |
| 8733 } |
| 8734 // Insert the object at the empty slot. |
| 8735 cache.SetAt(index, name); |
| 8736 ASSERT(cache.At(index + cache_size) == Object::null()); |
| 8737 cache.SetAt(index + cache_size, obj); |
| 8738 |
| 8739 // One more element added. |
| 8740 intptr_t num_used = Smi::Value(Smi::RawCast(cache.At(counter_index))) + 1; |
| 8741 cache.SetAt(counter_index, Smi::Handle(Smi::New(num_used))); |
| 8742 CompilerStats::num_names_cached++; |
| 8743 |
| 8744 // Rehash if symbol_table is 75% full. |
| 8745 if (num_used > ((cache_size / 4) * 3)) { |
| 8746 CompilerStats::num_names_cached -= num_used; |
| 8747 GrowResolvedNamesCache(); |
| 8748 } |
8698 } | 8749 } |
8699 | 8750 |
8700 | 8751 |
8701 void Library::InvalidateResolvedName(const String& name) const { | 8752 void Library::InvalidateResolvedName(const String& name) const { |
8702 Object& entry = Object::Handle(); | 8753 Object& entry = Object::Handle(); |
8703 if (LookupResolvedNamesCache(name, &entry)) { | 8754 if (LookupResolvedNamesCache(name, &entry)) { |
8704 // TODO(koda): Support deleted sentinel in snapshots and remove only 'name'. | |
8705 InvalidateResolvedNamesCache(); | 8755 InvalidateResolvedNamesCache(); |
8706 } | 8756 } |
8707 } | 8757 } |
8708 | 8758 |
8709 | 8759 |
8710 void Library::InvalidateResolvedNamesCache() const { | 8760 void Library::InvalidateResolvedNamesCache() const { |
8711 const intptr_t kInvalidatedCacheSize = 16; | 8761 const intptr_t kInvalidatedCacheSize = 16; |
8712 InitResolvedNamesCache(kInvalidatedCacheSize); | 8762 InitResolvedNamesCache(kInvalidatedCacheSize); |
8713 } | 8763 } |
8714 | 8764 |
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9211 | 9261 |
9212 static RawArray* NewDictionary(intptr_t initial_size) { | 9262 static RawArray* NewDictionary(intptr_t initial_size) { |
9213 const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); | 9263 const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); |
9214 // The last element of the dictionary specifies the number of in use slots. | 9264 // The last element of the dictionary specifies the number of in use slots. |
9215 dict.SetAt(initial_size, Smi::Handle(Smi::New(0))); | 9265 dict.SetAt(initial_size, Smi::Handle(Smi::New(0))); |
9216 return dict.raw(); | 9266 return dict.raw(); |
9217 } | 9267 } |
9218 | 9268 |
9219 | 9269 |
9220 void Library::InitResolvedNamesCache(intptr_t size) const { | 9270 void Library::InitResolvedNamesCache(intptr_t size) const { |
9221 const Array& cache = Array::Handle(HashTables::New<ResolvedNamesMap>(size)); | 9271 // Need space for 'size' names and 'size' resolved object entries. |
9222 StorePointer(&raw_ptr()->resolved_names_, cache.raw()); | 9272 StorePointer(&raw_ptr()->resolved_names_, NewDictionary(2 * size)); |
9223 } | 9273 } |
9224 | 9274 |
9225 | 9275 |
9226 void Library::InitClassDictionary() const { | 9276 void Library::InitClassDictionary() const { |
9227 // TODO(iposva): Find reasonable initial size. | 9277 // TODO(iposva): Find reasonable initial size. |
9228 const int kInitialElementCount = 16; | 9278 const int kInitialElementCount = 16; |
9229 StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount)); | 9279 StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount)); |
9230 } | 9280 } |
9231 | 9281 |
9232 | 9282 |
(...skipping 9801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19034 return tag_label.ToCString(); | 19084 return tag_label.ToCString(); |
19035 } | 19085 } |
19036 | 19086 |
19037 | 19087 |
19038 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 19088 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
19039 Instance::PrintJSONImpl(stream, ref); | 19089 Instance::PrintJSONImpl(stream, ref); |
19040 } | 19090 } |
19041 | 19091 |
19042 | 19092 |
19043 } // namespace dart | 19093 } // namespace dart |
OLD | NEW |