OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This clang plugin checks various invariants of the Blink garbage | 5 // This clang plugin checks various invariants of the Blink garbage |
6 // collection infrastructure. | 6 // collection infrastructure. |
7 // | 7 // |
8 // Errors are described at: | 8 // Errors are described at: |
9 // http://www.chromium.org/developers/blink-gc-plugin-errors | 9 // http://www.chromium.org/developers/blink-gc-plugin-errors |
10 | 10 |
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
944 it != info->GetBases().end(); | 944 it != info->GetBases().end(); |
945 ++it) { | 945 ++it) { |
946 if (!it->second.info()->IsStackAllocated()) | 946 if (!it->second.info()->IsStackAllocated()) |
947 ReportDerivesNonStackAllocated(info, &it->second); | 947 ReportDerivesNonStackAllocated(info, &it->second); |
948 } | 948 } |
949 } | 949 } |
950 | 950 |
951 if (CXXMethodDecl* trace = info->GetTraceMethod()) { | 951 if (CXXMethodDecl* trace = info->GetTraceMethod()) { |
952 if (trace->isPure()) | 952 if (trace->isPure()) |
953 ReportClassDeclaresPureVirtualTrace(info, trace); | 953 ReportClassDeclaresPureVirtualTrace(info, trace); |
954 if (info->record()->isPolymorphic()) | |
955 CheckPolymorphicClass(info, trace); | |
956 } else if (info->RequiresTraceMethod()) { | 954 } else if (info->RequiresTraceMethod()) { |
957 ReportClassRequiresTraceMethod(info); | 955 ReportClassRequiresTraceMethod(info); |
958 } | 956 } |
959 | 957 |
| 958 // Check polymorphic classes that are GC-derived or have a trace method. |
| 959 if (info->record()->hasDefinition() && info->record()->isPolymorphic()) { |
| 960 CXXMethodDecl* trace = info->GetTraceMethod(); |
| 961 if (trace || info->IsGCDerived()) |
| 962 CheckPolymorphicClass(info, trace); |
| 963 } |
| 964 |
960 { | 965 { |
961 CheckFieldsVisitor visitor(options_); | 966 CheckFieldsVisitor visitor(options_); |
962 if (visitor.ContainsInvalidFields(info)) | 967 if (visitor.ContainsInvalidFields(info)) |
963 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); | 968 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); |
964 } | 969 } |
965 | 970 |
966 if (info->IsGCDerived()) { | 971 if (info->IsGCDerived()) { |
967 | 972 |
968 if (!info->IsGCMixin()) { | 973 if (!info->IsGCMixin()) { |
969 CheckLeftMostDerived(info); | 974 CheckLeftMostDerived(info); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 | 1008 |
1004 // The GC infrastructure assumes that if the vtable of a polymorphic | 1009 // The GC infrastructure assumes that if the vtable of a polymorphic |
1005 // base-class is not initialized for a given object (ie, it is partially | 1010 // base-class is not initialized for a given object (ie, it is partially |
1006 // initialized) then the object does not need to be traced. Thus, we must | 1011 // initialized) then the object does not need to be traced. Thus, we must |
1007 // ensure that any polymorphic class with a trace method does not have any | 1012 // ensure that any polymorphic class with a trace method does not have any |
1008 // tractable fields that are initialized before we are sure that the vtable | 1013 // tractable fields that are initialized before we are sure that the vtable |
1009 // and the trace method are both defined. There are two cases that need to | 1014 // and the trace method are both defined. There are two cases that need to |
1010 // hold to satisfy that assumption: | 1015 // hold to satisfy that assumption: |
1011 // | 1016 // |
1012 // 1. If trace is virtual, then it must be defined in the left-most base. | 1017 // 1. If trace is virtual, then it must be defined in the left-most base. |
1013 // This ensures that if the vtable is initialized and it contains a pointer to | 1018 // This ensures that if the vtable is initialized then it contains a pointer |
1014 // the trace method. | 1019 // to the trace method. |
1015 // | 1020 // |
1016 // 2. If trace is non-virtual, then the trace method is defined and we must | 1021 // 2. If trace is non-virtual, then the trace method is defined and we must |
1017 // ensure that the left-most base defines a vtable. This ensures that the | 1022 // ensure that the left-most base defines a vtable. This ensures that the |
1018 // first thing to be initialized when constructing the object is the vtable | 1023 // first thing to be initialized when constructing the object is the vtable |
1019 // itself. | 1024 // itself. |
1020 void CheckPolymorphicClass(RecordInfo* info, CXXMethodDecl* trace) { | 1025 void CheckPolymorphicClass(RecordInfo* info, CXXMethodDecl* trace) { |
1021 CXXRecordDecl* left_most = info->record(); | 1026 CXXRecordDecl* left_most = info->record(); |
1022 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); | 1027 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); |
1023 CXXRecordDecl* left_most_base = 0; | 1028 CXXRecordDecl* left_most_base = 0; |
1024 while (it != left_most->bases_end()) { | 1029 while (it != left_most->bases_end()) { |
1025 left_most_base = it->getType()->getAsCXXRecordDecl(); | 1030 left_most_base = it->getType()->getAsCXXRecordDecl(); |
1026 if (!left_most_base && it->getType()->isDependentType()) | 1031 if (!left_most_base && it->getType()->isDependentType()) |
1027 left_most_base = GetDependentTemplatedDecl(*it->getType()); | 1032 left_most_base = GetDependentTemplatedDecl(*it->getType()); |
1028 | 1033 |
1029 // TODO: Find a way to correctly check actual instantiations | 1034 // TODO: Find a way to correctly check actual instantiations |
1030 // for dependent types. The escape below will be hit, eg, when | 1035 // for dependent types. The escape below will be hit, eg, when |
1031 // we have a primary template with no definition and | 1036 // we have a primary template with no definition and |
1032 // specializations for each case (such as SupplementBase) in | 1037 // specializations for each case (such as SupplementBase) in |
1033 // which case we don't succeed in checking the required | 1038 // which case we don't succeed in checking the required |
1034 // properties. | 1039 // properties. |
1035 if (!left_most_base || !left_most_base->hasDefinition()) | 1040 if (!left_most_base || !left_most_base->hasDefinition()) |
1036 return; | 1041 return; |
1037 | 1042 |
1038 StringRef name = left_most_base->getName(); | 1043 StringRef name = left_most_base->getName(); |
1039 // We know GCMixin base defines virtual trace. | 1044 // We know GCMixin base defines virtual trace. |
1040 if (Config::IsGCMixinBase(name)) | 1045 if (Config::IsGCMixinBase(name)) |
1041 return; | 1046 return; |
1042 | 1047 |
1043 // Stop with the left-most prior to a safe polymorphic base (a safe base | 1048 // Stop with the left-most prior to a safe polymorphic base (a safe base |
1044 // is non-polymorphic and contains no fields that need tracing). | 1049 // is non-polymorphic and contains no fields). |
1045 if (Config::IsSafePolymorphicBase(name)) | 1050 if (Config::IsSafePolymorphicBase(name)) |
1046 break; | 1051 break; |
1047 | 1052 |
1048 left_most = left_most_base; | 1053 left_most = left_most_base; |
1049 it = left_most->bases_begin(); | 1054 it = left_most->bases_begin(); |
1050 } | 1055 } |
1051 | 1056 |
1052 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) { | 1057 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) { |
1053 | 1058 |
1054 // Check condition (1): | 1059 // Check condition (1): |
1055 if (trace->isVirtual()) { | 1060 if (trace && trace->isVirtual()) { |
1056 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) { | 1061 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) { |
1057 if (trace->isVirtual()) | 1062 if (trace->isVirtual()) |
1058 return; | 1063 return; |
1059 } | 1064 } |
1060 ReportBaseClassMustDeclareVirtualTrace(info, left_most); | 1065 ReportBaseClassMustDeclareVirtualTrace(info, left_most); |
1061 return; | 1066 return; |
1062 } | 1067 } |
1063 | 1068 |
1064 // Check condition (2): | 1069 // Check condition (2): |
1065 if (DeclaresVirtualMethods(info->record())) | 1070 if (DeclaresVirtualMethods(left_most)) |
1066 return; | 1071 return; |
1067 if (left_most_base) { | 1072 if (left_most_base) { |
1068 ++it; // Get the base next to the "safe polymorphic base" | 1073 ++it; // Get the base next to the "safe polymorphic base" |
1069 if (it != left_most->bases_end()) { | 1074 if (it != left_most->bases_end()) { |
1070 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) { | 1075 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) { |
1071 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) { | 1076 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) { |
1072 if (DeclaresVirtualMethods(next_left_most)) | 1077 if (DeclaresVirtualMethods(next_left_most)) |
1073 return; | 1078 return; |
1074 ReportLeftMostBaseMustBePolymorphic(info, next_left_most); | 1079 ReportLeftMostBaseMustBePolymorphic(info, next_left_most); |
1075 return; | 1080 return; |
(...skipping 792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1868 | 1873 |
1869 private: | 1874 private: |
1870 BlinkGCPluginOptions options_; | 1875 BlinkGCPluginOptions options_; |
1871 }; | 1876 }; |
1872 | 1877 |
1873 } // namespace | 1878 } // namespace |
1874 | 1879 |
1875 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1880 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
1876 "blink-gc-plugin", | 1881 "blink-gc-plugin", |
1877 "Check Blink GC invariants"); | 1882 "Check Blink GC invariants"); |
OLD | NEW |