Chromium Code Reviews| 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/longjump.h" | 36 #include "vm/longjump.h" |
| 36 #include "vm/object_id_ring.h" | 37 #include "vm/object_id_ring.h" |
| 37 #include "vm/object_store.h" | 38 #include "vm/object_store.h" |
| 38 #include "vm/parser.h" | 39 #include "vm/parser.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 8444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8486 obj = LookupLocalObject(accessor_name); | 8487 obj = LookupLocalObject(accessor_name); |
| 8487 if (obj.IsNull()) { | 8488 if (obj.IsNull()) { |
| 8488 obj = LookupImportedObject(name); | 8489 obj = LookupImportedObject(name); |
| 8489 } | 8490 } |
| 8490 } | 8491 } |
| 8491 AddToResolvedNamesCache(name, obj); | 8492 AddToResolvedNamesCache(name, obj); |
| 8492 return obj.raw(); | 8493 return obj.raw(); |
| 8493 } | 8494 } |
| 8494 | 8495 |
| 8495 | 8496 |
| 8496 static intptr_t ResolvedNameCacheSize(const Array& cache) { | 8497 class StringEqualsTraits { |
| 8497 return (cache.Length() - 1) / 2; | 8498 public: |
| 8498 } | 8499 static bool IsMatch(const Object& a, const Object& b) { |
| 8500 return String::Cast(a).Equals(String::Cast(b)); | |
| 8501 } | |
| 8502 static uword Hash(const Object& obj) { | |
| 8503 return String::Cast(obj).Hash(); | |
| 8504 } | |
| 8505 }; | |
| 8506 typedef UnorderedHashMap<StringEqualsTraits> ResolvedNamesMap; | |
| 8499 | 8507 |
| 8500 | 8508 |
| 8501 // Returns true if the name is found in the cache, false no cache hit. | 8509 // Returns true if the name is found in the cache, false no cache hit. |
| 8502 // obj is set to the cached entry. It may be null, indicating that the | 8510 // obj is set to the cached entry. It may be null, indicating that the |
| 8503 // name does not resolve to anything in this library. | 8511 // name does not resolve to anything in this library. |
| 8504 bool Library::LookupResolvedNamesCache(const String& name, | 8512 bool Library::LookupResolvedNamesCache(const String& name, |
| 8505 Object* obj) const { | 8513 Object* obj) const { |
| 8506 const Array& cache = Array::Handle(resolved_names()); | 8514 ResolvedNamesMap cache(Array::Handle(resolved_names())); |
| 8507 const intptr_t cache_size = ResolvedNameCacheSize(cache); | 8515 bool present = false; |
| 8508 intptr_t index = name.Hash() % cache_size; | 8516 *obj = cache.GetOrNull(name, &present); |
| 8509 String& entry_name = String::Handle(); | 8517 ASSERT(cache.Release() == resolved_names()); |
|
siva
2014/06/13 19:51:19
Strange that you are calling Release which has a s
koda
2014/06/23 19:44:56
Done.
| |
| 8510 entry_name ^= cache.At(index); | 8518 return present; |
| 8511 while (!entry_name.IsNull()) { | |
| 8512 if (entry_name.Equals(name)) { | |
| 8513 CompilerStats::num_lib_cache_hit++; | |
| 8514 *obj = cache.At(index + cache_size); | |
| 8515 return true; | |
| 8516 } | |
| 8517 index = (index + 1) % cache_size; | |
| 8518 entry_name ^= cache.At(index); | |
| 8519 } | |
| 8520 *obj = Object::null(); | |
| 8521 return false; | |
| 8522 } | |
| 8523 | |
| 8524 | |
| 8525 void Library::GrowResolvedNamesCache() const { | |
| 8526 const Array& old_cache = Array::Handle(resolved_names()); | |
| 8527 const intptr_t old_cache_size = ResolvedNameCacheSize(old_cache); | |
| 8528 | |
| 8529 // Create empty new cache and add entries from the old cache. | |
| 8530 const intptr_t new_cache_size = old_cache_size * 3 / 2; | |
| 8531 InitResolvedNamesCache(new_cache_size); | |
| 8532 String& name = String::Handle(); | |
| 8533 Object& entry = Object::Handle(); | |
| 8534 for (intptr_t i = 0; i < old_cache_size; i++) { | |
| 8535 name ^= old_cache.At(i); | |
| 8536 if (!name.IsNull()) { | |
| 8537 entry = old_cache.At(i + old_cache_size); | |
| 8538 AddToResolvedNamesCache(name, entry); | |
| 8539 } | |
| 8540 } | |
| 8541 } | 8519 } |
| 8542 | 8520 |
| 8543 | 8521 |
| 8544 // Add a name to the resolved name cache. This name resolves to the | 8522 // Add a name to the resolved name cache. This name resolves to the |
| 8545 // given object in this library scope. obj may be null, which means | 8523 // given object in this library scope. obj may be null, which means |
| 8546 // the name does not resolve to anything in this library scope. | 8524 // the name does not resolve to anything in this library scope. |
| 8547 void Library::AddToResolvedNamesCache(const String& name, | 8525 void Library::AddToResolvedNamesCache(const String& name, |
| 8548 const Object& obj) const { | 8526 const Object& obj) const { |
| 8549 if (!FLAG_use_lib_cache) { | 8527 if (!FLAG_use_lib_cache) { |
| 8550 return; | 8528 return; |
| 8551 } | 8529 } |
| 8552 ASSERT(!Field::IsGetterName(name) && !Field::IsSetterName(name)); | 8530 ResolvedNamesMap cache(Array::Handle(resolved_names())); |
| 8553 const Array& cache = Array::Handle(resolved_names()); | 8531 cache.UpdateOrInsert(name, obj); |
| 8554 // let N = cache.Length(); | 8532 StorePointer(&raw_ptr()->resolved_names_, cache.Release()); |
| 8555 // The entry cache[N-1] is used as a counter | |
| 8556 // The array entries [0..N-2] are used as cache entries. | |
| 8557 // cache[i] contains the name of the entry | |
| 8558 // cache[i+(N-1)/2] contains the resolved entity, or NULL if that name | |
| 8559 // is not present in the library. | |
| 8560 const intptr_t counter_index = cache.Length() - 1; | |
| 8561 intptr_t cache_size = ResolvedNameCacheSize(cache); | |
| 8562 intptr_t index = name.Hash() % cache_size; | |
| 8563 String& entry_name = String::Handle(); | |
| 8564 entry_name ^= cache.At(index); | |
| 8565 // An empty spot will be found because we keep the hash set at most 75% full. | |
| 8566 while (!entry_name.IsNull()) { | |
| 8567 index = (index + 1) % cache_size; | |
| 8568 entry_name ^= cache.At(index); | |
| 8569 } | |
| 8570 // Insert the object at the empty slot. | |
| 8571 cache.SetAt(index, name); | |
| 8572 ASSERT(cache.At(index + cache_size) == Object::null()); | |
| 8573 cache.SetAt(index + cache_size, obj); | |
| 8574 | |
| 8575 // One more element added. | |
| 8576 intptr_t num_used = Smi::Value(Smi::RawCast(cache.At(counter_index))) + 1; | |
| 8577 cache.SetAt(counter_index, Smi::Handle(Smi::New(num_used))); | |
| 8578 CompilerStats::num_names_cached++; | |
| 8579 | |
| 8580 // Rehash if symbol_table is 75% full. | |
| 8581 if (num_used > ((cache_size / 4) * 3)) { | |
| 8582 CompilerStats::num_names_cached -= num_used; | |
| 8583 GrowResolvedNamesCache(); | |
| 8584 } | |
| 8585 } | 8533 } |
| 8586 | 8534 |
| 8587 | 8535 |
| 8588 void Library::InvalidateResolvedName(const String& name) const { | 8536 void Library::InvalidateResolvedName(const String& name) const { |
| 8589 Object& entry = Object::Handle(); | 8537 Object& entry = Object::Handle(); |
| 8590 if (LookupResolvedNamesCache(name, &entry)) { | 8538 if (LookupResolvedNamesCache(name, &entry)) { |
| 8539 // TODO(koda): Support deleted sentinel in snapshots and remove only 'name'. | |
| 8591 InvalidateResolvedNamesCache(); | 8540 InvalidateResolvedNamesCache(); |
| 8592 } | 8541 } |
| 8593 } | 8542 } |
| 8594 | 8543 |
| 8595 | 8544 |
| 8596 void Library::InvalidateResolvedNamesCache() const { | 8545 void Library::InvalidateResolvedNamesCache() const { |
| 8597 const intptr_t kInvalidatedCacheSize = 16; | 8546 const intptr_t kInvalidatedCacheSize = 16; |
| 8598 InitResolvedNamesCache(kInvalidatedCacheSize); | 8547 InitResolvedNamesCache(kInvalidatedCacheSize); |
| 8599 } | 8548 } |
| 8600 | 8549 |
| (...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9097 | 9046 |
| 9098 static RawArray* NewDictionary(intptr_t initial_size) { | 9047 static RawArray* NewDictionary(intptr_t initial_size) { |
| 9099 const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); | 9048 const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld)); |
| 9100 // The last element of the dictionary specifies the number of in use slots. | 9049 // The last element of the dictionary specifies the number of in use slots. |
| 9101 dict.SetAt(initial_size, Smi::Handle(Smi::New(0))); | 9050 dict.SetAt(initial_size, Smi::Handle(Smi::New(0))); |
| 9102 return dict.raw(); | 9051 return dict.raw(); |
| 9103 } | 9052 } |
| 9104 | 9053 |
| 9105 | 9054 |
| 9106 void Library::InitResolvedNamesCache(intptr_t size) const { | 9055 void Library::InitResolvedNamesCache(intptr_t size) const { |
| 9107 // Need space for 'size' names and 'size' resolved object entries. | 9056 Array& cache = Array::Handle(HashTables::New<ResolvedNamesMap>(size)); |
|
siva
2014/06/13 19:51:19
const Array& cache = ...;
koda
2014/06/23 19:44:56
Done.
| |
| 9108 StorePointer(&raw_ptr()->resolved_names_, NewDictionary(2 * size)); | 9057 StorePointer(&raw_ptr()->resolved_names_, cache.raw()); |
| 9109 } | 9058 } |
| 9110 | 9059 |
| 9111 | 9060 |
| 9112 void Library::InitClassDictionary() const { | 9061 void Library::InitClassDictionary() const { |
| 9113 // TODO(iposva): Find reasonable initial size. | 9062 // TODO(iposva): Find reasonable initial size. |
| 9114 const int kInitialElementCount = 16; | 9063 const int kInitialElementCount = 16; |
| 9115 StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount)); | 9064 StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount)); |
| 9116 } | 9065 } |
| 9117 | 9066 |
| 9118 | 9067 |
| (...skipping 9864 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 18983 return tag_label.ToCString(); | 18932 return tag_label.ToCString(); |
| 18984 } | 18933 } |
| 18985 | 18934 |
| 18986 | 18935 |
| 18987 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 18936 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 18988 Instance::PrintJSONImpl(stream, ref); | 18937 Instance::PrintJSONImpl(stream, ref); |
| 18989 } | 18938 } |
| 18990 | 18939 |
| 18991 | 18940 |
| 18992 } // namespace dart | 18941 } // namespace dart |
| OLD | NEW |