Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: runtime/vm/object.cc

Issue 11474056: Store canonical type argments in a hash table instead of linear list. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: addressed comments Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« runtime/vm/object.h ('K') | « runtime/vm/object.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/bigint_operations.h" 10 #include "vm/bigint_operations.h"
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 // declared in RawArray. 566 // declared in RawArray.
567 cls.set_type_arguments_field_offset(Array::type_arguments_offset()); 567 cls.set_type_arguments_field_offset(Array::type_arguments_offset());
568 568
569 // Set up the growable object array class (Has to be done after the array 569 // Set up the growable object array class (Has to be done after the array
570 // class is setup as one of its field is an array object). 570 // class is setup as one of its field is an array object).
571 cls = Class::New<GrowableObjectArray>(); 571 cls = Class::New<GrowableObjectArray>();
572 object_store->set_growable_object_array_class(cls); 572 object_store->set_growable_object_array_class(cls);
573 cls.set_type_arguments_field_offset( 573 cls.set_type_arguments_field_offset(
574 GrowableObjectArray::type_arguments_offset()); 574 GrowableObjectArray::type_arguments_offset());
575 575
576 // canonical_type_arguments_ are NULL terminated. 576 // canonical_type_arguments_ are Smi terminated.
577 array = Array::New(4); 577 // Last element contains the count of used slots.
578 const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
579 array = Array::New(kInitialCanonicalTypeArgumentsSize + 1);
580 array.SetAt(kInitialCanonicalTypeArgumentsSize, Smi::Handle(Smi::New(0)));
578 object_store->set_canonical_type_arguments(array); 581 object_store->set_canonical_type_arguments(array);
579 582
580 // Setup type class early in the process. 583 // Setup type class early in the process.
581 cls = Class::New<Type>(); 584 cls = Class::New<Type>();
582 object_store->set_type_class(cls); 585 object_store->set_type_class(cls);
583 586
584 cls = Class::New<TypeParameter>(); 587 cls = Class::New<TypeParameter>();
585 object_store->set_type_parameter_class(cls); 588 object_store->set_type_parameter_class(cls);
586 589
587 // Pre-allocate the OneByteString class needed by the symbol table. 590 // Pre-allocate the OneByteString class needed by the symbol table.
(...skipping 1905 matching lines...) Expand 10 before | Expand all | Expand 10 after
2493 } 2496 }
2494 2497
2495 2498
2496 bool AbstractTypeArguments::IsUninstantiatedIdentity() const { 2499 bool AbstractTypeArguments::IsUninstantiatedIdentity() const {
2497 // AbstractTypeArguments is an abstract class. 2500 // AbstractTypeArguments is an abstract class.
2498 UNREACHABLE(); 2501 UNREACHABLE();
2499 return false; 2502 return false;
2500 } 2503 }
2501 2504
2502 2505
2506 static uword FinalizeHash(uword hash) {
2507 hash += hash << 3;
2508 hash ^= hash >> 11;
2509 hash += hash << 15;
2510 return hash;
2511 }
2512
2513
2514 uword AbstractTypeArguments::Hash() const {
2515 if (IsNull()) return 0;
2516 uword result = 0;
2517 intptr_t num_types = Length();
2518 for (intptr_t i = 0; i < num_types; i++) {
2519 result += AbstractType::Handle(TypeAt(i)).Hash();
regis 2012/12/11 19:04:04 You should move the Handle out of the loop, not to
Florian Schneider 2012/12/12 14:58:40 Thanks. Done.
2520 result += result << 10;
2521 result ^= result >> 6;
2522 }
2523 return FinalizeHash(result);
2524 }
2525
2526
2503 RawString* AbstractTypeArguments::SubvectorName( 2527 RawString* AbstractTypeArguments::SubvectorName(
2504 intptr_t from_index, 2528 intptr_t from_index,
2505 intptr_t len, 2529 intptr_t len,
2506 NameVisibility name_visibility) const { 2530 NameVisibility name_visibility) const {
2507 ASSERT(from_index + len <= Length()); 2531 ASSERT(from_index + len <= Length());
2508 String& name = String::Handle(); 2532 String& name = String::Handle();
2509 const intptr_t num_strings = 2*len + 1; // "<""T"", ""T"">". 2533 const intptr_t num_strings = 2*len + 1; // "<""T"", ""T"">".
2510 const Array& strings = Array::Handle(Array::New(num_strings)); 2534 const Array& strings = Array::Handle(Array::New(num_strings));
2511 intptr_t s = 0; 2535 intptr_t s = 0;
2512 strings.SetAt(s++, String::Handle(Symbols::New("<"))); 2536 strings.SetAt(s++, String::Handle(Symbols::New("<")));
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
2702 } 2726 }
2703 2727
2704 2728
2705 const char* AbstractTypeArguments::ToCString() const { 2729 const char* AbstractTypeArguments::ToCString() const {
2706 // AbstractTypeArguments is an abstract class, valid only for representing 2730 // AbstractTypeArguments is an abstract class, valid only for representing
2707 // null. 2731 // null.
2708 if (IsNull()) { 2732 if (IsNull()) {
2709 return "NULL AbstractTypeArguments"; 2733 return "NULL AbstractTypeArguments";
2710 } 2734 }
2711 UNREACHABLE(); 2735 UNREACHABLE();
2712 return "AbstractTypeArguments"; 2736 return NULL;
2713 } 2737 }
2714 2738
2715 2739
2716 intptr_t TypeArguments::Length() const { 2740 intptr_t TypeArguments::Length() const {
2717 ASSERT(!IsNull()); 2741 ASSERT(!IsNull());
2718 return Smi::Value(raw_ptr()->length_); 2742 return Smi::Value(raw_ptr()->length_);
2719 } 2743 }
2720 2744
2721 2745
2722 RawAbstractType* TypeArguments::TypeAt(intptr_t index) const { 2746 RawAbstractType* TypeArguments::TypeAt(intptr_t index) const {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
2826 2850
2827 2851
2828 void TypeArguments::SetLength(intptr_t value) const { 2852 void TypeArguments::SetLength(intptr_t value) const {
2829 ASSERT(!IsCanonical()); 2853 ASSERT(!IsCanonical());
2830 // This is only safe because we create a new Smi, which does not cause 2854 // This is only safe because we create a new Smi, which does not cause
2831 // heap allocation. 2855 // heap allocation.
2832 raw_ptr()->length_ = Smi::New(value); 2856 raw_ptr()->length_ = Smi::New(value);
2833 } 2857 }
2834 2858
2835 2859
2860 static void GrowCanonicalTypeArguments(Isolate* isolate, const Array& table) {
2861 // Last element of the array is the number of used elements.
2862 intptr_t table_size = table.Length() - 1;
2863 intptr_t new_table_size = table_size * 2;
2864 ASSERT(Utils::IsPowerOfTwo(new_table_size));
2865 Array& new_table = Array::Handle(isolate, Array::New(new_table_size + 1));
2866 // Copy all elements from the original table to the newly allocated
2867 // array.
2868 TypeArguments& element = TypeArguments::Handle(isolate);
2869 Object& new_element = Object::Handle(isolate);
2870 for (intptr_t i = 0; i < table_size; i++) {
2871 element ^= table.At(i);
2872 if (!element.IsNull()) {
2873 intptr_t hash = element.Hash();
2874 intptr_t index = static_cast<uword>(hash) % new_table_size;
Ivan Posva 2012/12/11 14:54:52 Since you know you have a power of two. Please do
2875 new_element = new_table.At(index);
2876 while (!new_element.IsNull()) {
2877 index = (index + 1) % new_table_size; // Move to next element.
2878 new_element = new_table.At(index);
2879 }
2880 new_table.SetAt(index, element);
2881 }
2882 }
2883 // Copy used count.
2884 new_element = table.At(table_size);
2885 new_table.SetAt(new_table_size, new_element);
2886 // Remember the new table now.
2887 isolate->object_store()->set_canonical_type_arguments(new_table);
2888 }
2889
2890
2891 static void InsertIntoCanonicalTypeArguments(Isolate* isolate,
2892 const Array& table,
2893 const TypeArguments& arguments,
2894 intptr_t index) {
2895 // Last element of the array is the number of used elements.
2896 intptr_t table_size = table.Length() - 1;
2897 arguments.SetCanonical(); // Mark object as being canonical.
2898 table.SetAt(index, arguments); // Remember the new element.
2899 Smi& used = Smi::Handle(isolate);
2900 used ^= table.At(table_size);
2901 intptr_t used_elements = used.Value() + 1; // One more element added.
2902 used = Smi::New(used_elements);
2903 table.SetAt(table_size, used); // Update used count.
2904
2905 // Rehash if table is 75% full.
2906 if (used_elements > ((table_size / 4) * 3)) {
2907 GrowCanonicalTypeArguments(isolate, table);
2908 }
2909 }
2910
2911
2912 static intptr_t FindIndexInCanonicalTypeArguments(
2913 Isolate* isolate,
2914 const Array& table,
2915 const TypeArguments& arguments,
2916 intptr_t hash) {
2917 // Last element of the array is the number of used elements.
2918 intptr_t table_size = table.Length() - 1;
2919 intptr_t index = static_cast<uword>(hash) % table_size;
Ivan Posva 2012/12/11 14:54:52 ditto: power of two assertion, & mask, uword cast.
2920
2921 TypeArguments& current = TypeArguments::Handle(isolate);
2922 current ^= table.At(index);
2923 while (!current.IsNull() && !current.Equals(arguments)) {
2924 index = (index + 1) % table_size; // Move to next element.
2925 current ^= table.At(index);
2926 }
2927 return index; // Index of element if found or slot into which to add it.
2928 }
2929
2930
2836 RawAbstractTypeArguments* TypeArguments::Canonicalize() const { 2931 RawAbstractTypeArguments* TypeArguments::Canonicalize() const {
2837 if (IsNull() || IsCanonical()) { 2932 if (IsNull() || IsCanonical()) {
2838 ASSERT(IsOld()); 2933 ASSERT(IsOld());
2839 return this->raw(); 2934 return this->raw();
2840 } 2935 }
2841 ObjectStore* object_store = Isolate::Current()->object_store(); 2936 Isolate* isolate = Isolate::Current();
2842 // 'table' must be null terminated. 2937 ObjectStore* object_store = isolate->object_store();
2843 Array& table = Array::Handle(object_store->canonical_type_arguments()); 2938 const Array& table = Array::Handle(isolate,
2939 object_store->canonical_type_arguments());
2844 ASSERT(table.Length() > 0); 2940 ASSERT(table.Length() > 0);
2845 intptr_t index = 0; 2941 TypeArguments& self = TypeArguments::Handle(isolate, this->raw());
2846 TypeArguments& result = TypeArguments::Handle(); 2942 intptr_t index = FindIndexInCanonicalTypeArguments(isolate,
2943 table,
2944 self,
2945 Hash());
2946 TypeArguments& result = TypeArguments::Handle(isolate);
2847 result ^= table.At(index); 2947 result ^= table.At(index);
2848 while (!result.IsNull()) { 2948 if (result.IsNull()) {
2849 if (this->Equals(result)) { 2949 // Make sure we have an old space object and add it to the table.
2850 return result.raw(); 2950 result ^= this->raw();
2951 if (result.IsNew()) {
2952 result ^= Object::Clone(result, Heap::kOld);
2851 } 2953 }
2852 result ^= table.At(++index); 2954 ASSERT(result.IsOld());
2955 InsertIntoCanonicalTypeArguments(isolate, table, result, index);
2853 } 2956 }
2854 // Not found. Add 'this' to table. 2957 ASSERT(result.Equals(self));
2855 result ^= this->raw(); 2958 ASSERT(!result.IsNull());
2856 if (result.IsNew()) { 2959 ASSERT(result.IsTypeArguments());
2857 result ^= Object::Clone(result, Heap::kOld);
2858 }
2859 ASSERT(result.IsOld());
2860 if (index == table.Length() - 1) {
2861 table = Array::Grow(table, table.Length() + 4, Heap::kOld);
2862 object_store->set_canonical_type_arguments(table);
2863 }
2864 table.SetAt(index, result);
2865 result.SetCanonical();
2866 return result.raw(); 2960 return result.raw();
2867 } 2961 }
2868 2962
2869 2963
2870 const char* TypeArguments::ToCString() const { 2964 const char* TypeArguments::ToCString() const {
2871 if (IsNull()) { 2965 if (IsNull()) {
2872 return "NULL TypeArguments"; 2966 return "NULL TypeArguments";
2873 } 2967 }
2874 const char* format = "%s [%s]"; 2968 const char* format = "%s [%s]";
2875 const char* prev_cstr = "TypeArguments:"; 2969 const char* prev_cstr = "TypeArguments:";
(...skipping 5831 matching lines...) Expand 10 before | Expand all | Expand 10 after
8707 } 8801 }
8708 const Class& cls = Class::Handle(type_class()); 8802 const Class& cls = Class::Handle(type_class());
8709 return cls.TypeTest(test_kind, 8803 return cls.TypeTest(test_kind,
8710 AbstractTypeArguments::Handle(arguments()), 8804 AbstractTypeArguments::Handle(arguments()),
8711 Class::Handle(other.type_class()), 8805 Class::Handle(other.type_class()),
8712 AbstractTypeArguments::Handle(other.arguments()), 8806 AbstractTypeArguments::Handle(other.arguments()),
8713 malformed_error); 8807 malformed_error);
8714 } 8808 }
8715 8809
8716 8810
8811 uword AbstractType::Hash() const {
8812 // AbstractType is an abstract class.
8813 UNREACHABLE();
8814 return 0;
8815 }
8816
8817
8717 const char* AbstractType::ToCString() const { 8818 const char* AbstractType::ToCString() const {
8718 // AbstractType is an abstract class. 8819 // AbstractType is an abstract class.
8719 UNREACHABLE(); 8820 UNREACHABLE();
8720 return "AbstractType"; 8821 return "AbstractType";
8721 } 8822 }
8722 8823
8723 8824
8724 RawType* Type::NullType() { 8825 RawType* Type::NullType() {
8725 return Isolate::Current()->object_store()->null_type(); 8826 return Isolate::Current()->object_store()->null_type();
8726 } 8827 }
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
8981 new_canonical_types.SetAt(index, *this); 9082 new_canonical_types.SetAt(index, *this);
8982 } else { 9083 } else {
8983 canonical_types.SetAt(index, *this); 9084 canonical_types.SetAt(index, *this);
8984 } 9085 }
8985 ASSERT(IsOld()); 9086 ASSERT(IsOld());
8986 SetCanonical(); 9087 SetCanonical();
8987 return this->raw(); 9088 return this->raw();
8988 } 9089 }
8989 9090
8990 9091
9092 uword Type::Hash() const {
regis 2012/12/11 19:04:04 ASSERT(IsFinalized());
Florian Schneider 2012/12/12 14:58:40 Done.
9093 uword result = 1;
9094 result <<= IsMalformed() ? 10 : 0;
9095 result += Class::Handle(type_class()).id();
regis 2012/12/11 19:04:04 A malformed type may not have a type_class. You wi
Florian Schneider 2012/12/12 14:58:40 Done.
9096 result += AbstractTypeArguments::Handle(arguments()).Hash();
9097 return FinalizeHash(result);
9098 }
9099
9100
8991 void Type::set_type_class(const Object& value) const { 9101 void Type::set_type_class(const Object& value) const {
8992 ASSERT(!value.IsNull() && (value.IsClass() || value.IsUnresolvedClass())); 9102 ASSERT(!value.IsNull() && (value.IsClass() || value.IsUnresolvedClass()));
8993 StorePointer(&raw_ptr()->type_class_, value.raw()); 9103 StorePointer(&raw_ptr()->type_class_, value.raw());
8994 } 9104 }
8995 9105
8996 9106
8997 void Type::set_arguments(const AbstractTypeArguments& value) const { 9107 void Type::set_arguments(const AbstractTypeArguments& value) const {
8998 StorePointer(&raw_ptr()->arguments_, value.raw()); 9108 StorePointer(&raw_ptr()->arguments_, value.raw());
8999 } 9109 }
9000 9110
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
9122 RawAbstractType* TypeParameter::InstantiateFrom( 9232 RawAbstractType* TypeParameter::InstantiateFrom(
9123 const AbstractTypeArguments& instantiator_type_arguments) const { 9233 const AbstractTypeArguments& instantiator_type_arguments) const {
9124 ASSERT(IsFinalized()); 9234 ASSERT(IsFinalized());
9125 if (instantiator_type_arguments.IsNull()) { 9235 if (instantiator_type_arguments.IsNull()) {
9126 return Type::DynamicType(); 9236 return Type::DynamicType();
9127 } 9237 }
9128 return instantiator_type_arguments.TypeAt(index()); 9238 return instantiator_type_arguments.TypeAt(index());
9129 } 9239 }
9130 9240
9131 9241
9242 uword TypeParameter::Hash() const {
regis 2012/12/11 19:04:04 ASSERT(IsFinalized());
Florian Schneider 2012/12/12 14:58:40 Done.
9243 uword result = 0;
9244 result += Class::Handle(parameterized_class()).id();
9245 result <<= index();
9246 result ^= String::Handle(name()).Hash();
regis 2012/12/11 19:04:04 You do not need the name. It is only used for erro
Florian Schneider 2012/12/12 14:58:40 Ok, then I'd like to remove from TypeParameter::Eq
regis 2012/12/12 18:36:48 Yes, it is safe, because Equals returns false if o
Florian Schneider 2012/12/13 11:59:45 Done.
9247 result += IsFinalized() ? 1 : 0;
9248 return FinalizeHash(result);
9249 }
9250
9251
9132 RawTypeParameter* TypeParameter::New() { 9252 RawTypeParameter* TypeParameter::New() {
9133 ASSERT(Isolate::Current()->object_store()->type_parameter_class() != 9253 ASSERT(Isolate::Current()->object_store()->type_parameter_class() !=
9134 Class::null()); 9254 Class::null());
9135 RawObject* raw = Object::Allocate(TypeParameter::kClassId, 9255 RawObject* raw = Object::Allocate(TypeParameter::kClassId,
9136 TypeParameter::InstanceSize(), 9256 TypeParameter::InstanceSize(),
9137 Heap::kOld); 9257 Heap::kOld);
9138 return reinterpret_cast<RawTypeParameter*>(raw); 9258 return reinterpret_cast<RawTypeParameter*>(raw);
9139 } 9259 }
9140 9260
9141 9261
(...skipping 3157 matching lines...) Expand 10 before | Expand all | Expand 10 after
12299 } 12419 }
12300 return result.raw(); 12420 return result.raw();
12301 } 12421 }
12302 12422
12303 12423
12304 const char* WeakProperty::ToCString() const { 12424 const char* WeakProperty::ToCString() const {
12305 return "_WeakProperty"; 12425 return "_WeakProperty";
12306 } 12426 }
12307 12427
12308 } // namespace dart 12428 } // namespace dart
OLDNEW
« runtime/vm/object.h ('K') | « runtime/vm/object.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698