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" |
32 #include "vm/heap.h" | 33 #include "vm/heap.h" |
33 #include "vm/intermediate_language.h" | 34 #include "vm/intermediate_language.h" |
34 #include "vm/intrinsifier.h" | 35 #include "vm/intrinsifier.h" |
35 #include "vm/object_id_ring.h" | 36 #include "vm/object_id_ring.h" |
36 #include "vm/object_store.h" | 37 #include "vm/object_store.h" |
37 #include "vm/parser.h" | 38 #include "vm/parser.h" |
38 #include "vm/report.h" | 39 #include "vm/report.h" |
39 #include "vm/reusable_handles.h" | 40 #include "vm/reusable_handles.h" |
40 #include "vm/runtime_entry.h" | 41 #include "vm/runtime_entry.h" |
41 #include "vm/scopes.h" | 42 #include "vm/scopes.h" |
(...skipping 8560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8602 obj = LookupLocalObject(accessor_name); | 8603 obj = LookupLocalObject(accessor_name); |
8603 if (obj.IsNull()) { | 8604 if (obj.IsNull()) { |
8604 obj = LookupImportedObject(name); | 8605 obj = LookupImportedObject(name); |
8605 } | 8606 } |
8606 } | 8607 } |
8607 AddToResolvedNamesCache(name, obj); | 8608 AddToResolvedNamesCache(name, obj); |
8608 return obj.raw(); | 8609 return obj.raw(); |
8609 } | 8610 } |
8610 | 8611 |
8611 | 8612 |
8612 static intptr_t ResolvedNameCacheSize(const Array& cache) { | 8613 class StringEqualsTraits { |
8613 return (cache.Length() - 1) / 2; | 8614 public: |
8614 } | 8615 static bool IsMatch(const Object& a, const Object& b) { |
| 8616 return String::Cast(a).Equals(String::Cast(b)); |
| 8617 } |
| 8618 static uword Hash(const Object& obj) { |
| 8619 return String::Cast(obj).Hash(); |
| 8620 } |
| 8621 }; |
| 8622 typedef UnorderedHashMap<StringEqualsTraits> ResolvedNamesMap; |
8615 | 8623 |
8616 | 8624 |
8617 // Returns true if the name is found in the cache, false no cache hit. | 8625 // Returns true if the name is found in the cache, false no cache hit. |
8618 // obj is set to the cached entry. It may be null, indicating that the | 8626 // obj is set to the cached entry. It may be null, indicating that the |
8619 // name does not resolve to anything in this library. | 8627 // name does not resolve to anything in this library. |
8620 bool Library::LookupResolvedNamesCache(const String& name, | 8628 bool Library::LookupResolvedNamesCache(const String& name, |
8621 Object* obj) const { | 8629 Object* obj) const { |
8622 const Array& cache = Array::Handle(resolved_names()); | 8630 ResolvedNamesMap cache(Array::Handle(resolved_names())); |
8623 const intptr_t cache_size = ResolvedNameCacheSize(cache); | 8631 bool present = false; |
8624 intptr_t index = name.Hash() % cache_size; | 8632 *obj = cache.GetOrNull(name, &present); |
8625 String& entry_name = String::Handle(); | 8633 RawArray* array = cache.Release(); |
8626 entry_name ^= cache.At(index); | 8634 ASSERT(array == resolved_names()); |
8627 while (!entry_name.IsNull()) { | 8635 return present; |
8628 if (entry_name.Equals(name)) { | |
8629 CompilerStats::num_lib_cache_hit++; | |
8630 *obj = cache.At(index + cache_size); | |
8631 return true; | |
8632 } | |
8633 index = (index + 1) % cache_size; | |
8634 entry_name ^= cache.At(index); | |
8635 } | |
8636 *obj = Object::null(); | |
8637 return false; | |
8638 } | |
8639 | |
8640 | |
8641 void Library::GrowResolvedNamesCache() const { | |
8642 const Array& old_cache = Array::Handle(resolved_names()); | |
8643 const intptr_t old_cache_size = ResolvedNameCacheSize(old_cache); | |
8644 | |
8645 // Create empty new cache and add entries from the old cache. | |
8646 const intptr_t new_cache_size = old_cache_size * 3 / 2; | |
8647 InitResolvedNamesCache(new_cache_size); | |
8648 String& name = String::Handle(); | |
8649 Object& entry = Object::Handle(); | |
8650 for (intptr_t i = 0; i < old_cache_size; i++) { | |
8651 name ^= old_cache.At(i); | |
8652 if (!name.IsNull()) { | |
8653 entry = old_cache.At(i + old_cache_size); | |
8654 AddToResolvedNamesCache(name, entry); | |
8655 } | |
8656 } | |
8657 } | 8636 } |
8658 | 8637 |
8659 | 8638 |
8660 // Add a name to the resolved name cache. This name resolves to the | 8639 // Add a name to the resolved name cache. This name resolves to the |
8661 // given object in this library scope. obj may be null, which means | 8640 // given object in this library scope. obj may be null, which means |
8662 // the name does not resolve to anything in this library scope. | 8641 // the name does not resolve to anything in this library scope. |
8663 void Library::AddToResolvedNamesCache(const String& name, | 8642 void Library::AddToResolvedNamesCache(const String& name, |
8664 const Object& obj) const { | 8643 const Object& obj) const { |
8665 if (!FLAG_use_lib_cache) { | 8644 if (!FLAG_use_lib_cache) { |
8666 return; | 8645 return; |
8667 } | 8646 } |
8668 ASSERT(!Field::IsGetterName(name) && !Field::IsSetterName(name)); | 8647 ResolvedNamesMap cache(Array::Handle(resolved_names())); |
8669 const Array& cache = Array::Handle(resolved_names()); | 8648 cache.UpdateOrInsert(name, obj); |
8670 // let N = cache.Length(); | 8649 StorePointer(&raw_ptr()->resolved_names_, cache.Release()); |
8671 // The entry cache[N-1] is used as a counter | |
8672 // The array entries [0..N-2] are used as cache entries. | |
8673 // cache[i] contains the name of the entry | |
8674 // cache[i+(N-1)/2] contains the resolved entity, or NULL if that name | |
8675 // is not present in the library. | |
8676 const intptr_t counter_index = cache.Length() - 1; | |
8677 intptr_t cache_size = ResolvedNameCacheSize(cache); | |
8678 intptr_t index = name.Hash() % cache_size; | |
8679 String& entry_name = String::Handle(); | |
8680 entry_name ^= cache.At(index); | |
8681 // An empty spot will be found because we keep the hash set at most 75% full. | |
8682 while (!entry_name.IsNull()) { | |
8683 index = (index + 1) % cache_size; | |
8684 entry_name ^= cache.At(index); | |
8685 } | |
8686 // Insert the object at the empty slot. | |
8687 cache.SetAt(index, name); | |
8688 ASSERT(cache.At(index + cache_size) == Object::null()); | |
8689 cache.SetAt(index + cache_size, obj); | |
8690 | |
8691 // One more element added. | |
8692 intptr_t num_used = Smi::Value(Smi::RawCast(cache.At(counter_index))) + 1; | |
8693 cache.SetAt(counter_index, Smi::Handle(Smi::New(num_used))); | |
8694 CompilerStats::num_names_cached++; | |
8695 | |
8696 // Rehash if symbol_table is 75% full. | |
8697 if (num_used > ((cache_size / 4) * 3)) { | |
8698 CompilerStats::num_names_cached -= num_used; | |
8699 GrowResolvedNamesCache(); | |
8700 } | |
8701 } | 8650 } |
8702 | 8651 |
8703 | 8652 |
8704 void Library::InvalidateResolvedName(const String& name) const { | 8653 void Library::InvalidateResolvedName(const String& name) const { |
8705 Object& entry = Object::Handle(); | 8654 Object& entry = Object::Handle(); |
8706 if (LookupResolvedNamesCache(name, &entry)) { | 8655 if (LookupResolvedNamesCache(name, &entry)) { |
| 8656 // TODO(koda): Support deleted sentinel in snapshots and remove only 'name'. |
8707 InvalidateResolvedNamesCache(); | 8657 InvalidateResolvedNamesCache(); |
8708 } | 8658 } |
8709 } | 8659 } |
8710 | 8660 |
8711 | 8661 |
8712 void Library::InvalidateResolvedNamesCache() const { | 8662 void Library::InvalidateResolvedNamesCache() const { |
8713 const intptr_t kInvalidatedCacheSize = 16; | 8663 const intptr_t kInvalidatedCacheSize = 16; |
8714 InitResolvedNamesCache(kInvalidatedCacheSize); | 8664 InitResolvedNamesCache(kInvalidatedCacheSize); |
8715 } | 8665 } |
8716 | 8666 |
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9213 | 9163 |
9214 static RawArray* NewDictionary(intptr_t initial_size) { | 9164 static RawArray* NewDictionary(intptr_t initial_size) { |
9215 const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); | 9165 const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); |
9216 // The last element of the dictionary specifies the number of in use slots. | 9166 // The last element of the dictionary specifies the number of in use slots. |
9217 dict.SetAt(initial_size, Smi::Handle(Smi::New(0))); | 9167 dict.SetAt(initial_size, Smi::Handle(Smi::New(0))); |
9218 return dict.raw(); | 9168 return dict.raw(); |
9219 } | 9169 } |
9220 | 9170 |
9221 | 9171 |
9222 void Library::InitResolvedNamesCache(intptr_t size) const { | 9172 void Library::InitResolvedNamesCache(intptr_t size) const { |
9223 // Need space for 'size' names and 'size' resolved object entries. | 9173 const Array& cache = Array::Handle(HashTables::New<ResolvedNamesMap>(size)); |
9224 StorePointer(&raw_ptr()->resolved_names_, NewDictionary(2 * size)); | 9174 StorePointer(&raw_ptr()->resolved_names_, cache.raw()); |
9225 } | 9175 } |
9226 | 9176 |
9227 | 9177 |
9228 void Library::InitClassDictionary() const { | 9178 void Library::InitClassDictionary() const { |
9229 // TODO(iposva): Find reasonable initial size. | 9179 // TODO(iposva): Find reasonable initial size. |
9230 const int kInitialElementCount = 16; | 9180 const int kInitialElementCount = 16; |
9231 StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount)); | 9181 StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount)); |
9232 } | 9182 } |
9233 | 9183 |
9234 | 9184 |
(...skipping 9807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19042 return tag_label.ToCString(); | 18992 return tag_label.ToCString(); |
19043 } | 18993 } |
19044 | 18994 |
19045 | 18995 |
19046 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 18996 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
19047 Instance::PrintJSONImpl(stream, ref); | 18997 Instance::PrintJSONImpl(stream, ref); |
19048 } | 18998 } |
19049 | 18999 |
19050 | 19000 |
19051 } // namespace dart | 19001 } // namespace dart |
OLD | NEW |