Revision | 7348a4f236177005123c181da13b3db65ca0bf37 (tree) |
---|---|
Time | 2017-06-28 07:31:57 |
Author | Roland Levillain <rpl@goog...> |
Commiter | android-build-team Robot |
Only look for method optimization annotations in the bootstrap class loader.
When checking for an optimization annotation (FastNative or
CriticalNative) on a method, do not resolve the method's annotations'
classes as a side effect -- instead, look them up in the bootstrap
class loader's resolved types. This is to prevent exceptions from being
thrown (during class resolution) in JNI transitions.
This change does not affect annotation lookup rules in the context of
reflection.
(cherry-picked from commit 35e42f0ab3b70203038fe037ee50d39e2d37af9a)
Test: art/test/testrunner/testrunner.py -t 656-annotation-lookup-generic-jni
Bug: 38454151
Bug: 34659969
Change-Id: Ie6b8b30b96a08baa629c449e3803a031515508d1
(cherry picked from commit 2ed6cce6fcfd031b0f9d83111f01b6b48ead1a32)
@@ -403,15 +403,19 @@ bool ArtMethod::IsOverridableByDefaultMethod() { | ||
403 | 403 | |
404 | 404 | bool ArtMethod::IsAnnotatedWithFastNative() { |
405 | 405 | return IsAnnotatedWith(WellKnownClasses::dalvik_annotation_optimization_FastNative, |
406 | - DexFile::kDexVisibilityBuild); | |
406 | + DexFile::kDexVisibilityBuild, | |
407 | + /* lookup_in_resolved_boot_classes */ true); | |
407 | 408 | } |
408 | 409 | |
409 | 410 | bool ArtMethod::IsAnnotatedWithCriticalNative() { |
410 | 411 | return IsAnnotatedWith(WellKnownClasses::dalvik_annotation_optimization_CriticalNative, |
411 | - DexFile::kDexVisibilityBuild); | |
412 | + DexFile::kDexVisibilityBuild, | |
413 | + /* lookup_in_resolved_boot_classes */ true); | |
412 | 414 | } |
413 | 415 | |
414 | -bool ArtMethod::IsAnnotatedWith(jclass klass, uint32_t visibility) { | |
416 | +bool ArtMethod::IsAnnotatedWith(jclass klass, | |
417 | + uint32_t visibility, | |
418 | + bool lookup_in_resolved_boot_classes) { | |
415 | 419 | Thread* self = Thread::Current(); |
416 | 420 | ScopedObjectAccess soa(self); |
417 | 421 | StackHandleScope<1> shs(self); |
@@ -420,10 +424,8 @@ bool ArtMethod::IsAnnotatedWith(jclass klass, uint32_t visibility) { | ||
420 | 424 | DCHECK(annotation->IsAnnotation()); |
421 | 425 | Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation)); |
422 | 426 | |
423 | - // Note: Resolves any method annotations' classes as a side-effect. | |
424 | - // -- This seems allowed by the spec since it says we can preload any classes | |
425 | - // referenced by another classes's constant pool table. | |
426 | - return annotations::IsMethodAnnotationPresent(this, annotation_handle, visibility); | |
427 | + return annotations::IsMethodAnnotationPresent( | |
428 | + this, annotation_handle, visibility, lookup_in_resolved_boot_classes); | |
427 | 429 | } |
428 | 430 | |
429 | 431 | static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, |
@@ -716,7 +716,10 @@ class ArtMethod FINAL { | ||
716 | 716 | private: |
717 | 717 | uint16_t FindObsoleteDexClassDefIndex() REQUIRES_SHARED(Locks::mutator_lock_); |
718 | 718 | |
719 | - bool IsAnnotatedWith(jclass klass, uint32_t visibility); | |
719 | + // If `lookup_in_resolved_boot_classes` is true, look up any of the | |
720 | + // method's annotations' classes in the bootstrap class loader's | |
721 | + // resolved types; otherwise, resolve them as a side effect. | |
722 | + bool IsAnnotatedWith(jclass klass, uint32_t visibility, bool lookup_in_resolved_boot_classes); | |
720 | 723 | |
721 | 724 | static constexpr size_t PtrSizedFieldsOffset(PointerSize pointer_size) { |
722 | 725 | // Round up to pointer size for padding field. Tested in art_method.cc. |
@@ -751,7 +751,8 @@ const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet( | ||
751 | 751 | const ClassData& klass, |
752 | 752 | const DexFile::AnnotationSetItem* annotation_set, |
753 | 753 | uint32_t visibility, |
754 | - Handle<mirror::Class> annotation_class) | |
754 | + Handle<mirror::Class> annotation_class, | |
755 | + bool lookup_in_resolved_boot_classes = false) | |
755 | 756 | REQUIRES_SHARED(Locks::mutator_lock_) { |
756 | 757 | const DexFile& dex_file = klass.GetDexFile(); |
757 | 758 | for (uint32_t i = 0; i < annotation_set->size_; ++i) { |
@@ -761,19 +762,37 @@ const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet( | ||
761 | 762 | } |
762 | 763 | const uint8_t* annotation = annotation_item->annotation_; |
763 | 764 | uint32_t type_index = DecodeUnsignedLeb128(&annotation); |
764 | - StackHandleScope<2> hs(Thread::Current()); | |
765 | - mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType( | |
766 | - klass.GetDexFile(), | |
767 | - dex::TypeIndex(type_index), | |
768 | - hs.NewHandle(klass.GetDexCache()), | |
769 | - hs.NewHandle(klass.GetClassLoader())); | |
770 | - if (resolved_class == nullptr) { | |
771 | - std::string temp; | |
772 | - LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d", | |
773 | - klass.GetRealClass()->GetDescriptor(&temp), type_index); | |
774 | - CHECK(Thread::Current()->IsExceptionPending()); | |
775 | - Thread::Current()->ClearException(); | |
776 | - continue; | |
765 | + mirror::Class* resolved_class; | |
766 | + if (lookup_in_resolved_boot_classes) { | |
767 | + ObjPtr<mirror::Class> looked_up_class = | |
768 | + Runtime::Current()->GetClassLinker()->LookupResolvedType( | |
769 | + klass.GetDexFile(), | |
770 | + dex::TypeIndex(type_index), | |
771 | + klass.GetDexCache(), | |
772 | + // Force the use of the bootstrap class loader. | |
773 | + static_cast<mirror::ClassLoader*>(nullptr)); | |
774 | + resolved_class = looked_up_class.Ptr(); | |
775 | + if (resolved_class == nullptr) { | |
776 | + // If `resolved_class` is null, this is fine: just ignore that | |
777 | + // annotation item. We expect this to happen, as we do not | |
778 | + // attempt to resolve the annotation's class in this code path. | |
779 | + continue; | |
780 | + } | |
781 | + } else { | |
782 | + StackHandleScope<2> hs(Thread::Current()); | |
783 | + resolved_class = Runtime::Current()->GetClassLinker()->ResolveType( | |
784 | + klass.GetDexFile(), | |
785 | + dex::TypeIndex(type_index), | |
786 | + hs.NewHandle(klass.GetDexCache()), | |
787 | + hs.NewHandle(klass.GetClassLoader())); | |
788 | + if (resolved_class == nullptr) { | |
789 | + std::string temp; | |
790 | + LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d", | |
791 | + klass.GetRealClass()->GetDescriptor(&temp), type_index); | |
792 | + CHECK(Thread::Current()->IsExceptionPending()); | |
793 | + Thread::Current()->ClearException(); | |
794 | + continue; | |
795 | + } | |
777 | 796 | } |
778 | 797 | if (resolved_class == annotation_class.Get()) { |
779 | 798 | return annotation_item; |
@@ -1200,15 +1219,20 @@ mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* | ||
1200 | 1219 | return GetSignatureValue(ClassData(method), annotation_set); |
1201 | 1220 | } |
1202 | 1221 | |
1203 | -bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class, | |
1204 | - uint32_t visibility /* = DexFile::kDexVisibilityRuntime */) { | |
1222 | +bool IsMethodAnnotationPresent(ArtMethod* method, | |
1223 | + Handle<mirror::Class> annotation_class, | |
1224 | + uint32_t visibility /* = DexFile::kDexVisibilityRuntime */, | |
1225 | + bool lookup_in_resolved_boot_classes /* = false */) { | |
1205 | 1226 | const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); |
1206 | 1227 | if (annotation_set == nullptr) { |
1207 | 1228 | return false; |
1208 | 1229 | } |
1209 | 1230 | const DexFile::AnnotationItem* annotation_item = |
1210 | 1231 | GetAnnotationItemFromAnnotationSet(ClassData(method), |
1211 | - annotation_set, visibility, annotation_class); | |
1232 | + annotation_set, | |
1233 | + visibility, | |
1234 | + annotation_class, | |
1235 | + lookup_in_resolved_boot_classes); | |
1212 | 1236 | return annotation_item != nullptr; |
1213 | 1237 | } |
1214 | 1238 |
@@ -65,8 +65,15 @@ bool GetParametersMetadataForMethod(ArtMethod* method, | ||
65 | 65 | REQUIRES_SHARED(Locks::mutator_lock_); |
66 | 66 | mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) |
67 | 67 | REQUIRES_SHARED(Locks::mutator_lock_); |
68 | -bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class, | |
69 | - uint32_t visibility = DexFile::kDexVisibilityRuntime) | |
68 | +// Check whether `method` is annotated with `annotation_class`. | |
69 | +// If `lookup_in_resolved_boot_classes` is true, look up any of the | |
70 | +// method's annotations' classes in the bootstrap class loader's | |
71 | +// resolved types; if it is false (default value), resolve them as a | |
72 | +// side effect. | |
73 | +bool IsMethodAnnotationPresent(ArtMethod* method, | |
74 | + Handle<mirror::Class> annotation_class, | |
75 | + uint32_t visibility = DexFile::kDexVisibilityRuntime, | |
76 | + bool lookup_in_resolved_boot_classes = false) | |
70 | 77 | REQUIRES_SHARED(Locks::mutator_lock_); |
71 | 78 | |
72 | 79 | // Class annotations. |
@@ -2086,6 +2086,11 @@ extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** | ||
2086 | 2086 | self->SetTopOfStack(sp); |
2087 | 2087 | uint32_t shorty_len = 0; |
2088 | 2088 | const char* shorty = called->GetShorty(&shorty_len); |
2089 | + // Optimization annotations lookup does not try to resolve classes, | |
2090 | + // as this may throw an exception, which is not supported by the | |
2091 | + // Generic JNI trampoline at this stage; instead, method's | |
2092 | + // annotations' classes are looked up in the bootstrap class | |
2093 | + // loader's resolved types (which won't trigger an exception). | |
2089 | 2094 | bool critical_native = called->IsAnnotatedWithCriticalNative(); |
2090 | 2095 | // ArtMethod::IsAnnotatedWithCriticalNative should not throw |
2091 | 2096 | // an exception; clear it if it happened anyway. |