| 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 |