ART: Fixes for constructor parameter annotations
Synthesize empty parameter annotations for implicit parameters on
constructors. Reflective methods for recovering parameter annotations
expect them to be present though they may not be present in the DEX file.
Bug: b/68033708
Test: art/test/run-test --host 715
Change-Id: I0827c7e71ff7c7e044fc9dd6c5aac639a0e1a4c6
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index a5e70af..b129c66 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -70,7 +70,6 @@
if (method->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
- StackHandleScope<1> hs(soa.Self());
return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForMethod(method));
}
@@ -80,9 +79,76 @@
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
if (method->IsProxyMethod()) {
return nullptr;
- } else {
- return soa.AddLocalReference<jobjectArray>(annotations::GetParameterAnnotations(method));
}
+
+ StackHandleScope<4> hs(soa.Self());
+ Handle<mirror::ObjectArray<mirror::Object>> annotations =
+ hs.NewHandle(annotations::GetParameterAnnotations(method));
+ if (annotations.IsNull()) {
+ return nullptr;
+ }
+
+ // If the method is not a constructor, or has parameter annotations
+ // for each parameter, then we can return those annotations
+ // unmodified. Otherwise, we need to look at whether the
+ // constructor has implicit parameters as these may need padding
+ // with empty parameter annotations.
+ if (!method->IsConstructor() ||
+ annotations->GetLength() == static_cast<int>(method->GetNumberOfParameters())) {
+ return soa.AddLocalReference<jobjectArray>(annotations.Get());
+ }
+
+ // If declaring class is a local or an enum, do not pad parameter
+ // annotations, as the implicit constructor parameters are an implementation
+ // detail rather than required by JLS.
+ Handle<mirror::Class> declaring_class = hs.NewHandle(method->GetDeclaringClass());
+ if (annotations::GetEnclosingMethod(declaring_class) != nullptr ||
+ declaring_class->IsEnum()) {
+ return soa.AddLocalReference<jobjectArray>(annotations.Get());
+ }
+
+ // Prepare to resize the annotations so there is 1:1 correspondence
+ // with the constructor parameters.
+ Handle<mirror::ObjectArray<mirror::Object>> resized_annotations = hs.NewHandle(
+ mirror::ObjectArray<mirror::Object>::Alloc(
+ soa.Self(),
+ annotations->GetClass(),
+ static_cast<int>(method->GetNumberOfParameters())));
+ if (resized_annotations.IsNull()) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
+ }
+
+ static constexpr bool kTransactionActive = false;
+ const int32_t offset = resized_annotations->GetLength() - annotations->GetLength();
+ if (offset > 0) {
+ // Workaround for dexers (d8/dx) that do not insert annotations
+ // for implicit parameters (b/68033708).
+ ObjPtr<mirror::Class> annotation_array_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
+ Handle<mirror::ObjectArray<mirror::Object>> empty_annotations = hs.NewHandle(
+ mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0));
+ if (empty_annotations.IsNull()) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
+ }
+ for (int i = 0; i < offset; ++i) {
+ resized_annotations->SetWithoutChecks<kTransactionActive>(i, empty_annotations.Get());
+ }
+ for (int i = 0; i < annotations->GetLength(); ++i) {
+ ObjPtr<mirror::Object> annotation = annotations->GetWithoutChecks(i);
+ resized_annotations->SetWithoutChecks<kTransactionActive>(i + offset, annotation);
+ }
+ } else {
+ // Workaround for Jack (defunct) erroneously inserting annotations
+ // for local classes (b/68033708).
+ DCHECK_LT(offset, 0);
+ for (int i = 0; i < resized_annotations->GetLength(); ++i) {
+ ObjPtr<mirror::Object> annotation = annotations->GetWithoutChecks(i - offset);
+ resized_annotations->SetWithoutChecks<kTransactionActive>(i, annotation);
+ }
+ }
+ return soa.AddLocalReference<jobjectArray>(resized_annotations.Get());
}
static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) {