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/bigint_operations.h" | 10 #include "vm/bigint_operations.h" |
| (...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |