Run time illegal access checks on static and direct methods
Fixes test 075.
Change-Id: I28b20451dcae8000dc0e2cb9068dfa5166659d43
diff --git a/src/compiler.cc b/src/compiler.cc
index 35108bb..08c6cc4 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -71,19 +71,36 @@
LOG(INFO) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases";
}
-void AOTCompilationStats::Dump() {
- DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache");
- DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache");
- DumpStat(resolved_types_, unresolved_types_, "types resolved");
- DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
- DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
- "static fields resolved");
- DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
- "static fields local to a class");
- DumpStat(resolved_virtual_methods_, unresolved_virtual_methods_, "resolved virtual methods");
- DumpStat(resolved_super_methods_, unresolved_super_methods_, "resolved super-class methods");
- DumpStat(resolved_interface_methods_, unresolved_interface_methods_, "resolved interface methods");
-}
+class AOTCompilationStats {
+ public:
+ AOTCompilationStats() : stats_lock_("AOT compilation statistics lock"),
+ types_in_dex_cache_(0), types_not_in_dex_cache_(0),
+ strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
+ resolved_types_(0), unresolved_types_(0),
+ resolved_instance_fields_(0), unresolved_instance_fields_(0),
+ resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0) {
+ for (size_t i = 0; i < kMaxInvokeType; i++) {
+ resolved_methods_[i] = 0;
+ unresolved_methods_[i] = 0;
+ }
+ }
+
+ void Dump() {
+ DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache");
+ DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache");
+ DumpStat(resolved_types_, unresolved_types_, "types resolved");
+ DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
+ DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
+ "static fields resolved");
+ DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
+ "static fields local to a class");
+
+ for (size_t i = 0; i < kMaxInvokeType; i++) {
+ std::ostringstream oss;
+ oss << "resolved " << static_cast<InvokeType>(i) << " methods";
+ DumpStat(resolved_methods_[i], unresolved_methods_[i], oss.str().c_str());
+ }
+ }
// Allow lossy statistics in non-debug builds
#ifndef NDEBUG
@@ -92,82 +109,97 @@
#define STATS_LOCK()
#endif
-void AOTCompilationStats::TypeInDexCache() {
- STATS_LOCK();
- types_in_dex_cache_++;
-}
-
-void AOTCompilationStats::TypeNotInDexCache() {
- STATS_LOCK();
- types_not_in_dex_cache_++;
-}
-
-void AOTCompilationStats::StringInDexCache() {
- STATS_LOCK();
- strings_in_dex_cache_++;
-}
-
-void AOTCompilationStats::StringNotInDexCache() {
- STATS_LOCK();
- strings_not_in_dex_cache_++;
-}
-
-void AOTCompilationStats::TypeDoesntNeedAccessCheck() {
- STATS_LOCK();
- resolved_types_++;
-}
-
-void AOTCompilationStats::TypeNeedsAccessCheck() {
- STATS_LOCK();
- unresolved_types_++;
-}
-
-void AOTCompilationStats::ResolvedInstanceField() {
- STATS_LOCK();
- resolved_instance_fields_++;
-}
-
-void AOTCompilationStats::UnresolvedInstanceField(){
- STATS_LOCK();
- unresolved_instance_fields_++;
-}
-
-void AOTCompilationStats::ResolvedLocalStaticField() {
- STATS_LOCK();
- resolved_local_static_fields_++;
-}
-
-void AOTCompilationStats::ResolvedStaticField() {
- STATS_LOCK();
- resolved_static_fields_++;
-}
-
-void AOTCompilationStats::UnresolvedStaticField() {
- STATS_LOCK();
- unresolved_static_fields_++;
-}
-
-void AOTCompilationStats::ResolvedMethod(bool is_interface, bool is_super) {
- STATS_LOCK();
- if (is_interface) {
- resolved_interface_methods_++;
- } else if (is_super) {
- resolved_super_methods_++;
- } else {
- resolved_virtual_methods_++;
+ void TypeInDexCache() {
+ STATS_LOCK();
+ types_in_dex_cache_++;
}
-}
-void AOTCompilationStats::UnresolvedMethod(bool is_interface, bool is_super) {
- STATS_LOCK();
- if (is_interface) {
- unresolved_interface_methods_++;
- } else if (is_super) {
- unresolved_super_methods_++;
- } else {
- unresolved_virtual_methods_++;
+ void TypeNotInDexCache() {
+ STATS_LOCK();
+ types_not_in_dex_cache_++;
}
-}
+
+ void StringInDexCache() {
+ STATS_LOCK();
+ strings_in_dex_cache_++;
+ }
+
+ void StringNotInDexCache() {
+ STATS_LOCK();
+ strings_not_in_dex_cache_++;
+ }
+
+ void TypeDoesntNeedAccessCheck() {
+ STATS_LOCK();
+ resolved_types_++;
+ }
+
+ void TypeNeedsAccessCheck() {
+ STATS_LOCK();
+ unresolved_types_++;
+ }
+
+ void ResolvedInstanceField() {
+ STATS_LOCK();
+ resolved_instance_fields_++;
+ }
+
+ void UnresolvedInstanceField(){
+ STATS_LOCK();
+ unresolved_instance_fields_++;
+ }
+
+ void ResolvedLocalStaticField() {
+ STATS_LOCK();
+ resolved_local_static_fields_++;
+ }
+
+ void ResolvedStaticField() {
+ STATS_LOCK();
+ resolved_static_fields_++;
+ }
+
+ void UnresolvedStaticField() {
+ STATS_LOCK();
+ unresolved_static_fields_++;
+ }
+
+ void ResolvedMethod(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
+ STATS_LOCK();
+ resolved_methods_[type]++;
+ }
+
+ void UnresolvedMethod(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
+ STATS_LOCK();
+ unresolved_methods_[type]++;
+ }
+
+ private:
+ Mutex stats_lock_;
+
+ size_t types_in_dex_cache_;
+ size_t types_not_in_dex_cache_;
+
+ size_t strings_in_dex_cache_;
+ size_t strings_not_in_dex_cache_;
+
+ size_t resolved_types_;
+ size_t unresolved_types_;
+
+ size_t resolved_instance_fields_;
+ size_t unresolved_instance_fields_;
+
+ size_t resolved_local_static_fields_;
+ size_t resolved_static_fields_;
+ size_t unresolved_static_fields_;
+
+ size_t resolved_methods_[kMaxInvokeType + 1];
+ size_t unresolved_methods_[kMaxInvokeType + 1];
+
+ DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
+};
Compiler::Compiler(InstructionSet instruction_set, bool image, size_t thread_count,
const std::set<std::string>* image_classes)
@@ -178,6 +210,7 @@
compiled_invoke_stubs_lock_("compiled invoke stubs lock"),
image_(image),
thread_count_(thread_count),
+ stats_(new AOTCompilationStats),
image_classes_(image_classes)
#if defined(ART_USE_LLVM_COMPILER)
,
@@ -257,7 +290,7 @@
timings.Dump();
}
- stats_.Dump();
+ stats_->Dump();
}
void Compiler::CompileOne(const Method* method) {
@@ -320,19 +353,19 @@
bool Compiler::CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache,
uint32_t type_idx) {
if (!IsImage()) {
- stats_.TypeNotInDexCache();
+ stats_->TypeNotInDexCache();
return false;
}
Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == NULL) {
- stats_.TypeNotInDexCache();
+ stats_->TypeNotInDexCache();
return false;
}
bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor());
if (result) {
- stats_.TypeInDexCache();
+ stats_->TypeInDexCache();
} else {
- stats_.TypeNotInDexCache();
+ stats_->TypeNotInDexCache();
}
return result;
}
@@ -346,9 +379,9 @@
// image classes then we can assume the string is present in the dex cache if it is there now
bool result = IsImage() && image_classes_ == NULL && dex_cache->GetResolvedString(string_idx) != NULL;
if (result) {
- stats_.StringInDexCache();
+ stats_->StringInDexCache();
} else {
- stats_.StringNotInDexCache();
+ stats_->StringNotInDexCache();
}
return result;
}
@@ -358,22 +391,22 @@
// Get type from dex cache assuming it was populated by the verifier
Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
if (referrer_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Incomplete referrer knowledge needs access check.
}
// Perform access check, will return true if access is ok or false if we're going to have to
// check this at runtime (for example for class loaders).
bool result = referrer_class->CanAccess(resolved_class);
if (result) {
- stats_.TypeDoesntNeedAccessCheck();
+ stats_->TypeDoesntNeedAccessCheck();
} else {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
}
return result;
}
@@ -385,22 +418,22 @@
// Get type from dex cache assuming it was populated by the verifier.
Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
if (referrer_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Incomplete referrer knowledge needs access check.
}
// Perform access and instantiable checks, will return true if access is ok or false if we're
// going to have to check this at runtime (for example for class loaders).
bool result = referrer_class->CanAccess(resolved_class) && resolved_class->IsInstantiable();
if (result) {
- stats_.TypeDoesntNeedAccessCheck();
+ stats_->TypeDoesntNeedAccessCheck();
} else {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
}
return result;
}
@@ -439,7 +472,7 @@
resolved_field->GetAccessFlags())) {
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedInstanceField();
+ stats_->ResolvedInstanceField();
return true; // Fast path.
}
}
@@ -448,7 +481,7 @@
if (thread->IsExceptionPending()) {
thread->ClearException();
}
- stats_.UnresolvedInstanceField();
+ stats_->UnresolvedInstanceField();
return false; // Incomplete knowledge needs slow path.
}
@@ -470,7 +503,7 @@
is_referrers_class = true; // implies no worrying about class initialization
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedLocalStaticField();
+ stats_->ResolvedLocalStaticField();
return true; // fast path
} else {
Class* fields_class = resolved_field->GetDeclaringClass();
@@ -487,7 +520,7 @@
ssb_index = fields_class->GetDexTypeIndex();
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedStaticField();
+ stats_->ResolvedStaticField();
return true;
}
// Search dex file for localized ssb index
@@ -502,7 +535,7 @@
ssb_index = cUnit->dex_file->GetIndexForTypeId(*type_id);
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedStaticField();
+ stats_->ResolvedStaticField();
return true;
}
}
@@ -515,12 +548,11 @@
if (thread->IsExceptionPending()) {
thread->ClearException();
}
- stats_.UnresolvedStaticField();
+ stats_->UnresolvedStaticField();
return false; // Incomplete knowledge needs slow path.
}
-bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit,
- bool is_interface, bool is_super,
+bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
int& vtable_idx) {
vtable_idx = -1;
Method* resolved_method = ComputeReferrerMethod(cUnit, method_idx);
@@ -545,15 +577,15 @@
referrer_class->CanAccessMember(methods_class,
resolved_method->GetAccessFlags())) {
vtable_idx = resolved_method->GetMethodIndex();
- if (is_interface || !is_super) {
- // nothing left to do for virtual/interface dispatch
- stats_.ResolvedMethod(is_interface, is_super);
+ if (type != kSuper) {
+ // nothing left to do for static/direct/virtual/interface dispatch
+ stats_->ResolvedMethod(type);
return true;
} else {
// ensure the vtable index will be correct to dispatch in the vtable of the super class
if (referrer_class->IsSubClass(methods_class) &&
vtable_idx < methods_class->GetVTable()->GetLength()) {
- stats_.ResolvedMethod(is_interface, is_super);
+ stats_->ResolvedMethod(type);
return true;
}
}
@@ -565,7 +597,7 @@
if (thread->IsExceptionPending()) {
thread->ClearException();
}
- stats_.UnresolvedMethod(is_interface, is_super);
+ stats_->UnresolvedMethod(type);
return false; // Incomplete knowledge needs slow path.
}