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

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

Issue 58923002: - Avoid deep recursions when executing type tests. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 1 month 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
« no previous file with comments | « 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/cpu.h" 10 #include "vm/cpu.h"
(...skipping 2719 matching lines...) Expand 10 before | Expand all | Expand 10 after
2730 return (!function.IsNull() && (function.signature_class() == raw())); 2730 return (!function.IsNull() && (function.signature_class() == raw()));
2731 } 2731 }
2732 2732
2733 2733
2734 // If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T. 2734 // If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T.
2735 // If test_kind == kIsMoreSpecificThan, checks if S is more specific than T. 2735 // If test_kind == kIsMoreSpecificThan, checks if S is more specific than T.
2736 // Type S is specified by this class parameterized with 'type_arguments', and 2736 // Type S is specified by this class parameterized with 'type_arguments', and
2737 // type T by class 'other' parameterized with 'other_type_arguments'. 2737 // type T by class 'other' parameterized with 'other_type_arguments'.
2738 // This class and class 'other' do not need to be finalized, however, they must 2738 // This class and class 'other' do not need to be finalized, however, they must
2739 // be resolved as well as their interfaces. 2739 // be resolved as well as their interfaces.
2740 bool Class::TypeTestNonRecursive(
regis 2013/11/05 18:17:40 Why do you need a new function that is forwarded t
2741 const Class& cls,
2742 Class::TypeTestKind test_kind,
2743 const AbstractTypeArguments& type_arguments,
2744 const Class& other,
2745 const AbstractTypeArguments& other_type_arguments,
2746 Error* bound_error) {
2747 // Use the thsi object as if it was the receiver of this method, but instead
2748 // of recursing reset it to the super class and loop.
2749 Class& thsi = Class::Handle(cls.raw());
2750 while (true) {
2751 ASSERT(!thsi.IsVoidClass());
Ivan Posva 2013/11/05 04:48:29 The contents of this loop is what was being done a
2752 // Check for DynamicType.
2753 // Each occurrence of DynamicType in type T is interpreted as the dynamic
2754 // type, a supertype of all types.
2755 if (other.IsDynamicClass()) {
2756 return true;
2757 }
2758 // In the case of a subtype test, each occurrence of DynamicType in type S
2759 // is interpreted as the bottom type, a subtype of all types.
2760 // However, DynamicType is not more specific than any type.
2761 if (thsi.IsDynamicClass()) {
2762 return test_kind == Class::kIsSubtypeOf;
2763 }
2764 // Check for NullType, which is only a subtype of ObjectType, of
2765 // DynamicType, or of itself, and which is more specific than any type.
2766 if (thsi.IsNullClass()) {
2767 // We already checked for other.IsDynamicClass() above.
2768 return (test_kind == Class::kIsMoreSpecificThan) ||
2769 other.IsObjectClass() || other.IsNullClass();
2770 }
2771 // Check for ObjectType. Any type that is not NullType or DynamicType
2772 // (already checked above), is more specific than ObjectType.
2773 if (other.IsObjectClass()) {
2774 return true;
2775 }
2776 // Check for reflexivity.
2777 if (thsi.raw() == other.raw()) {
2778 const intptr_t len = thsi.NumTypeArguments();
2779 if (len == 0) {
2780 return true;
2781 }
2782 // Since we do not truncate the type argument vector of a subclass (see
2783 // below), we only check a prefix of the proper length.
2784 // Check for covariance.
2785 if (other_type_arguments.IsNull() || other_type_arguments.IsRaw(len)) {
2786 return true;
2787 }
2788 if (type_arguments.IsNull() || type_arguments.IsRaw(len)) {
2789 // Other type can't be more specific than this one because for that
2790 // it would have to have all dynamic type arguments which is checked
2791 // above.
2792 return test_kind == Class::kIsSubtypeOf;
2793 }
2794 return type_arguments.TypeTest(test_kind,
2795 other_type_arguments,
2796 len,
2797 bound_error);
2798 }
2799 const bool other_is_function_class = other.IsFunctionClass();
2800 if (other.IsSignatureClass() || other_is_function_class) {
2801 const Function& other_fun = Function::Handle(other.signature_function());
2802 if (thsi.IsSignatureClass()) {
2803 if (other_is_function_class) {
2804 return true;
2805 }
2806 // Check for two function types.
2807 const Function& fun = Function::Handle(thsi.signature_function());
2808 return fun.TypeTest(test_kind,
2809 type_arguments,
2810 other_fun,
2811 other_type_arguments,
2812 bound_error);
2813 }
2814 // Check if type S has a call() method of function type T.
2815 Function& function =
2816 Function::Handle(thsi.LookupDynamicFunction(Symbols::Call()));
2817 if (function.IsNull()) {
2818 // Walk up the super_class chain.
2819 Class& cls = Class::Handle(thsi.SuperClass());
2820 while (!cls.IsNull() && function.IsNull()) {
2821 function = cls.LookupDynamicFunction(Symbols::Call());
2822 cls = cls.SuperClass();
2823 }
2824 }
2825 if (!function.IsNull()) {
2826 if (other_is_function_class ||
2827 function.TypeTest(test_kind,
2828 type_arguments,
2829 other_fun,
2830 other_type_arguments,
2831 bound_error)) {
2832 return true;
2833 }
2834 }
2835 }
2836 // Check for 'direct super type' specified in the implements clause
2837 // and check for transitivity at the same time.
2838 Array& interfaces = Array::Handle(thsi.interfaces());
2839 AbstractType& interface = AbstractType::Handle();
2840 Class& interface_class = Class::Handle();
2841 AbstractTypeArguments& interface_args = AbstractTypeArguments::Handle();
2842 Error& error = Error::Handle();
2843 for (intptr_t i = 0; i < interfaces.Length(); i++) {
2844 interface ^= interfaces.At(i);
2845 if (!interface.IsFinalized()) {
2846 // We may be checking bounds at finalization time. Skipping this
2847 // unfinalized interface will postpone bound checking to run time.
2848 continue;
2849 }
2850 error = Error::null();
2851 if (interface.IsMalboundedWithError(&error)) {
2852 // Return the first bound error to the caller if it requests it.
2853 if ((bound_error != NULL) && bound_error->IsNull()) {
2854 ASSERT(!error.IsNull());
2855 *bound_error = error.raw();
2856 }
2857 continue; // Another interface may work better.
2858 }
2859 interface_class = interface.type_class();
2860 interface_args = interface.arguments();
2861 if (!interface_args.IsNull() && !interface_args.IsInstantiated()) {
2862 // This type class implements an interface that is parameterized with
2863 // generic type(s), e.g. it implements List<T>.
2864 // The uninstantiated type T must be instantiated using the type
2865 // parameters of this type before performing the type test.
2866 // The type arguments of this type that are referred to by the type
2867 // parameters of the interface are at the end of the type vector,
2868 // after the type arguments of the super type of this type.
2869 // The index of the type parameters is adjusted upon finalization.
2870 error = Error::null();
2871 interface_args = interface_args.InstantiateFrom(type_arguments, &error);
2872 if (!error.IsNull()) {
2873 // Return the first bound error to the caller if it requests it.
2874 if ((bound_error != NULL) && bound_error->IsNull()) {
2875 *bound_error = error.raw();
2876 }
2877 continue; // Another interface may work better.
2878 }
2879 }
2880 if (interface_class.TypeTest(test_kind,
2881 interface_args,
2882 other,
2883 other_type_arguments,
2884 bound_error)) {
2885 return true;
2886 }
2887 }
2888 // "Recurse" up the class hierarchy until we have reached the top.
2889 thsi = thsi.SuperClass();
2890 if (thsi.IsNull()) {
2891 return false;
2892 }
2893 }
2894 UNREACHABLE();
2895 return false;
2896 }
2897
2898
2899 // If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T.
2900 // If test_kind == kIsMoreSpecificThan, checks if S is more specific than T.
2901 // Type S is specified by this class parameterized with 'type_arguments', and
2902 // type T by class 'other' parameterized with 'other_type_arguments'.
2903 // This class and class 'other' do not need to be finalized, however, they must
2904 // be resolved as well as their interfaces.
2740 bool Class::TypeTest( 2905 bool Class::TypeTest(
2741 TypeTestKind test_kind, 2906 TypeTestKind test_kind,
2742 const AbstractTypeArguments& type_arguments, 2907 const AbstractTypeArguments& type_arguments,
2743 const Class& other, 2908 const Class& other,
2744 const AbstractTypeArguments& other_type_arguments, 2909 const AbstractTypeArguments& other_type_arguments,
2745 Error* bound_error) const { 2910 Error* bound_error) const {
2746 ASSERT(!IsVoidClass()); 2911 return TypeTestNonRecursive(*this,
2747 // Check for DynamicType. 2912 test_kind,
2748 // Each occurrence of DynamicType in type T is interpreted as the dynamic
2749 // type, a supertype of all types.
2750 if (other.IsDynamicClass()) {
2751 return true;
2752 }
2753 // In the case of a subtype test, each occurrence of DynamicType in type S is
2754 // interpreted as the bottom type, a subtype of all types.
2755 // However, DynamicType is not more specific than any type.
2756 if (IsDynamicClass()) {
2757 return test_kind == kIsSubtypeOf;
2758 }
2759 // Check for NullType, which is only a subtype of ObjectType, of DynamicType,
2760 // or of itself, and which is more specific than any type.
2761 if (IsNullClass()) {
2762 // We already checked for other.IsDynamicClass() above.
2763 return (test_kind == kIsMoreSpecificThan) ||
2764 other.IsObjectClass() || other.IsNullClass();
2765 }
2766 // Check for ObjectType. Any type that is not NullType or DynamicType (already
2767 // checked above), is more specific than ObjectType.
2768 if (other.IsObjectClass()) {
2769 return true;
2770 }
2771 // Check for reflexivity.
2772 if (raw() == other.raw()) {
2773 const intptr_t len = NumTypeArguments();
2774 if (len == 0) {
2775 return true;
2776 }
2777 // Since we do not truncate the type argument vector of a subclass (see
2778 // below), we only check a prefix of the proper length.
2779 // Check for covariance.
2780 if (other_type_arguments.IsNull() || other_type_arguments.IsRaw(len)) {
2781 return true;
2782 }
2783 if (type_arguments.IsNull() || type_arguments.IsRaw(len)) {
2784 // Other type can't be more specific than this one because for that
2785 // it would have to have all dynamic type arguments which is checked
2786 // above.
2787 return test_kind == kIsSubtypeOf;
2788 }
2789 return type_arguments.TypeTest(test_kind,
2790 other_type_arguments,
2791 len,
2792 bound_error);
2793 }
2794 const bool other_is_function_class = other.IsFunctionClass();
2795 if (other.IsSignatureClass() || other_is_function_class) {
2796 const Function& other_fun = Function::Handle(other.signature_function());
2797 if (IsSignatureClass()) {
2798 if (other_is_function_class) {
2799 return true;
2800 }
2801 // Check for two function types.
2802 const Function& fun = Function::Handle(signature_function());
2803 return fun.TypeTest(test_kind,
2804 type_arguments,
2805 other_fun,
2806 other_type_arguments,
2807 bound_error);
2808 }
2809 // Check if type S has a call() method of function type T.
2810 Function& function =
2811 Function::Handle(LookupDynamicFunction(Symbols::Call()));
2812 if (function.IsNull()) {
2813 // Walk up the super_class chain.
2814 Class& cls = Class::Handle(SuperClass());
2815 while (!cls.IsNull() && function.IsNull()) {
2816 function = cls.LookupDynamicFunction(Symbols::Call());
2817 cls = cls.SuperClass();
2818 }
2819 }
2820 if (!function.IsNull()) {
2821 if (other_is_function_class ||
2822 function.TypeTest(test_kind,
2823 type_arguments,
2824 other_fun,
2825 other_type_arguments,
2826 bound_error)) {
2827 return true;
2828 }
2829 }
2830 }
2831 // Check for 'direct super type' specified in the implements clause
2832 // and check for transitivity at the same time.
2833 Array& interfaces = Array::Handle(this->interfaces());
2834 AbstractType& interface = AbstractType::Handle();
2835 Class& interface_class = Class::Handle();
2836 AbstractTypeArguments& interface_args = AbstractTypeArguments::Handle();
2837 Error& error = Error::Handle();
2838 for (intptr_t i = 0; i < interfaces.Length(); i++) {
2839 interface ^= interfaces.At(i);
2840 if (!interface.IsFinalized()) {
2841 // We may be checking bounds at finalization time. Skipping this
2842 // unfinalized interface will postpone bound checking to run time.
2843 continue;
2844 }
2845 error = Error::null();
2846 if (interface.IsMalboundedWithError(&error)) {
2847 // Return the first bound error to the caller if it requests it.
2848 if ((bound_error != NULL) && bound_error->IsNull()) {
2849 ASSERT(!error.IsNull());
2850 *bound_error = error.raw();
2851 }
2852 continue; // Another interface may work better.
2853 }
2854 interface_class = interface.type_class();
2855 interface_args = interface.arguments();
2856 if (!interface_args.IsNull() && !interface_args.IsInstantiated()) {
2857 // This type class implements an interface that is parameterized with
2858 // generic type(s), e.g. it implements List<T>.
2859 // The uninstantiated type T must be instantiated using the type
2860 // parameters of this type before performing the type test.
2861 // The type arguments of this type that are referred to by the type
2862 // parameters of the interface are at the end of the type vector,
2863 // after the type arguments of the super type of this type.
2864 // The index of the type parameters is adjusted upon finalization.
2865 error = Error::null();
2866 interface_args = interface_args.InstantiateFrom(type_arguments, &error);
2867 if (!error.IsNull()) {
2868 // Return the first bound error to the caller if it requests it.
2869 if ((bound_error != NULL) && bound_error->IsNull()) {
2870 *bound_error = error.raw();
2871 }
2872 continue; // Another interface may work better.
2873 }
2874 }
2875 if (interface_class.TypeTest(test_kind,
2876 interface_args,
2877 other,
2878 other_type_arguments,
2879 bound_error)) {
2880 return true;
2881 }
2882 }
2883 const Class& super_class = Class::Handle(SuperClass());
2884 if (super_class.IsNull()) {
2885 return false;
2886 }
2887 // Instead of truncating the type argument vector to the length of the super
2888 // type argument vector, we make sure that the code works with a vector that
2889 // is longer than necessary.
2890 return super_class.TypeTest(test_kind,
2891 type_arguments, 2913 type_arguments,
2892 other, 2914 other,
2893 other_type_arguments, 2915 other_type_arguments,
2894 bound_error); 2916 bound_error);
2895 } 2917 }
2896 2918
2897 2919
2898 bool Class::IsTopLevel() const { 2920 bool Class::IsTopLevel() const {
2899 return Name() == Symbols::TopLevel().raw(); 2921 return Name() == Symbols::TopLevel().raw();
2900 } 2922 }
(...skipping 12816 matching lines...) Expand 10 before | Expand all | Expand 10 after
15717 return "_MirrorReference"; 15739 return "_MirrorReference";
15718 } 15740 }
15719 15741
15720 15742
15721 void MirrorReference::PrintToJSONStream(JSONStream* stream, bool ref) const { 15743 void MirrorReference::PrintToJSONStream(JSONStream* stream, bool ref) const {
15722 JSONObject jsobj(stream); 15744 JSONObject jsobj(stream);
15723 } 15745 }
15724 15746
15725 15747
15726 } // namespace dart 15748 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/object.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698