Runtime flags only for fast/slow hiddenapi path
With more flags being supported in the dex file, stop copying all of
them into ArtField/ArtMethod access flags. Instead, store the
information needed to figure out whether to enter the slow path and
retrieve full access flags from dex or not.
At the moment, the only runtime flag is kAccPublicApi assigned to all
class members on the whitelist.
The CL also moves hardcoded API membership of intrinsics out of
ArtMethod and into hidden_api.h, and moves ArtMethod::SetIntrinsic
into the .cc file.
Test: m test-art
Change-Id: Ia1cc05060dbc22341768161dfd8697c6158e803a
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9bf31ed..abfdd55 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -33,6 +33,7 @@
#include "dex/dex_instruction.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
+#include "hidden_api.h"
#include "interpreter/interpreter.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
@@ -682,23 +683,72 @@
return GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize()) != nullptr;
}
+void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
+ // Currently we only do intrinsics for static/final methods or methods of final
+ // classes. We don't set kHasSingleImplementation for those methods.
+ DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) <<
+ "Potential conflict with kAccSingleImplementation";
+ static const int kAccFlagsShift = CTZ(kAccIntrinsicBits);
+ DCHECK_LE(intrinsic, kAccIntrinsicBits >> kAccFlagsShift);
+ uint32_t intrinsic_bits = intrinsic << kAccFlagsShift;
+ uint32_t new_value = (GetAccessFlags() & ~kAccIntrinsicBits) | kAccIntrinsic | intrinsic_bits;
+ if (kIsDebugBuild) {
+ uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
+ bool is_constructor = IsConstructor();
+ bool is_synchronized = IsSynchronized();
+ bool skip_access_checks = SkipAccessChecks();
+ bool is_fast_native = IsFastNative();
+ bool is_critical_native = IsCriticalNative();
+ bool is_copied = IsCopied();
+ bool is_miranda = IsMiranda();
+ bool is_default = IsDefault();
+ bool is_default_conflict = IsDefaultConflicting();
+ bool is_compilable = IsCompilable();
+ bool must_count_locks = MustCountLocks();
+ uint32_t hiddenapi_flags = hiddenapi::GetRuntimeFlags(this);
+ SetAccessFlags(new_value);
+ DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
+ DCHECK_EQ(is_constructor, IsConstructor());
+ DCHECK_EQ(is_synchronized, IsSynchronized());
+ DCHECK_EQ(skip_access_checks, SkipAccessChecks());
+ DCHECK_EQ(is_fast_native, IsFastNative());
+ DCHECK_EQ(is_critical_native, IsCriticalNative());
+ DCHECK_EQ(is_copied, IsCopied());
+ DCHECK_EQ(is_miranda, IsMiranda());
+ DCHECK_EQ(is_default, IsDefault());
+ DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
+ DCHECK_EQ(is_compilable, IsCompilable());
+ DCHECK_EQ(must_count_locks, MustCountLocks());
+ // Only DCHECK that we have preserved the hidden API access flags if the
+ // original method was not on the whitelist. This is because the core image
+ // does not have the access flags set (b/77733081). It is fine to hard-code
+ // these because (a) warnings on greylist do not change semantics, and
+ // (b) only VarHandle intrinsics are blacklisted at the moment and they
+ // should not be used outside tests with disabled API checks.
+ if ((hiddenapi_flags & kAccHiddenapiBits) == 0) {
+ DCHECK_EQ(hiddenapi_flags, hiddenapi::GetRuntimeFlags(this)) << PrettyMethod();
+ }
+ } else {
+ SetAccessFlags(new_value);
+ }
+}
+
void ArtMethod::SetNotIntrinsic() {
if (!IsIntrinsic()) {
return;
}
- // Query the hidden API access flags of the intrinsic.
- hiddenapi::ApiList intrinsic_api_list = GetHiddenApiAccessFlags();
+ // Read the existing hiddenapi flags.
+ uint32_t hiddenapi_runtime_flags = hiddenapi::GetRuntimeFlags(this);
// Clear intrinsic-related access flags.
ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits);
// Re-apply hidden API access flags now that the method is not an intrinsic.
- SetAccessFlags(hiddenapi::EncodeForRuntime(GetAccessFlags(), intrinsic_api_list));
- DCHECK_EQ(GetHiddenApiAccessFlags(), intrinsic_api_list);
+ SetAccessFlags(GetAccessFlags() | hiddenapi_runtime_flags);
+ DCHECK_EQ(hiddenapi_runtime_flags, hiddenapi::GetRuntimeFlags(this));
}
-
void ArtMethod::CopyFrom(ArtMethod* src, PointerSize image_pointer_size) {
memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src),
Size(image_pointer_size));