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

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: 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 NULL terminated.
Ivan Posva 2012/12/10 20:07:52 Comment out of date.
srdjan 2012/12/10 21:19:37 Fix comment: Smi terminated.
Florian Schneider 2012/12/11 12:23:04 Done.
Florian Schneider 2012/12/11 12:23:04 Done.
Florian Schneider 2012/12/11 12:23:04 Done.
577 array = Array::New(4); 577 const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
srdjan 2012/12/10 21:19:37 Seems too small as initial size.
Florian Schneider 2012/12/11 12:23:04 I don't want to wast space for programs that don't
578 array = Array::New(kInitialCanonicalTypeArgumentsSize + 1);
579 // Last element contains the count of used slots.
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 2114 matching lines...) Expand 10 before | Expand all | Expand 10 after
2702 } 2705 }
2703 2706
2704 2707
2705 const char* AbstractTypeArguments::ToCString() const { 2708 const char* AbstractTypeArguments::ToCString() const {
2706 // AbstractTypeArguments is an abstract class, valid only for representing 2709 // AbstractTypeArguments is an abstract class, valid only for representing
2707 // null. 2710 // null.
2708 if (IsNull()) { 2711 if (IsNull()) {
2709 return "NULL AbstractTypeArguments"; 2712 return "NULL AbstractTypeArguments";
2710 } 2713 }
2711 UNREACHABLE(); 2714 UNREACHABLE();
2712 return "AbstractTypeArguments"; 2715 return NULL;
Ivan Posva 2012/12/10 20:07:52 This seems very unconnected to the change at hand?
Florian Schneider 2012/12/11 12:23:04 I think it still makes sense, but I can put it int
2713 } 2716 }
2714 2717
2715 2718
2716 intptr_t TypeArguments::Length() const { 2719 intptr_t TypeArguments::Length() const {
2717 ASSERT(!IsNull()); 2720 ASSERT(!IsNull());
2718 return Smi::Value(raw_ptr()->length_); 2721 return Smi::Value(raw_ptr()->length_);
2719 } 2722 }
2720 2723
2721 2724
2722 RawAbstractType* TypeArguments::TypeAt(intptr_t index) const { 2725 RawAbstractType* TypeArguments::TypeAt(intptr_t index) const {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
2826 2829
2827 2830
2828 void TypeArguments::SetLength(intptr_t value) const { 2831 void TypeArguments::SetLength(intptr_t value) const {
2829 ASSERT(!IsCanonical()); 2832 ASSERT(!IsCanonical());
2830 // This is only safe because we create a new Smi, which does not cause 2833 // This is only safe because we create a new Smi, which does not cause
2831 // heap allocation. 2834 // heap allocation.
2832 raw_ptr()->length_ = Smi::New(value); 2835 raw_ptr()->length_ = Smi::New(value);
2833 } 2836 }
2834 2837
2835 2838
2839 static void GrowCanonicalTypeArguments(const Array& table, Isolate* isolate) {
2840 // Last element of the array is the number of used elements.
srdjan 2012/12/10 21:19:37 Pass isolate as first argument (as done in other p
Florian Schneider 2012/12/11 12:23:04 Done.
2841 intptr_t table_size = table.Length() - 1;
2842 intptr_t new_table_size = table_size * 2;
srdjan 2012/12/10 21:19:37 Can you check on dart2js, checked mode, how much t
Florian Schneider 2012/12/11 12:23:04 The max table size in dart2js is 1024 with ~50% oc
2843 Array& new_table = Array::Handle(isolate, Array::New(new_table_size + 1));
2844 // Copy all elements from the original table to the newly allocated
2845 // array.
2846 TypeArguments& element = TypeArguments::Handle(isolate);
2847 dart::Object& new_element = Object::Handle(isolate);
2848 for (intptr_t i = 0; i < table_size; i++) {
2849 element ^= table.At(i);
2850 if (!element.IsNull()) {
2851 intptr_t hash = element.Hash();
2852 intptr_t index = hash % new_table_size;
srdjan 2012/12/10 21:19:37 new_table_size should be power of 2 for performanc
Florian Schneider 2012/12/11 12:23:04 Done.
2853 new_element = new_table.At(index);
2854 while (!new_element.IsNull()) {
2855 index = (index + 1) % new_table_size; // Move to next element.
2856 new_element = new_table.At(index);
2857 }
2858 new_table.SetAt(index, element);
2859 }
2860 }
2861 // Copy used count.
2862 new_element = table.At(table_size);
2863 new_table.SetAt(new_table_size, new_element);
2864 // Remember the new table now.
2865 isolate->object_store()->set_canonical_type_arguments(new_table);
2866 }
2867
2868
2869 static void InsertIntoCanonicalTypeArguments(const Array& table,
2870 const TypeArguments& arguments,
2871 intptr_t index,
2872 Isolate* isolate) {
srdjan 2012/12/10 21:19:37 'isolate' as first argument.
Florian Schneider 2012/12/11 12:23:04 Done.
2873 // Last element of the array is the number of used elements.
2874 intptr_t table_size = table.Length() - 1;
2875 arguments.SetCanonical(); // Mark object as being canonical.
2876 table.SetAt(index, arguments); // Remember the new element.
2877 dart::Smi& used = Smi::Handle(isolate);
srdjan 2012/12/10 21:19:37 s/dart::Smi/Smi/ I do not think there is a conflic
Florian Schneider 2012/12/11 12:23:04 Done.
2878 used ^= table.At(table_size);
2879 intptr_t used_elements = used.Value() + 1; // One more element added.
2880 used = Smi::New(used_elements);
2881 table.SetAt(table_size, used); // Update used count.
2882
2883 // Rehash if table is 75% full.
2884 if (used_elements > ((table_size / 4) * 3)) {
2885 GrowCanonicalTypeArguments(table, isolate);
2886 }
2887 }
2888
2889
2890 intptr_t FindIndexInCanonicalTypeArguments(const Array& table,
2891 const TypeArguments& arguments,
2892 intptr_t hash,
2893 Isolate* isolate) {
srdjan 2012/12/10 21:19:37 ditto
Florian Schneider 2012/12/11 12:23:04 Done.
2894 // Last element of the array is the number of used elements.
2895 intptr_t table_size = table.Length() - 1;
2896 intptr_t index = hash % table_size;
2897
2898 TypeArguments& current = TypeArguments::Handle(isolate);
2899 current ^= table.At(index);
2900 while (!current.IsNull() && !current.Equals(arguments)) {
2901 index = (index + 1) % table_size; // Move to next element.
2902 current ^= table.At(index);
2903 }
2904 return index; // Index of element if found or slot into which to add it.
2905 }
2906
2907
2836 RawAbstractTypeArguments* TypeArguments::Canonicalize() const { 2908 RawAbstractTypeArguments* TypeArguments::Canonicalize() const {
2837 if (IsNull() || IsCanonical()) { 2909 if (IsNull() || IsCanonical()) {
2838 ASSERT(IsOld()); 2910 ASSERT(IsOld());
2839 return this->raw(); 2911 return this->raw();
2840 } 2912 }
2841 ObjectStore* object_store = Isolate::Current()->object_store(); 2913 Isolate* isolate = Isolate::Current();
2842 // 'table' must be null terminated. 2914 ObjectStore* object_store = isolate->object_store();
2843 Array& table = Array::Handle(object_store->canonical_type_arguments()); 2915 const Array& table = Array::Handle(isolate,
2916 object_store->canonical_type_arguments());
2844 ASSERT(table.Length() > 0); 2917 ASSERT(table.Length() > 0);
2845 intptr_t index = 0; 2918 TypeArguments& self = TypeArguments::Handle(isolate, this->raw());
2846 TypeArguments& result = TypeArguments::Handle(); 2919 intptr_t index = FindIndexInCanonicalTypeArguments(table,
2920 self,
2921 Hash(),
2922 isolate);
2923 TypeArguments& result = TypeArguments::Handle(isolate);
2847 result ^= table.At(index); 2924 result ^= table.At(index);
2848 while (!result.IsNull()) { 2925 if (result.IsNull()) {
2849 if (this->Equals(result)) { 2926 // Make sure we have an old space object and add it to the table.
2850 return result.raw(); 2927 result ^= this->raw();
2928 if (result.IsNew()) {
2929 result ^= Object::Clone(result, Heap::kOld);
2851 } 2930 }
2852 result ^= table.At(++index); 2931 ASSERT(result.IsOld());
2932 InsertIntoCanonicalTypeArguments(table, result, index, isolate);
2853 } 2933 }
2854 // Not found. Add 'this' to table. 2934 ASSERT(result.Equals(self));
2855 result ^= this->raw(); 2935 ASSERT(!result.IsNull());
2856 if (result.IsNew()) { 2936 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(); 2937 return result.raw();
2867 } 2938 }
2868 2939
2869 2940
2870 const char* TypeArguments::ToCString() const { 2941 const char* TypeArguments::ToCString() const {
2871 if (IsNull()) { 2942 if (IsNull()) {
2872 return "NULL TypeArguments"; 2943 return "NULL TypeArguments";
2873 } 2944 }
2874 const char* format = "%s [%s]"; 2945 const char* format = "%s [%s]";
2875 const char* prev_cstr = "TypeArguments:"; 2946 const char* prev_cstr = "TypeArguments:";
(...skipping 7117 matching lines...) Expand 10 before | Expand all | Expand 10 after
9993 static intptr_t HashImpl(const T* characters, intptr_t len) { 10064 static intptr_t HashImpl(const T* characters, intptr_t len) {
9994 ASSERT(len >= 0); 10065 ASSERT(len >= 0);
9995 StringHasher hasher; 10066 StringHasher hasher;
9996 for (intptr_t i = 0; i < len; i++) { 10067 for (intptr_t i = 0; i < len; i++) {
9997 hasher.Add(characters[i]); 10068 hasher.Add(characters[i]);
9998 } 10069 }
9999 return hasher.Finalize(String::kHashBits); 10070 return hasher.Finalize(String::kHashBits);
10000 } 10071 }
10001 10072
10002 10073
10074 intptr_t TypeArguments::Hash() const {
10075 const char* characters = ToCString();
Ivan Posva 2012/12/10 20:07:52 This seems very fragile to me and as you are not c
regis 2012/12/11 01:37:15 Yes, for efficiency, the hash of a TypeArguments v
Florian Schneider 2012/12/11 12:23:04 Done. Added ::Hash() for Type, TypeParameter and A
10076 return HashImpl(characters, strlen(characters));
10077 }
10078
10079
10003 intptr_t String::Hash(const uint8_t* characters, intptr_t len) { 10080 intptr_t String::Hash(const uint8_t* characters, intptr_t len) {
10004 return HashImpl(characters, len); 10081 return HashImpl(characters, len);
10005 } 10082 }
10006 10083
10007 10084
10008 intptr_t String::Hash(const uint16_t* characters, intptr_t len) { 10085 intptr_t String::Hash(const uint16_t* characters, intptr_t len) {
10009 StringHasher hasher; 10086 StringHasher hasher;
10010 intptr_t i = 0; 10087 intptr_t i = 0;
10011 while (i < len) { 10088 while (i < len) {
10012 hasher.Add(Utf16::Next(characters, &i, len)); 10089 hasher.Add(Utf16::Next(characters, &i, len));
(...skipping 2286 matching lines...) Expand 10 before | Expand all | Expand 10 after
12299 } 12376 }
12300 return result.raw(); 12377 return result.raw();
12301 } 12378 }
12302 12379
12303 12380
12304 const char* WeakProperty::ToCString() const { 12381 const char* WeakProperty::ToCString() const {
12305 return "_WeakProperty"; 12382 return "_WeakProperty";
12306 } 12383 }
12307 12384
12308 } // namespace dart 12385 } // 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