summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/verified_method.cc20
-rw-r--r--compiler/driver/compiler_driver.cc13
-rw-r--r--oatdump/oatdump.cc10
-rw-r--r--runtime/barrier.cc8
-rw-r--r--runtime/barrier.h7
-rw-r--r--runtime/base/mutex.cc9
-rw-r--r--runtime/base/mutex.h2
-rw-r--r--runtime/base/stringpiece.h12
-rw-r--r--runtime/class_linker.cc156
-rw-r--r--runtime/class_linker.h41
-rw-r--r--runtime/class_linker_test.cc6
-rw-r--r--runtime/debugger.cc2
-rw-r--r--runtime/dex_instruction.h2
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h20
-rw-r--r--runtime/entrypoints/entrypoint_utils.h2
-rw-r--r--runtime/entrypoints/interpreter/interpreter_entrypoints.cc3
-rw-r--r--runtime/entrypoints/portable/portable_thread_entrypoints.cc6
-rw-r--r--runtime/entrypoints/portable/portable_trampoline_entrypoints.cc4
-rw-r--r--runtime/entrypoints/quick/quick_jni_entrypoints.cc11
-rw-r--r--runtime/entrypoints/quick/quick_thread_entrypoints.cc10
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc4
-rw-r--r--runtime/exception_test.cc2
-rw-r--r--runtime/gc/heap.h2
-rw-r--r--runtime/interpreter/interpreter.cc4
-rw-r--r--runtime/interpreter/interpreter_common.cc2
-rw-r--r--runtime/interpreter/interpreter_common.h2
-rw-r--r--runtime/interpreter/interpreter_goto_table_impl.cc56
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc92
-rw-r--r--runtime/jni_internal.cc2
-rw-r--r--runtime/mirror/class.h10
-rw-r--r--runtime/native/dalvik_system_DexFile.cc4
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc9
-rw-r--r--runtime/native/java_lang_Class.cc2
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc19
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc2
-rw-r--r--runtime/native/java_lang_reflect_Field.cc3
-rw-r--r--runtime/oat.h2
-rw-r--r--runtime/profiler.cc13
-rw-r--r--runtime/quick_exception_handler.cc2
-rw-r--r--runtime/reflection.cc2
-rw-r--r--runtime/reflection_test.cc2
-rw-r--r--runtime/runtime.cc16
-rw-r--r--runtime/runtime.h3
-rw-r--r--runtime/signal_catcher.cc19
-rw-r--r--runtime/thread-inl.h21
-rw-r--r--runtime/thread.cc8
-rw-r--r--runtime/thread.h13
-rw-r--r--runtime/thread_list.cc67
-rw-r--r--runtime/thread_list.h13
-rw-r--r--runtime/transaction_test.cc24
-rw-r--r--runtime/utils.cc14
-rw-r--r--runtime/verifier/instruction_flags.cc7
-rw-r--r--runtime/verifier/instruction_flags.h32
-rw-r--r--runtime/verifier/method_verifier.cc704
-rw-r--r--runtime/verifier/method_verifier.h17
-rw-r--r--runtime/verifier/method_verifier_test.cc5
-rw-r--r--runtime/verifier/reg_type-inl.h183
-rw-r--r--runtime/verifier/reg_type.cc467
-rw-r--r--runtime/verifier/reg_type.h833
-rw-r--r--runtime/verifier/reg_type_cache-inl.h82
-rw-r--r--runtime/verifier/reg_type_cache.cc131
-rw-r--r--runtime/verifier/reg_type_cache.h54
-rw-r--r--runtime/verifier/reg_type_test.cc23
-rw-r--r--runtime/verifier/register_line-inl.h129
-rw-r--r--runtime/verifier/register_line.cc379
-rw-r--r--runtime/verifier/register_line.h92
66 files changed, 1982 insertions, 1934 deletions
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 01c8f80dd2..9f0a696096 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -38,7 +38,7 @@
#include "verifier/dex_gc_map.h"
#include "verifier/method_verifier.h"
#include "verifier/method_verifier-inl.h"
-#include "verifier/register_line.h"
+#include "verifier/reg_type-inl.h"
#include "verifier/register_line-inl.h"
namespace art {
@@ -127,7 +127,7 @@ bool VerifiedMethod::GenerateGcMap(verifier::MethodVerifier* method_verifier) {
dex_gc_map_.push_back((i >> 8) & 0xFF);
}
verifier::RegisterLine* line = method_verifier->GetRegLine(i);
- line->WriteReferenceBitMap(dex_gc_map_, ref_bitmap_bytes);
+ line->WriteReferenceBitMap(method_verifier, &dex_gc_map_, ref_bitmap_bytes);
}
}
DCHECK_EQ(dex_gc_map_.size(), table_size);
@@ -151,7 +151,7 @@ void VerifiedMethod::VerifyGcMap(verifier::MethodVerifier* method_verifier,
map_index++;
verifier::RegisterLine* line = method_verifier->GetRegLine(i);
for (size_t j = 0; j < code_item->registers_size_; j++) {
- if (line->GetRegisterType(j).IsNonZeroReferenceTypes()) {
+ if (line->GetRegisterType(method_verifier, j).IsNonZeroReferenceTypes()) {
DCHECK_LT(j / 8, map.RegWidth());
DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
} else if ((j / 8) < map.RegWidth()) {
@@ -178,7 +178,7 @@ void VerifiedMethod::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier
local_gc_points++;
max_insn = i;
verifier::RegisterLine* line = method_verifier->GetRegLine(i);
- max_ref_reg = line->GetMaxNonZeroReferenceReg(max_ref_reg);
+ max_ref_reg = line->GetMaxNonZeroReferenceReg(method_verifier, max_ref_reg);
}
}
*gc_points = local_gc_points;
@@ -217,7 +217,8 @@ void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier
bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) ||
(inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
const verifier::RegType&
- reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
+ reg_type(line->GetRegisterType(method_verifier,
+ is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
if (!reg_type.HasClass()) {
// We will compute devirtualization information only when we know the Class of the reg type.
@@ -284,17 +285,20 @@ void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifi
const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
bool is_safe_cast = false;
if (code == Instruction::CHECK_CAST) {
- const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+ const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
+ inst->VRegA_21c()));
const verifier::RegType& cast_type =
method_verifier->ResolveCheckedClass(inst->VRegB_21c());
is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type);
} else {
- const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x()));
+ const verifier::RegType& array_type(line->GetRegisterType(method_verifier,
+ inst->VRegB_23x()));
// We only know its safe to assign to an array if the array type is precise. For example,
// an Object[] can have any type of object stored in it, but it may also be assigned a
// String[] in which case the stores need to be of Strings.
if (array_type.IsPreciseReference()) {
- const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x()));
+ const verifier::RegType& value_type(line->GetRegisterType(method_verifier,
+ inst->VRegA_23x()));
const verifier::RegType& component_type = method_verifier->GetRegTypeCache()
->GetComponentType(array_type, method_verifier->GetClassLoader());
is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index db6a01eb82..bbd19396cd 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1725,15 +1725,15 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
*/
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
std::string error_msg;
- if (verifier::MethodVerifier::VerifyClass(&dex_file, dex_cache, class_loader, &class_def, true,
- &error_msg) ==
+ if (verifier::MethodVerifier::VerifyClass(soa.Self(), &dex_file, dex_cache, class_loader,
+ &class_def, true, &error_msg) ==
verifier::MethodVerifier::kHardFailure) {
LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor)
<< " because: " << error_msg;
}
} else if (!SkipClass(jclass_loader, dex_file, klass.Get())) {
CHECK(klass->IsResolved()) << PrettyClass(klass.Get());
- class_linker->VerifyClass(klass);
+ class_linker->VerifyClass(soa.Self(), klass);
if (klass->IsErroneous()) {
// ClassLinker::VerifyClass throws, which isn't useful in the compiler.
@@ -1778,7 +1778,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
if (klass->IsVerified()) {
// Attempt to initialize the class but bail if we either need to initialize the super-class
// or static fields.
- manager->GetClassLinker()->EnsureInitialized(klass, false, false);
+ manager->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false);
if (!klass->IsInitialized()) {
// We don't want non-trivial class initialization occurring on multiple threads due to
// deadlock problems. For example, a parent class is initialized (holding its lock) that
@@ -1792,7 +1792,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
ObjectLock<mirror::Class> lock(soa.Self(), h_klass);
// Attempt to initialize allowing initialization of parent classes but still not static
// fields.
- manager->GetClassLinker()->EnsureInitialized(klass, false, true);
+ manager->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, true);
if (!klass->IsInitialized()) {
// We need to initialize static fields, we only do this for image classes that aren't
// marked with the $NoPreloadHolder (which implies this should not be initialized early).
@@ -1811,7 +1811,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
// Run the class initializer in transaction mode.
runtime->EnterTransactionMode(&transaction);
const mirror::Class::Status old_status = klass->GetStatus();
- bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
+ bool success = manager->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true,
+ true);
// TODO we detach transaction from runtime to indicate we quit the transactional
// mode which prevents the GC from visiting objects modified during the transaction.
// Ensure GC is not run so don't access freed objects when aborting transaction.
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4cdf6187f5..6ca0bcdb16 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -656,7 +656,8 @@ class OatDumper {
StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(
hs.NewHandle(runtime->GetClassLinker()->FindDexCache(dex_file)));
- verifier::MethodVerifier verifier(&dex_file, dex_cache, NullHandle<mirror::ClassLoader>(),
+ verifier::MethodVerifier verifier(soa.Self(), &dex_file, dex_cache,
+ NullHandle<mirror::ClassLoader>(),
&class_def, code_item, dex_method_idx,
NullHandle<mirror::ArtMethod>(), method_access_flags,
true, true, true);
@@ -966,9 +967,10 @@ class OatDumper {
StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(
hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
- verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache,
- NullHandle<mirror::ClassLoader>(), &class_def,
- code_item, NullHandle<mirror::ArtMethod>(),
+ verifier::MethodVerifier::VerifyMethodAndDump(soa.Self(), os, dex_method_idx, dex_file,
+ dex_cache, NullHandle<mirror::ClassLoader>(),
+ &class_def, code_item,
+ NullHandle<mirror::ArtMethod>(),
method_access_flags);
}
}
diff --git a/runtime/barrier.cc b/runtime/barrier.cc
index 5f43bec01a..b8edad32af 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -57,17 +57,19 @@ void Barrier::Increment(Thread* self, int delta) {
}
}
-void Barrier::Increment(Thread* self, int delta, uint32_t timeout_ms) {
+bool Barrier::Increment(Thread* self, int delta, uint32_t timeout_ms) {
MutexLock mu(self, lock_);
SetCountLocked(self, count_ + delta);
+ bool timed_out = false;
if (count_ != 0) {
- condition_.TimedWait(self, timeout_ms, 0);
+ timed_out = condition_.TimedWait(self, timeout_ms, 0);
}
+ return timed_out;
}
void Barrier::SetCountLocked(Thread* self, int count) {
count_ = count;
- if (count_ == 0) {
+ if (count == 0) {
condition_.Broadcast(self);
}
}
diff --git a/runtime/barrier.h b/runtime/barrier.h
index a433caca1e..167e1d6bd9 100644
--- a/runtime/barrier.h
+++ b/runtime/barrier.h
@@ -38,10 +38,11 @@ class Barrier {
void Init(Thread* self, int count);
// Increment the count by delta, wait on condition if count is non zero.
- void Increment(Thread* self, int delta);
+ void Increment(Thread* self, int delta) LOCKS_EXCLUDED(lock_);
- // Increment the count by delta, wait on condition if count is non zero, with a timeout
- void Increment(Thread* self, int delta, uint32_t timeout_ms) LOCKS_EXCLUDED(lock_);
+ // Increment the count by delta, wait on condition if count is non zero, with a timeout. Returns
+ // true if time out occurred.
+ bool Increment(Thread* self, int delta, uint32_t timeout_ms) LOCKS_EXCLUDED(lock_);
private:
void SetCountLocked(Thread* self, int count) EXCLUSIVE_LOCKS_REQUIRED(lock_);
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index f01ea0c452..52a3dea61a 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -773,8 +773,9 @@ void ConditionVariable::WaitHoldingLocks(Thread* self) {
guard_.recursion_count_ = old_recursion_count;
}
-void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) {
+bool ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) {
DCHECK(self == NULL || self == Thread::Current());
+ bool timed_out = false;
guard_.AssertExclusiveHeld(self);
guard_.CheckSafeToWait(self);
unsigned int old_recursion_count = guard_.recursion_count_;
@@ -790,6 +791,7 @@ void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) {
if (futex(sequence_.Address(), FUTEX_WAIT, cur_sequence, &rel_ts, NULL, 0) != 0) {
if (errno == ETIMEDOUT) {
// Timed out we're done.
+ timed_out = true;
} else if ((errno == EAGAIN) || (errno == EINTR)) {
// A signal or ConditionVariable::Signal/Broadcast has come in.
} else {
@@ -814,13 +816,16 @@ void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) {
timespec ts;
InitTimeSpec(true, clock, ms, ns, &ts);
int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &guard_.mutex_, &ts));
- if (rc != 0 && rc != ETIMEDOUT) {
+ if (rc == ETIMEDOUT) {
+ timed_out = true;
+ } else if (rc != 0) {
errno = rc;
PLOG(FATAL) << "TimedWait failed for " << name_;
}
guard_.exclusive_owner_ = old_owner;
#endif
guard_.recursion_count_ = old_recursion_count;
+ return timed_out;
}
void Locks::Init() {
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 6642b1e989..354298e73e 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -382,7 +382,7 @@ class ConditionVariable {
// TODO: No thread safety analysis on Wait and TimedWait as they call mutex operations via their
// pointer copy, thereby defeating annotalysis.
void Wait(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
- void TimedWait(Thread* self, int64_t ms, int32_t ns) NO_THREAD_SAFETY_ANALYSIS;
+ bool TimedWait(Thread* self, int64_t ms, int32_t ns) NO_THREAD_SAFETY_ANALYSIS;
// Variant of Wait that should be used with caution. Doesn't validate that no mutexes are held
// when waiting.
// TODO: remove this.
diff --git a/runtime/base/stringpiece.h b/runtime/base/stringpiece.h
index 91b83f61dc..2dde245a8d 100644
--- a/runtime/base/stringpiece.h
+++ b/runtime/base/stringpiece.h
@@ -184,10 +184,22 @@ inline bool operator==(const StringPiece& x, const StringPiece& y) {
return memcmp(p1, p2, len) == 0;
}
+inline bool operator==(const StringPiece& x, const char* y) {
+ if (y == nullptr) {
+ return x.size() == 0;
+ } else {
+ return strncmp(x.data(), y, x.size()) == 0 && y[x.size()] == '\0';
+ }
+}
+
inline bool operator!=(const StringPiece& x, const StringPiece& y) {
return !(x == y);
}
+inline bool operator!=(const StringPiece& x, const char* y) {
+ return !(x == y);
+}
+
inline bool operator<(const StringPiece& x, const StringPiece& y) {
const int r = memcmp(x.data(), y.data(),
std::min(x.size(), y.size()));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 16cddd5f71..4474f1be5b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -64,7 +64,7 @@
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
#include "handle_scope-inl.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "utils.h"
#include "verifier/method_verifier.h"
#include "well_known_classes.h"
@@ -89,21 +89,29 @@ static void ThrowEarlierClassFailure(mirror::Class* c)
// a NoClassDefFoundError (v2 2.17.5). The exception to this rule is if we
// failed in verification, in which case v2 5.4.1 says we need to re-throw
// the previous error.
- if (!Runtime::Current()->IsCompiler()) { // Give info if this occurs at runtime.
+ Runtime* runtime = Runtime::Current();
+ bool is_compiler = runtime->IsCompiler();
+ if (!is_compiler) { // Give info if this occurs at runtime.
LOG(INFO) << "Rejecting re-init on previously-failed class " << PrettyClass(c);
}
CHECK(c->IsErroneous()) << PrettyClass(c) << " " << c->GetStatus();
Thread* self = Thread::Current();
- ThrowLocation throw_location = self->GetCurrentLocationForThrow();
- if (c->GetVerifyErrorClass() != NULL) {
- // TODO: change the verifier to store an _instance_, with a useful detail message?
- std::string temp;
- self->ThrowNewException(throw_location, c->GetVerifyErrorClass()->GetDescriptor(&temp),
- PrettyDescriptor(c).c_str());
+ if (is_compiler) {
+ // At compile time, accurate errors and NCDFE are disabled to speed compilation.
+ mirror::Throwable* pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(ThrowLocation(), pre_allocated);
} else {
- self->ThrowNewException(throw_location, "Ljava/lang/NoClassDefFoundError;",
- PrettyDescriptor(c).c_str());
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ if (c->GetVerifyErrorClass() != NULL) {
+ // TODO: change the verifier to store an _instance_, with a useful detail message?
+ std::string temp;
+ self->ThrowNewException(throw_location, c->GetVerifyErrorClass()->GetDescriptor(&temp),
+ PrettyDescriptor(c).c_str());
+ } else {
+ self->ThrowNewException(throw_location, "Ljava/lang/NoClassDefFoundError;",
+ PrettyDescriptor(c).c_str());
+ }
}
}
@@ -438,7 +446,7 @@ void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class
for (size_t i = 0; i != boot_class_path.size(); ++i) {
const DexFile* dex_file = boot_class_path[i];
CHECK(dex_file != NULL);
- AppendToBootClassPath(*dex_file);
+ AppendToBootClassPath(self, *dex_file);
}
// now we can use FindSystemClass
@@ -666,7 +674,7 @@ void ClassLinker::RunRootClinits() {
if (!c->IsArrayClass() && !c->IsPrimitive()) {
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(GetClassRoot(ClassRoot(i))));
- EnsureInitialized(h_class, true, true);
+ EnsureInitialized(self, h_class, true, true);
self->AssertNoPendingException();
}
}
@@ -1880,7 +1888,7 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* ar
while (!local_arg.success) {
size_t class_table_size;
{
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
class_table_size = class_table_.size();
}
mirror::Class* class_type = mirror::Class::GetJavaLangClass();
@@ -2024,7 +2032,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor,
}
CHECK(h_class->IsRetired());
// Get the updated class from class table.
- klass = LookupClass(descriptor, h_class.Get()->GetClassLoader());
+ klass = LookupClass(self, descriptor, h_class.Get()->GetClassLoader());
}
// Wait for the class if it has not already been linked.
@@ -2083,11 +2091,11 @@ mirror::Class* ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlready
ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
// Check if this would be found in the parent boot class loader.
if (pair.second != nullptr) {
- mirror::Class* klass = LookupClass(descriptor, nullptr);
+ mirror::Class* klass = LookupClass(self, descriptor, nullptr);
if (klass != nullptr) {
return EnsureResolved(self, descriptor, klass);
}
- klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+ klass = DefineClass(self, descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
*pair.second);
if (klass != nullptr) {
return klass;
@@ -2139,7 +2147,7 @@ mirror::Class* ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlready
if (dex_class_def != nullptr) {
RegisterDexFile(*dex_file);
mirror::Class* klass =
- DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+ DefineClass(self, descriptor, class_loader, *dex_file, *dex_class_def);
if (klass == nullptr) {
CHECK(self->IsExceptionPending()) << descriptor;
self->ClearException();
@@ -2167,7 +2175,7 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
return FindPrimitiveClass(descriptor[0]);
}
// Find the class in the loaded classes table.
- mirror::Class* klass = LookupClass(descriptor, class_loader.Get());
+ mirror::Class* klass = LookupClass(self, descriptor, class_loader.Get());
if (klass != nullptr) {
return EnsureResolved(self, descriptor, klass);
}
@@ -2178,7 +2186,8 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
// The boot class loader, search the boot class path.
ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
if (pair.second != nullptr) {
- return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second);
+ return DefineClass(self, descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+ *pair.second);
} else {
// The boot class loader is searched ahead of the application class loader, failures are
// expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to
@@ -2190,7 +2199,7 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
} else if (Runtime::Current()->UseCompileTimeClassPath()) {
// First try with the bootstrap class loader.
if (class_loader.Get() != nullptr) {
- klass = LookupClass(descriptor, nullptr);
+ klass = LookupClass(self, descriptor, nullptr);
if (klass != nullptr) {
return EnsureResolved(self, descriptor, klass);
}
@@ -2199,7 +2208,8 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
// a NoClassDefFoundError being allocated.
ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
if (pair.second != nullptr) {
- return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second);
+ return DefineClass(self, descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+ *pair.second);
}
// Next try the compile time class path.
const std::vector<const DexFile*>* class_path;
@@ -2211,7 +2221,12 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
}
pair = FindInClassPath(descriptor, *class_path);
if (pair.second != nullptr) {
- return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
+ return DefineClass(self, descriptor, class_loader, *pair.first, *pair.second);
+ } else {
+ // Use the pre-allocated NCDFE at compile time to avoid wasting time constructing exceptions.
+ mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(ThrowLocation(), pre_allocated);
+ return nullptr;
}
} else {
ScopedObjectAccessUnchecked soa(self);
@@ -2254,11 +2269,10 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
return nullptr;
}
-mirror::Class* ClassLinker::DefineClass(const char* descriptor,
+mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
- Thread* self = Thread::Current();
StackHandleScope<3> hs(self);
auto klass = hs.NewHandle<mirror::Class>(nullptr);
bool should_allocate = false;
@@ -2299,7 +2313,7 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor,
return nullptr;
}
klass->SetDexCache(FindDexCache(dex_file));
- LoadClass(dex_file, dex_class_def, klass, class_loader.Get());
+ LoadClass(self, dex_file, dex_class_def, klass, class_loader.Get());
ObjectLock<mirror::Class> lock(self, klass);
if (self->IsExceptionPending()) {
// An exception occured during load, set status to erroneous while holding klass' lock in case
@@ -2764,7 +2778,7 @@ void ClassLinker::LinkCode(ConstHandle<mirror::ArtMethod> method,
-void ClassLinker::LoadClass(const DexFile& dex_file,
+void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
ConstHandle<mirror::Class> klass,
mirror::ClassLoader* class_loader) {
@@ -2800,22 +2814,21 @@ void ClassLinker::LoadClass(const DexFile& dex_file,
OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
&has_oat_class);
if (has_oat_class) {
- LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
+ LoadClassMembers(self, dex_file, class_data, klass, class_loader, &oat_class);
}
}
if (!has_oat_class) {
- LoadClassMembers(dex_file, class_data, klass, class_loader, nullptr);
+ LoadClassMembers(self, dex_file, class_data, klass, class_loader, nullptr);
}
}
-void ClassLinker::LoadClassMembers(const DexFile& dex_file,
+void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file,
const byte* class_data,
ConstHandle<mirror::Class> klass,
mirror::ClassLoader* class_loader,
const OatFile::OatClass* oat_class) {
// Load fields.
ClassDataItemIterator it(dex_file, class_data);
- Thread* self = Thread::Current();
if (it.NumStaticFields() != 0) {
mirror::ObjectArray<mirror::ArtField>* statics = AllocArtFieldArray(self, it.NumStaticFields());
if (UNLIKELY(statics == NULL)) {
@@ -2834,6 +2847,7 @@ void ClassLinker::LoadClassMembers(const DexFile& dex_file,
klass->SetIFields(fields);
}
for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) {
+ self->AllowThreadSuspension();
StackHandleScope<1> hs(self);
Handle<mirror::ArtField> sfield(hs.NewHandle(AllocArtField(self)));
if (UNLIKELY(sfield.Get() == NULL)) {
@@ -2844,6 +2858,7 @@ void ClassLinker::LoadClassMembers(const DexFile& dex_file,
LoadField(dex_file, it, klass, sfield);
}
for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) {
+ self->AllowThreadSuspension();
StackHandleScope<1> hs(self);
Handle<mirror::ArtField> ifield(hs.NewHandle(AllocArtField(self)));
if (UNLIKELY(ifield.Get() == NULL)) {
@@ -2879,6 +2894,7 @@ void ClassLinker::LoadClassMembers(const DexFile& dex_file,
uint32_t last_dex_method_index = DexFile::kDexNoIndex;
size_t last_class_def_method_index = 0;
for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
+ self->AllowThreadSuspension();
StackHandleScope<1> hs(self);
Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
if (UNLIKELY(method.Get() == NULL)) {
@@ -2899,6 +2915,7 @@ void ClassLinker::LoadClassMembers(const DexFile& dex_file,
class_def_method_index++;
}
for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
+ self->AllowThreadSuspension();
StackHandleScope<1> hs(self);
Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
if (UNLIKELY(method.Get() == NULL)) {
@@ -2987,8 +3004,7 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file
return dst;
}
-void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) {
- Thread* self = Thread::Current();
+void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) {
StackHandleScope<1> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
CHECK(dex_cache.Get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
@@ -3142,7 +3158,7 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto
if (component_type.Get() == nullptr) {
DCHECK(self->IsExceptionPending());
// We need to accept erroneous classes as component types.
- component_type.Assign(LookupClass(descriptor + 1, class_loader.Get()));
+ component_type.Assign(LookupClass(self, descriptor + 1, class_loader.Get()));
if (component_type.Get() == nullptr) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -3172,7 +3188,7 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto
// class to the hash table --- necessary because of possible races with
// other threads.)
if (class_loader.Get() != component_type->GetClassLoader()) {
- mirror::Class* new_class = LookupClass(descriptor, component_type->GetClassLoader());
+ mirror::Class* new_class = LookupClass(self, descriptor, component_type->GetClassLoader());
if (new_class != NULL) {
return new_class;
}
@@ -3391,11 +3407,11 @@ bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader*
return false;
}
-mirror::Class* ClassLinker::LookupClass(const char* descriptor,
+mirror::Class* ClassLinker::LookupClass(Thread* self, const char* descriptor,
const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
{
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
mirror::Class* result = LookupClassFromTableLocked(descriptor, class_loader, hash);
if (result != NULL) {
return result;
@@ -3531,9 +3547,8 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Clas
}
}
-void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) {
+void ClassLinker::VerifyClass(Thread* self, ConstHandle<mirror::Class> klass) {
// TODO: assert that the monitor on the Class is held
- Thread* self = Thread::Current();
ObjectLock<mirror::Class> lock(self, klass);
// Don't attempt to re-verify if already sufficiently verified.
@@ -3576,7 +3591,7 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) {
ObjectLock<mirror::Class> lock(self, super);
if (!super->IsVerified() && !super->IsErroneous()) {
- VerifyClass(super);
+ VerifyClass(self, super);
}
if (!super->IsCompileTimeVerified()) {
std::string error_msg(
@@ -3617,7 +3632,7 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) {
verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
std::string error_msg;
if (!preverified) {
- verifier_failure = verifier::MethodVerifier::VerifyClass(klass.Get(),
+ verifier_failure = verifier::MethodVerifier::VerifyClass(self, klass.Get(),
Runtime::Current()->IsCompiler(),
&error_msg);
}
@@ -3652,7 +3667,7 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) {
klass->SetStatus(mirror::Class::kStatusVerified, self);
// As this is a fake verified status, make sure the methods are _not_ marked preverified
// later.
- klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
+ klass->SetPreverified();
}
}
} else {
@@ -3675,9 +3690,9 @@ void ClassLinker::VerifyClass(ConstHandle<mirror::Class> klass) {
}
void ClassLinker::EnsurePreverifiedMethods(ConstHandle<mirror::Class> klass) {
- if ((klass->GetAccessFlags() & kAccPreverified) == 0) {
+ if (!klass->IsPreverified()) {
klass->SetPreverifiedFlagOnAllMethods();
- klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
+ klass->SetPreverified();
}
}
@@ -4108,12 +4123,8 @@ static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
return true;
}
-bool ClassLinker::IsInitialized() const {
- return init_done_;
-}
-
-bool ClassLinker::InitializeClass(ConstHandle<mirror::Class> klass, bool can_init_statics,
- bool can_init_parents) {
+bool ClassLinker::InitializeClass(Thread* self, ConstHandle<mirror::Class> klass,
+ bool can_init_statics, bool can_init_parents) {
// see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
// Are we already initialized and therefore done?
@@ -4128,7 +4139,7 @@ bool ClassLinker::InitializeClass(ConstHandle<mirror::Class> klass, bool can_ini
return false;
}
- Thread* self = Thread::Current();
+ self->AllowThreadSuspension();
uint64_t t0;
{
ObjectLock<mirror::Class> lock(self, klass);
@@ -4147,7 +4158,7 @@ bool ClassLinker::InitializeClass(ConstHandle<mirror::Class> klass, bool can_ini
CHECK(klass->IsResolved()) << PrettyClass(klass.Get()) << ": state=" << klass->GetStatus();
if (!klass->IsVerified()) {
- VerifyClass(klass);
+ VerifyClass(self, klass);
if (!klass->IsVerified()) {
// We failed to verify, expect either the klass to be erroneous or verification failed at
// compile time.
@@ -4186,6 +4197,7 @@ bool ClassLinker::InitializeClass(ConstHandle<mirror::Class> klass, bool can_ini
klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
+ self->AllowThreadSuspension();
CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.Get());
@@ -4205,7 +4217,7 @@ bool ClassLinker::InitializeClass(ConstHandle<mirror::Class> klass, bool can_ini
CHECK(can_init_parents);
StackHandleScope<1> hs(self);
Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class));
- bool super_initialized = InitializeClass(handle_scope_super, can_init_statics, true);
+ bool super_initialized = InitializeClass(self, handle_scope_super, can_init_statics, true);
if (!super_initialized) {
// The super class was verified ahead of entering initializing, we should only be here if
// the super class became erroneous due to initialization.
@@ -4258,6 +4270,7 @@ bool ClassLinker::InitializeClass(ConstHandle<mirror::Class> klass, bool can_ini
clinit->Invoke(self, NULL, 0, &result, "V");
}
+ self->AllowThreadSuspension();
uint64_t t1 = NanoTime();
bool success = true;
@@ -4374,15 +4387,14 @@ bool ClassLinker::ValidateSuperClassDescriptors(ConstHandle<mirror::Class> klass
return true;
}
-bool ClassLinker::EnsureInitialized(ConstHandle<mirror::Class> c, bool can_init_fields,
- bool can_init_parents) {
+bool ClassLinker::EnsureInitialized(Thread* self, ConstHandle<mirror::Class> c,
+ bool can_init_fields, bool can_init_parents) {
DCHECK(c.Get() != nullptr);
if (c->IsInitialized()) {
EnsurePreverifiedMethods(c);
return true;
}
- const bool success = InitializeClass(c, can_init_fields, can_init_parents);
- Thread* self = Thread::Current();
+ const bool success = InitializeClass(self, c, can_init_fields, can_init_parents);
if (!success) {
if (can_init_fields && can_init_parents) {
CHECK(self->IsExceptionPending()) << PrettyClass(c.Get());
@@ -4442,11 +4454,11 @@ bool ClassLinker::LinkClass(Thread* self, const char* descriptor, ConstHandle<mi
if (!LinkMethods(self, klass, interfaces)) {
return false;
}
- if (!LinkInstanceFields(klass)) {
+ if (!LinkInstanceFields(self, klass)) {
return false;
}
size_t class_size;
- if (!LinkStaticFields(klass, &class_size)) {
+ if (!LinkStaticFields(self, klass, &class_size)) {
return false;
}
CreateReferenceInstanceOffsets(klass);
@@ -4603,6 +4615,7 @@ bool ClassLinker::LinkSuperClass(ConstHandle<mirror::Class> klass) {
// Populate the class vtable and itable. Compute return type indices.
bool ClassLinker::LinkMethods(Thread* self, ConstHandle<mirror::Class> klass,
ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces) {
+ self->AllowThreadSuspension();
if (klass->IsInterface()) {
// No vtable.
size_t count = klass->NumVirtualMethods();
@@ -4780,6 +4793,7 @@ bool ClassLinker::LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
iftable->SetInterface(i, super_interface);
}
}
+ self->AllowThreadSuspension();
// Flatten the interface inheritance hierarchy.
size_t idx = super_ifcount;
for (size_t i = 0; i < num_interfaces; i++) {
@@ -4823,6 +4837,7 @@ bool ClassLinker::LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
}
}
}
+ self->AllowThreadSuspension();
// Shrink iftable in case duplicates were found
if (idx < ifcount) {
iftable.Assign(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax)));
@@ -4840,6 +4855,7 @@ bool ClassLinker::LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
if (klass->IsInterface()) {
return true;
}
+ self->AllowThreadSuspension();
// Allocate imtable
bool imtable_changed = false;
Handle<mirror::ObjectArray<mirror::ArtMethod>> imtable(
@@ -4858,6 +4874,7 @@ bool ClassLinker::LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
miranda_list(hs.NewHandle(AllocArtMethodArray(self, max_miranda_methods)));
size_t miranda_list_size = 0; // The current size of miranda_list.
for (size_t i = 0; i < ifcount; ++i) {
+ self->AllowThreadSuspension();
size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
if (num_methods > 0) {
StackHandleScope<2> hs(self);
@@ -4984,19 +5001,19 @@ bool ClassLinker::LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
CHECK(vtable->Get(i) != NULL);
}
-// klass->DumpClass(std::cerr, Class::kDumpClassFullDetail);
+ self->AllowThreadSuspension();
return true;
}
-bool ClassLinker::LinkInstanceFields(ConstHandle<mirror::Class> klass) {
+bool ClassLinker::LinkInstanceFields(Thread* self, ConstHandle<mirror::Class> klass) {
CHECK(klass.Get() != NULL);
- return LinkFields(klass, false, nullptr);
+ return LinkFields(self, klass, false, nullptr);
}
-bool ClassLinker::LinkStaticFields(ConstHandle<mirror::Class> klass, size_t* class_size) {
+bool ClassLinker::LinkStaticFields(Thread* self, ConstHandle<mirror::Class> klass, size_t* class_size) {
CHECK(klass.Get() != NULL);
- return LinkFields(klass, true, class_size);
+ return LinkFields(self, klass, true, class_size);
}
struct LinkFieldsComparator {
@@ -5026,7 +5043,9 @@ struct LinkFieldsComparator {
}
};
-bool ClassLinker::LinkFields(ConstHandle<mirror::Class> klass, bool is_static, size_t* class_size) {
+bool ClassLinker::LinkFields(Thread* self, ConstHandle<mirror::Class> klass, bool is_static,
+ size_t* class_size) {
+ self->AllowThreadSuspension();
size_t num_fields =
is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
@@ -5057,7 +5076,7 @@ bool ClassLinker::LinkFields(ConstHandle<mirror::Class> klass, bool is_static, s
// we want a relatively stable order so that adding new fields
// minimizes disruption of C++ version such as Class and Method.
std::deque<mirror::ArtField*> grouped_and_sorted_fields;
- const char* old_no_suspend_cause = Thread::Current()->StartAssertNoThreadSuspension(
+ const char* old_no_suspend_cause = self->StartAssertNoThreadSuspension(
"Naked ArtField references in deque");
for (size_t i = 0; i < num_fields; i++) {
mirror::ArtField* f = fields->Get(i);
@@ -5103,8 +5122,7 @@ bool ClassLinker::LinkFields(ConstHandle<mirror::Class> klass, bool is_static, s
fields, &grouped_and_sorted_fields, &gaps);
CHECK(grouped_and_sorted_fields.empty()) << "Missed " << grouped_and_sorted_fields.size() <<
" fields.";
-
- Thread::Current()->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
// We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
if (!is_static && klass->DescriptorEquals("Ljava/lang/ref/Reference;")) {
@@ -5520,10 +5538,12 @@ void ClassLinker::DumpAllClasses(int flags) {
}
void ClassLinker::DumpForSigQuit(std::ostream& os) {
+ Thread* self = Thread::Current();
if (dex_cache_image_class_lookup_required_) {
+ ScopedObjectAccess soa(self);
MoveImageClassesToClassTable();
}
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
os << "Loaded classes: " << class_table_.size() << " allocated classes\n";
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 11ac326c47..b6c62a9bd7 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -92,17 +92,20 @@ class ClassLinker {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Returns true if the class linker is initialized.
- bool IsInitialized() const;
+ bool IsInitialized() const {
+ return init_done_;
+ }
// Define a new a class based on a ClassDef from a DexFile
- mirror::Class* DefineClass(const char* descriptor,
+ mirror::Class* DefineClass(Thread* self, const char* descriptor,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
// by the given 'class_loader'.
- mirror::Class* LookupClass(const char* descriptor, const mirror::ClassLoader* class_loader)
+ mirror::Class* LookupClass(Thread* self, const char* descriptor,
+ const mirror::ClassLoader* class_loader)
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -124,8 +127,7 @@ class ClassLinker {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void DumpForSigQuit(std::ostream& os)
- LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
size_t NumLoadedClasses()
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
@@ -221,7 +223,8 @@ class ClassLinker {
// Returns true on success, false if there's an exception pending.
// can_run_clinit=false allows the compiler to attempt to init a class,
// given the restriction that no <clinit> execution is possible.
- bool EnsureInitialized(ConstHandle<mirror::Class> c, bool can_init_fields, bool can_init_parents)
+ bool EnsureInitialized(Thread* self, ConstHandle<mirror::Class> c, bool can_init_fields,
+ bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Initializes classes that have instances in the image but that have
@@ -323,7 +326,8 @@ class ClassLinker {
size_t length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void VerifyClass(ConstHandle<mirror::Class> klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VerifyClass(Thread* self, ConstHandle<mirror::Class> klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
mirror::Class::Status& oat_file_class_status)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -444,7 +448,7 @@ class ClassLinker {
ConstHandle<mirror::ClassLoader> class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void AppendToBootClassPath(const DexFile& dex_file)
+ void AppendToBootClassPath(Thread* self, const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void AppendToBootClassPath(const DexFile& dex_file, ConstHandle<mirror::DexCache> dex_cache)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -454,15 +458,11 @@ class ClassLinker {
uint32_t SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def);
- void LoadClass(const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def,
- ConstHandle<mirror::Class> klass,
- mirror::ClassLoader* class_loader)
+ void LoadClass(Thread* self, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
+ ConstHandle<mirror::Class> klass, mirror::ClassLoader* class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void LoadClassMembers(const DexFile& dex_file,
- const byte* class_data,
- ConstHandle<mirror::Class> klass,
- mirror::ClassLoader* class_loader,
+ void LoadClassMembers(Thread* self, const DexFile& dex_file, const byte* class_data,
+ ConstHandle<mirror::Class> klass, mirror::ClassLoader* class_loader,
const OatFile::OatClass* oat_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -488,7 +488,7 @@ class ClassLinker {
bool IsDexFileRegisteredLocked(const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(dex_lock_, Locks::mutator_lock_);
- bool InitializeClass(ConstHandle<mirror::Class> klass, bool can_run_clinit,
+ bool InitializeClass(Thread* self, ConstHandle<mirror::Class> klass, bool can_run_clinit,
bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool WaitForInitializeClass(ConstHandle<mirror::Class> klass, Thread* self,
@@ -528,11 +528,12 @@ class ClassLinker {
ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkStaticFields(ConstHandle<mirror::Class> klass, size_t* class_size)
+ bool LinkStaticFields(Thread* self, ConstHandle<mirror::Class> klass, size_t* class_size)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkInstanceFields(ConstHandle<mirror::Class> klass)
+ bool LinkInstanceFields(Thread* self, ConstHandle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkFields(ConstHandle<mirror::Class> klass, bool is_static, size_t* class_size)
+ bool LinkFields(Thread* self, ConstHandle<mirror::Class> klass, bool is_static,
+ size_t* class_size)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void LinkCode(ConstHandle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index ee5fbb71a2..273d4c055a 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -855,7 +855,7 @@ TEST_F(ClassLinkerTest, StaticFields) {
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
Handle<mirror::Class> statics(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
- class_linker_->EnsureInitialized(statics, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), statics, true, true);
// Static final primitives that are initialized by a compile-time constant
// expression resolve to a copy of a constant value from the constant pool.
@@ -1133,7 +1133,7 @@ TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) {
CheckPreverified(security_manager.Get(), false);
- class_linker_->EnsureInitialized(security_manager, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), security_manager, true, true);
CheckPreverified(security_manager.Get(), true);
}
@@ -1148,7 +1148,7 @@ TEST_F(ClassLinkerTest, Preverified_App) {
CheckPreverified(statics.Get(), false);
- class_linker_->EnsureInitialized(statics, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), statics, true, true);
CheckPreverified(statics.Get(), true);
}
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index d1e041cede..50bb0c9a08 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3051,7 +3051,7 @@ static bool IsMethodPossiblyInlined(Thread* self, mirror::ArtMethod* m)
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
Handle<mirror::ArtMethod> method(hs.NewHandle(m));
- verifier::MethodVerifier verifier(dex_cache->GetDexFile(), dex_cache, class_loader,
+ verifier::MethodVerifier verifier(self, dex_cache->GetDexFile(), dex_cache, class_loader,
&m->GetClassDef(), code_item, m->GetDexMethodIndex(), method,
m->GetAccessFlags(), false, true, false);
// Note: we don't need to verify the method.
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index b6810b02b2..b913220358 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -190,7 +190,7 @@ class Instruction {
}
// Reads an instruction out of the stream from the current address plus an offset.
- const Instruction* RelativeAt(int32_t offset) const {
+ const Instruction* RelativeAt(int32_t offset) const WARN_UNUSED {
return At(reinterpret_cast<const uint16_t*>(this) + offset);
}
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 38842cb8c2..4ef7d741f7 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -79,7 +79,7 @@ static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
// has changed and to null-check the return value in case the
// initialization fails.
*slow_path = true;
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_klass, true, true)) {
DCHECK(self->IsExceptionPending());
return nullptr; // Failure
} else {
@@ -107,7 +107,7 @@ static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class*
// has changed and to null-check the return value in case the
// initialization fails.
*slow_path = true;
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
DCHECK(self->IsExceptionPending());
return nullptr; // Failure
}
@@ -324,7 +324,7 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::Ar
} else {
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(fields_class));
- if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) {
+ if (LIKELY(class_linker->EnsureInitialized(self, h_class, true, true))) {
// Otherwise let's ensure the class is initialized before resolving the field.
return resolved_field;
}
@@ -603,7 +603,7 @@ static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
}
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(klass));
- if (!class_linker->EnsureInitialized(h_class, true, true)) {
+ if (!class_linker->EnsureInitialized(self, h_class, true, true)) {
CHECK(self->IsExceptionPending());
return nullptr; // Failure - Indicate to caller to deliver exception
}
@@ -640,18 +640,6 @@ static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
}
}
-static inline void CheckSuspend(Thread* thread) {
- for (;;) {
- if (thread->ReadFlag(kCheckpointRequest)) {
- thread->RunCheckpointFunction();
- } else if (thread->ReadFlag(kSuspendRequest)) {
- thread->FullSuspendCheck();
- } else {
- break;
- }
- }
-}
-
template <typename INT_TYPE, typename FLOAT_TYPE>
static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max());
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 44c89adada..08edecfb00 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -174,8 +174,6 @@ static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
void CheckReferenceResult(mirror::Object* o, Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty,
jobject rcvr_jobj, jobject interface_art_method_jobj,
std::vector<jvalue>& args)
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 64faf76213..b617636d13 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -36,7 +36,8 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m
self->PushShadowFrame(shadow_frame);
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(declaringClass));
- if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true))) {
+ if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true,
+ true))) {
self->PopShadowFrame();
DCHECK(self->IsExceptionPending());
return;
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
index 23e1c3640a..7d5ccc2256 100644
--- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method.h"
-#include "mirror/object-inl.h"
#include "verifier/dex_gc_map.h"
#include "stack.h"
+#include "thread-inl.h"
namespace art {
@@ -71,7 +69,7 @@ class ShadowFrameCopyVisitor : public StackVisitor {
extern "C" void art_portable_test_suspend_from_code(Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CheckSuspend(self);
+ self->CheckSuspend();
if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) {
// Save out the shadow frame to the heap
ShadowFrameCopyVisitor visitor(self);
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 9f75b0fcf0..7f6144bede 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -215,7 +215,7 @@ extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Th
if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) {
// Ensure static method's class is initialized.
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
DCHECK(Thread::Current()->IsExceptionPending());
self->PopManagedStackFragment(fragment);
return 0;
@@ -399,7 +399,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called
// Ensure that the called method's class is initialized.
StackHandleScope<1> hs(self);
Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
- linker->EnsureInitialized(called_class, true, true);
+ linker->EnsureInitialized(self, called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
code = called->GetEntryPointFromPortableCompiledCode();
// TODO: remove this after we solve the link issue.
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 653724989a..87f04bbbf2 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -14,15 +14,8 @@
* limitations under the License.
*/
-#include "dex_file-inl.h"
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/object.h"
#include "mirror/object-inl.h"
-#include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "verify_object-inl.h"
namespace art {
@@ -56,7 +49,7 @@ static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
// In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there
// is a flag raised.
DCHECK(Locks::mutator_lock_->IsSharedHeld(self));
- CheckSuspend(self);
+ self->CheckSuspend();
}
}
diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
index 118cd7fca1..ea75fb6c4e 100644
--- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
@@ -15,17 +15,15 @@
*/
#include "callee_save_frame.h"
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "thread.h"
-#include "thread_list.h"
+#include "thread-inl.h"
namespace art {
-extern "C" void artTestSuspendFromCode(Thread* thread, StackReference<mirror::ArtMethod>* sp)
+extern "C" void artTestSuspendFromCode(Thread* self, StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Called when suspend count check value is 0 and thread->suspend_count_ != 0
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
- CheckSuspend(thread);
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ self->CheckSuspend();
}
} // namespace art
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index dfd2e11fc2..95dd8be6cc 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -496,7 +496,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Threa
// Ensure static method's class is initialized.
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(method);
self->PopManagedStackFragment(fragment);
return 0;
@@ -808,7 +808,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
// Ensure that the called method's class is initialized.
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
- linker->EnsureInitialized(called_class, true, true);
+ linker->EnsureInitialized(soa.Self(), called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
code = called->GetEntryPointFromQuickCompiledCode();
} else if (called_class->IsInitializing()) {
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 99633a380b..6033a5fc5d 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -45,7 +45,7 @@ class ExceptionTest : public CommonRuntimeTest {
my_klass_ = class_linker_->FindClass(soa.Self(), "LExceptionHandle;", class_loader);
ASSERT_TRUE(my_klass_ != NULL);
Handle<mirror::Class> klass(hs.NewHandle(my_klass_));
- class_linker_->EnsureInitialized(klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), klass, true, true);
my_klass_ = klass.Get();
dex_ = my_klass_->GetDexCache()->GetDexFile();
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 9742277b26..822af24ca7 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -460,7 +460,7 @@ class Heap {
bool fail_ok) const;
space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const;
- void DumpForSigQuit(std::ostream& os) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void DumpForSigQuit(std::ostream& os);
// Do a pending heap transition or trim.
void DoPendingTransitionOrTrim() LOCKS_EXCLUDED(heap_trim_request_lock_);
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 47a7f0d62e..7e685e87e0 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -462,7 +462,7 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
- if (UNLIKELY(!class_linker->EnsureInitialized(h_class, true, true))) {
+ if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) {
CHECK(self->IsExceptionPending());
self->PopShadowFrame();
return;
@@ -537,7 +537,7 @@ extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh
StackHandleScope<1> hs(self);
HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(
- h_declaring_class, true, true))) {
+ self, h_declaring_class, true, true))) {
DCHECK(self->IsExceptionPending());
self->PopShadowFrame();
return;
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5724e3519b..2129c1bc64 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -800,7 +800,7 @@ static void UnstartedRuntimeFindClass(Thread* self, ConstHandle<mirror::String>
if (found != nullptr && initialize_class) {
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(found));
- if (!class_linker->EnsureInitialized(h_class, true, true)) {
+ if (!class_linker->EnsureInitialized(self, h_class, true, true)) {
CHECK(self->IsExceptionPending());
return;
}
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 5a1d01e3f7..9358632382 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -192,7 +192,7 @@ static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t str
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(java_lang_string_class));
- if (UNLIKELY(!class_linker->EnsureInitialized(h_class, true, true))) {
+ if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) {
DCHECK(self->IsExceptionPending());
return nullptr;
}
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 755e1ed814..5c8a6c6f16 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -249,9 +249,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
// perform the memory barrier now.
QuasiAtomic::ThreadFenceForConstructor();
}
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
@@ -268,9 +266,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
HANDLE_INSTRUCTION_START(RETURN_VOID_BARRIER) {
QuasiAtomic::ThreadFenceForConstructor();
JValue result;
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
@@ -288,9 +284,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
JValue result;
result.SetJ(0);
result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
@@ -307,9 +301,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
HANDLE_INSTRUCTION_START(RETURN_WIDE) {
JValue result;
result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
@@ -325,9 +317,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
HANDLE_INSTRUCTION_START(RETURN_OBJECT) {
JValue result;
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
const uint8_t vreg_index = inst->VRegA_11x(inst_data);
Object* obj_result = shadow_frame.GetVRegReference(vreg_index);
if (do_assignability_check && obj_result != NULL) {
@@ -632,7 +622,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int8_t offset = inst->VRegA_10t(inst_data);
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -644,7 +634,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegA_20t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -656,7 +646,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int32_t offset = inst->VRegA_30t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -668,7 +658,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -680,7 +670,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -773,7 +763,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -789,7 +779,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -805,7 +795,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -821,7 +811,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -837,7 +827,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -853,7 +843,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -869,7 +859,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -885,7 +875,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -901,7 +891,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -917,7 +907,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -933,7 +923,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -949,7 +939,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
}
@@ -2399,7 +2389,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
exception_pending_label: {
CHECK(self->IsExceptionPending());
if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
+ self->CheckSuspend();
UPDATE_HANDLER_TABLE();
}
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 6054a2531d..c6cef6a648 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -22,9 +22,7 @@ namespace interpreter {
#define HANDLE_PENDING_EXCEPTION() \
do { \
DCHECK(self->IsExceptionPending()); \
- if (UNLIKELY(self->TestAllFlags())) { \
- CheckSuspend(self); \
- } \
+ self->AllowThreadSuspension(); \
uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, \
inst->GetDexPc(insns), \
instrumentation); \
@@ -175,9 +173,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
// perform the memory barrier now.
QuasiAtomic::ThreadFenceForConstructor();
}
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
@@ -191,9 +187,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
case Instruction::RETURN_VOID_BARRIER: {
QuasiAtomic::ThreadFenceForConstructor();
JValue result;
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
@@ -208,9 +202,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
JValue result;
result.SetJ(0);
result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
@@ -224,9 +216,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
case Instruction::RETURN_WIDE: {
JValue result;
result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
@@ -239,9 +229,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
}
case Instruction::RETURN_OBJECT: {
JValue result;
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
const size_t ref_idx = inst->VRegA_11x(inst_data);
Object* obj_result = shadow_frame.GetVRegReference(ref_idx);
if (do_assignability_check && obj_result != NULL) {
@@ -545,9 +533,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
PREAMBLE();
int8_t offset = inst->VRegA_10t(inst_data);
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
break;
@@ -556,9 +542,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
PREAMBLE();
int16_t offset = inst->VRegA_20t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
break;
@@ -567,9 +551,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
PREAMBLE();
int32_t offset = inst->VRegA_30t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
break;
@@ -578,9 +560,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
PREAMBLE();
int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
break;
@@ -589,9 +569,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
PREAMBLE();
int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
break;
@@ -682,9 +660,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) == shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -697,9 +673,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) != shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -712,9 +686,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) < shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -727,9 +699,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >= shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -742,9 +712,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) > shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -757,9 +725,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <= shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
int16_t offset = inst->VRegC_22t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -772,9 +738,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -787,9 +751,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -802,9 +764,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -817,9 +777,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -832,9 +790,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
@@ -847,9 +803,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
int16_t offset = inst->VRegB_21t();
if (IsBackwardBranch(offset)) {
- if (UNLIKELY(self->TestAllFlags())) {
- CheckSuspend(self);
- }
+ self->AllowThreadSuspension();
}
inst = inst->RelativeAt(offset);
} else {
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 36f01dbf4b..bf979c132d 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -108,7 +108,7 @@ static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass)
}
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_klass(hs.NewHandle(klass));
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_klass, true, true)) {
return nullptr;
}
return h_klass.Get();
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index a1097b4ae1..aad678fede 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -266,6 +266,16 @@ class MANAGED Class FINAL : public Object {
return (GetAccessFlags() & kAccSynthetic) != 0;
}
+ // Returns true if the class can avoid access checks.
+ bool IsPreverified() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return (GetAccessFlags() & kAccPreverified) != 0;
+ }
+
+ void SetPreverified() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+ SetAccessFlags(flags | kAccPreverified);
+ }
+
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsTypeOfReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return (GetAccessFlags<kVerifyFlags>() & kAccClassIsReference) != 0;
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 14d6cd950e..ff9dc38e43 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -189,8 +189,8 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
- mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
- *dex_class_def);
+ mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(),
+ class_loader, *dex_file, *dex_class_def);
if (result != nullptr) {
VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
return soa.AddLocalReference<jclass>(result);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index db0a5c55df..e1d9fc769e 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -238,7 +238,7 @@ static void PreloadDexCachesResolveString(Handle<mirror::DexCache> dex_cache, ui
}
// Based on ClassLinker::ResolveType.
-static void PreloadDexCachesResolveType(mirror::DexCache* dex_cache, uint32_t type_idx)
+static void PreloadDexCachesResolveType(Thread* self, mirror::DexCache* dex_cache, uint32_t type_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
if (klass != NULL) {
@@ -250,7 +250,7 @@ static void PreloadDexCachesResolveType(mirror::DexCache* dex_cache, uint32_t ty
if (class_name[1] == '\0') {
klass = linker->FindPrimitiveClass(class_name[0]);
} else {
- klass = linker->LookupClass(class_name, NULL);
+ klass = linker->LookupClass(self, class_name, NULL);
}
if (klass == NULL) {
return;
@@ -427,7 +427,6 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
Runtime* runtime = Runtime::Current();
ClassLinker* linker = runtime->GetClassLinker();
- Thread* self = ThreadForEnv(env);
// We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings
StringTable strings;
@@ -440,7 +439,7 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
for (size_t i = 0; i< boot_class_path.size(); i++) {
const DexFile* dex_file = boot_class_path[i];
CHECK(dex_file != NULL);
- StackHandleScope<1> hs(self);
+ StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file)));
if (kPreloadDexCachesStrings) {
@@ -451,7 +450,7 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
if (kPreloadDexCachesTypes) {
for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
- PreloadDexCachesResolveType(dex_cache.Get(), i);
+ PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), i);
}
}
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 124bdf5475..b11cbdfb92 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -78,7 +78,7 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean
return nullptr;
}
if (initialize) {
- class_linker->EnsureInitialized(c, true, true);
+ class_linker->EnsureInitialized(soa.Self(), c, true, true);
}
return soa.AddLocalReference<jclass>(c.Get());
}
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 761e8009e3..f6a46bde88 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -24,17 +24,18 @@
namespace art {
-static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader, jstring javaName) {
+static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
+ jstring javaName) {
ScopedFastNativeObjectAccess soa(env);
mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
ScopedUtfChars name(env, javaName);
- if (name.c_str() == NULL) {
- return NULL;
+ if (name.c_str() == nullptr) {
+ return nullptr;
}
ClassLinker* cl = Runtime::Current()->GetClassLinker();
std::string descriptor(DotToDescriptor(name.c_str()));
- mirror::Class* c = cl->LookupClass(descriptor.c_str(), loader);
- if (c != NULL && c->IsResolved()) {
+ mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), loader);
+ if (c != nullptr && c->IsResolved()) {
return soa.AddLocalReference<jclass>(c);
}
if (loader != nullptr) {
@@ -47,7 +48,7 @@ static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoa
}
// Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into
// the regular loadClass code.
- return NULL;
+ return nullptr;
}
static jint VMClassLoader_getBootClassPathSize(JNIEnv*, jclass) {
@@ -67,13 +68,15 @@ static jint VMClassLoader_getBootClassPathSize(JNIEnv*, jclass) {
* with '/'); if it's not we'd need to make it absolute as part of forming
* the URL string.
*/
-static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstring javaName, jint index) {
+static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstring javaName,
+ jint index) {
ScopedUtfChars name(env, javaName);
if (name.c_str() == nullptr) {
return nullptr;
}
- const std::vector<const DexFile*>& path = Runtime::Current()->GetClassLinker()->GetBootClassPath();
+ const std::vector<const DexFile*>& path =
+ Runtime::Current()->GetClassLinker()->GetBootClassPath();
if (index < 0 || size_t(index) >= path.size()) {
return nullptr;
}
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 34cb93ae94..0542aeb98a 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -48,7 +48,7 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA
return nullptr;
}
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), c, true, true)) {
DCHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 3903ffcd6a..ad88109a86 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -97,7 +97,8 @@ static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa, jobject j_rcv
StackHandleScope<2> hs(soa.Self());
HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(f));
Handle<mirror::Class> h_klass(hs.NewHandle((*f)->GetDeclaringClass()));
- if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true))) {
+ if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), h_klass, true,
+ true))) {
DCHECK(soa.Self()->IsExceptionPending());
*class_or_rcvr = nullptr;
return false;
diff --git a/runtime/oat.h b/runtime/oat.h
index 6d5fefe2ce..6a32e3e56e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -152,7 +152,7 @@ class PACKED(4) OatHeader {
enum OatClassType {
kOatClassAllCompiled = 0, // OatClass is followed by an OatMethodOffsets for each method.
kOatClassSomeCompiled = 1, // A bitmap of which OatMethodOffsets are present follows the OatClass.
- kOatClassNoneCompiled = 2, // All methods are interpretted so no OatMethodOffsets are necessary.
+ kOatClassNoneCompiled = 2, // All methods are interpreted so no OatMethodOffsets are necessary.
kOatClassMax = 3,
};
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index a6a2475d4b..cde4177d6d 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -119,12 +119,12 @@ static void GetSample(Thread* thread, void* arg) SHARED_LOCKS_REQUIRED(Locks::mu
}
// A closure that is called by the thread checkpoint code.
-class SampleCheckpoint : public Closure {
+class SampleCheckpoint FINAL : public Closure {
public:
explicit SampleCheckpoint(BackgroundMethodSamplingProfiler* const profiler) :
profiler_(profiler) {}
- virtual void Run(Thread* thread) NO_THREAD_SAFETY_ANALYSIS {
+ void Run(Thread* thread) OVERRIDE {
Thread* self = Thread::Current();
if (thread == nullptr) {
LOG(ERROR) << "Checkpoint with nullptr thread";
@@ -192,6 +192,7 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
VLOG(profiler) << "Delaying profile start for " << delay_secs << " secs";
MutexLock mu(self, profiler->wait_lock_);
profiler->period_condition_.TimedWait(self, delay_secs * 1000, 0);
+ // We were either signaled by Stop or timedout, in either case ignore the timed out result.
// Expand the backoff by its coefficient, but don't go beyond the max.
backoff = std::min(backoff * profiler->options_.GetBackoffCoefficient(), kMaxBackoffSecs);
@@ -238,17 +239,13 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
// is done with a timeout so that we can detect problems with the checkpoint
// running code. We should never see this.
const uint32_t kWaitTimeoutMs = 10000;
- const uint32_t kWaitTimeoutUs = kWaitTimeoutMs * 1000;
- uint64_t waitstart_us = MicroTime();
// Wait for all threads to pass the barrier.
- profiler->profiler_barrier_->Increment(self, barrier_count, kWaitTimeoutMs);
- uint64_t waitend_us = MicroTime();
- uint64_t waitdiff_us = waitend_us - waitstart_us;
+ bool timed_out = profiler->profiler_barrier_->Increment(self, barrier_count, kWaitTimeoutMs);
// We should never get a timeout. If we do, it suggests a problem with the checkpoint
// code. Crash the process in this case.
- CHECK_LT(waitdiff_us, kWaitTimeoutUs);
+ CHECK(!timed_out);
// Update the current time.
now_us = MicroTime();
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 1ec488ef51..43d21de765 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -211,7 +211,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
Handle<mirror::ArtMethod> h_method(hs.NewHandle(m));
- verifier::MethodVerifier verifier(h_dex_cache->GetDexFile(), h_dex_cache, h_class_loader,
+ verifier::MethodVerifier verifier(self_, h_dex_cache->GetDexFile(), h_dex_cache, h_class_loader,
&m->GetClassDef(), code_item, m->GetDexMethodIndex(),
h_method, m->GetAccessFlags(), false, true, true);
verifier.Verify();
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 7da450c0a3..9fe296a6b1 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -560,7 +560,7 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM
if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), h_class, true, true)) {
return nullptr;
}
declaring_class = h_class.Get();
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 9d10daaffc..75211e00d7 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -117,7 +117,7 @@ class ReflectionTest : public CommonCompilerTest {
// Ensure class is initialized before allocating object
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(c));
- bool initialized = class_linker_->EnsureInitialized(h_class, true, true);
+ bool initialized = class_linker_->EnsureInitialized(self, h_class, true, true);
CHECK(initialized);
*receiver = c->AllocObject(self);
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 474b72dbd7..bf1e01654c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -199,7 +199,7 @@ Runtime::~Runtime() {
}
struct AbortState {
- void Dump(std::ostream& os) NO_THREAD_SAFETY_ANALYSIS {
+ void Dump(std::ostream& os) {
if (gAborting > 1) {
os << "Runtime aborting --- recursively, so no thread-specific detail!\n";
return;
@@ -229,7 +229,9 @@ struct AbortState {
DumpAllThreads(os, self);
}
- void DumpThread(std::ostream& os, Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // No thread-safety analysis as we do explicitly test for holding the mutator lock.
+ void DumpThread(std::ostream& os, Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+ DCHECK(Locks::mutator_lock_->IsExclusiveHeld(self) || Locks::mutator_lock_->IsSharedHeld(self));
self->Dump(os);
if (self->IsExceptionPending()) {
ThrowLocation throw_location;
@@ -240,7 +242,7 @@ struct AbortState {
}
}
- void DumpAllThreads(std::ostream& os, Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+ void DumpAllThreads(std::ostream& os, Thread* self) {
Runtime* runtime = Runtime::Current();
if (runtime != nullptr) {
ThreadList* thread_list = runtime->GetThreadList();
@@ -254,7 +256,7 @@ struct AbortState {
<< "\n";
}
os << "All threads:\n";
- thread_list->DumpLocked(os);
+ thread_list->Dump(os);
}
}
}
@@ -343,7 +345,7 @@ jobject CreateSystemClassLoader() {
StackHandleScope<2> hs(soa.Self());
Handle<mirror::Class> class_loader_class(
hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader)));
- CHECK(cl->EnsureInitialized(class_loader_class, true, true));
+ CHECK(cl->EnsureInitialized(soa.Self(), class_loader_class, true, true));
mirror::ArtMethod* getSystemClassLoader =
class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
@@ -359,7 +361,7 @@ jobject CreateSystemClassLoader() {
Handle<mirror::Class> thread_class(
hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread)));
- CHECK(cl->EnsureInitialized(thread_class, true, true));
+ CHECK(cl->EnsureInitialized(soa.Self(), thread_class, true, true));
mirror::ArtField* contextClassLoader =
thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;");
@@ -404,7 +406,7 @@ bool Runtime::Start() {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
auto klass(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
- class_linker_->EnsureInitialized(klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), klass, true, true);
}
// InitNativeMethods needs to be after started_ so that the classes
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 9df14538e9..cfb1abc477 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -197,8 +197,7 @@ class Runtime {
// Detaches the current native thread from the runtime.
void DetachCurrentThread() LOCKS_EXCLUDED(Locks::mutator_lock_);
- void DumpForSigQuit(std::ostream& os)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void DumpForSigQuit(std::ostream& os);
void DumpLockHolders(std::ostream& os);
~Runtime();
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 11e06fe885..336340eca9 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -118,17 +118,6 @@ void SignalCatcher::Output(const std::string& s) {
void SignalCatcher::HandleSigQuit() {
Runtime* runtime = Runtime::Current();
- ThreadList* thread_list = runtime->GetThreadList();
-
- // Grab exclusively the mutator lock, set state to Runnable without checking for a pending
- // suspend request as we're going to suspend soon anyway. We set the state to Runnable to avoid
- // giving away the mutator lock.
- thread_list->SuspendAll();
- Thread* self = Thread::Current();
- Locks::mutator_lock_->AssertExclusiveHeld(self);
- const char* old_cause = self->StartAssertNoThreadSuspension("Handling SIGQUIT");
- ThreadState old_state = self->SetStateUnsafe(kRunnable);
-
std::ostringstream os;
os << "\n"
<< "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
@@ -149,14 +138,6 @@ void SignalCatcher::HandleSigQuit() {
}
}
os << "----- end " << getpid() << " -----\n";
- CHECK_EQ(self->SetStateUnsafe(old_state), kRunnable);
- self->EndAssertNoThreadSuspension(old_cause);
- thread_list->ResumeAll();
- // Run the checkpoints after resuming the threads to prevent deadlocks if the checkpoint function
- // acquires the mutator lock.
- if (self->ReadFlag(kCheckpointRequest)) {
- self->RunCheckpointFunction();
- }
Output(os.str());
}
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index bd399e7734..6698634dcf 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -23,6 +23,7 @@
#include "base/casts.h"
#include "base/mutex-inl.h"
+#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/heap.h"
#include "jni_env_ext.h"
@@ -45,6 +46,26 @@ inline Thread* Thread::Current() {
}
}
+inline void Thread::AllowThreadSuspension() {
+ DCHECK_EQ(Thread::Current(), this);
+ if (UNLIKELY(TestAllFlags())) {
+ CheckSuspend();
+ }
+}
+
+inline void Thread::CheckSuspend() {
+ DCHECK_EQ(Thread::Current(), this);
+ for (;;) {
+ if (ReadFlag(kCheckpointRequest)) {
+ RunCheckpointFunction();
+ } else if (ReadFlag(kSuspendRequest)) {
+ FullSuspendCheck();
+ } else {
+ break;
+ }
+ }
+}
+
inline ThreadState Thread::SetState(ThreadState new_state) {
// Cannot use this code to change into Runnable as changing to Runnable should fail if
// old_state_and_flags.suspend_request is true.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 6e3e9c14ea..d4ac02b3ab 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -592,7 +592,7 @@ static void UnsafeLogFatalForSuspendCount(Thread* self, Thread* thread) NO_THREA
}
}
std::ostringstream ss;
- Runtime::Current()->GetThreadList()->DumpLocked(ss);
+ Runtime::Current()->GetThreadList()->Dump(ss);
LOG(FATAL) << ss.str();
}
@@ -1602,7 +1602,8 @@ void Thread::ThrowNewExceptionV(const ThrowLocation& throw_location,
ThrowNewException(throw_location, exception_class_descriptor, msg.c_str());
}
-void Thread::ThrowNewException(const ThrowLocation& throw_location, const char* exception_class_descriptor,
+void Thread::ThrowNewException(const ThrowLocation& throw_location,
+ const char* exception_class_descriptor,
const char* msg) {
// Callers should either clear or call ThrowNewWrappedException.
AssertNoPendingExceptionForNewException(msg);
@@ -1638,7 +1639,8 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
return;
}
- if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class, true, true))) {
+ if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(soa.Self(), exception_class, true,
+ true))) {
DCHECK(IsExceptionPending());
return;
}
diff --git a/runtime/thread.h b/runtime/thread.h
index aca4069ceb..d96b50ba13 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -146,6 +146,12 @@ class Thread {
static Thread* Current();
+ // On a runnable thread, check for pending thread suspension request and handle if pending.
+ void AllowThreadSuspension() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Process pending thread suspension request and handle if pending.
+ void CheckSuspend() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static Thread* FromManagedThread(const ScopedObjectAccessAlreadyRunnable& ts,
mirror::Object* thread_peer)
EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_)
@@ -1029,7 +1035,11 @@ class Thread {
deoptimization_shadow_frame(nullptr), shadow_frame_under_construction(nullptr), name(nullptr),
pthread_self(0), last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr),
thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_objects(0),
- thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr) {
+ thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr),
+ nested_signal_state(nullptr) {
+ for (size_t i = 0; i < kLockLevelCount; ++i) {
+ held_mutexes[i] = nullptr;
+ }
}
// The biased card table, see CardTable for details.
@@ -1162,7 +1172,6 @@ class Thread {
friend class Runtime; // For CreatePeer.
friend class QuickExceptionHandler; // For dumping the stack.
friend class ScopedThreadStateChange;
- friend class SignalCatcher; // For SetStateUnsafe.
friend class StubTest; // For accessing entrypoints.
friend class ThreadList; // For ~Thread and Destroy.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index afb98cab45..3cc2a2892d 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -88,10 +88,7 @@ void ThreadList::DumpNativeStacks(std::ostream& os) {
}
void ThreadList::DumpForSigQuit(std::ostream& os) {
- {
- MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
- DumpLocked(os);
- }
+ Dump(os);
DumpUnattachedThreads(os);
}
@@ -133,12 +130,50 @@ void ThreadList::DumpUnattachedThreads(std::ostream& os) {
closedir(d);
}
-void ThreadList::DumpLocked(std::ostream& os) {
- os << "DALVIK THREADS (" << list_.size() << "):\n";
- for (const auto& thread : list_) {
- thread->Dump(os);
- os << "\n";
+// A closure used by Thread::Dump.
+class DumpCheckpoint FINAL : public Closure {
+ public:
+ explicit DumpCheckpoint(std::ostream* os) : os_(os), barrier_(0) {}
+
+ void Run(Thread* thread) OVERRIDE {
+ // Note thread and self may not be equal if thread was already suspended at the point of the
+ // request.
+ Thread* self = Thread::Current();
+ std::ostringstream local_os;
+ {
+ ScopedObjectAccess soa(self);
+ thread->Dump(local_os);
+ }
+ local_os << "\n";
+ {
+ // Use the logging lock to ensure serialization when writing to the common ostream.
+ MutexLock mu(self, *Locks::logging_lock_);
+ *os_ << local_os.str();
+ }
+ barrier_.Pass(self);
+ }
+
+ void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) {
+ Thread* self = Thread::Current();
+ ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ barrier_.Increment(self, threads_running_checkpoint);
+ }
+
+ private:
+ // The common stream that will accumulate all the dumps.
+ std::ostream* const os_;
+ // The barrier to be passed through and for the requestor to wait upon.
+ Barrier barrier_;
+};
+
+void ThreadList::Dump(std::ostream& os) {
+ {
+ MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+ os << "DALVIK THREADS (" << list_.size() << "):\n";
}
+ DumpCheckpoint checkpoint(&os);
+ size_t threads_running_checkpoint = RunCheckpoint(&checkpoint);
+ checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint);
}
void ThreadList::AssertThreadsAreSuspended(Thread* self, Thread* ignore1, Thread* ignore2) {
@@ -155,12 +190,12 @@ void ThreadList::AssertThreadsAreSuspended(Thread* self, Thread* ignore1, Thread
#if HAVE_TIMED_RWLOCK
// Attempt to rectify locks so that we dump thread list with required locks before exiting.
-static void UnsafeLogFatalForThreadSuspendAllTimeout() NO_THREAD_SAFETY_ANALYSIS __attribute__((noreturn));
+static void UnsafeLogFatalForThreadSuspendAllTimeout() __attribute__((noreturn));
static void UnsafeLogFatalForThreadSuspendAllTimeout() {
Runtime* runtime = Runtime::Current();
std::ostringstream ss;
ss << "Thread suspend timeout\n";
- runtime->GetThreadList()->DumpLocked(ss);
+ runtime->GetThreadList()->Dump(ss);
LOG(FATAL) << ss.str();
exit(0);
}
@@ -266,12 +301,10 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) {
// threads. Returns the number of successful requests.
size_t ThreadList::RunCheckpointOnRunnableThreads(Closure* checkpoint_function) {
Thread* self = Thread::Current();
- if (kIsDebugBuild) {
- Locks::mutator_lock_->AssertNotExclusiveHeld(self);
- Locks::thread_list_lock_->AssertNotHeld(self);
- Locks::thread_suspend_count_lock_->AssertNotHeld(self);
- CHECK_NE(self->GetState(), kRunnable);
- }
+ Locks::mutator_lock_->AssertNotExclusiveHeld(self);
+ Locks::thread_list_lock_->AssertNotHeld(self);
+ Locks::thread_suspend_count_lock_->AssertNotHeld(self);
+ CHECK_NE(self->GetState(), kRunnable);
size_t count = 0;
{
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index bb4f7750f5..9f47f9f9ef 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -39,11 +39,11 @@ class ThreadList {
~ThreadList();
void DumpForSigQuit(std::ostream& os)
- LOCKS_EXCLUDED(Locks::thread_list_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void DumpLocked(std::ostream& os) // For thread suspend timeout dumps.
- EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ LOCKS_EXCLUDED(Locks::thread_list_lock_);
+ // For thread suspend timeout dumps.
+ void Dump(std::ostream& os)
+ LOCKS_EXCLUDED(Locks::thread_list_lock_,
+ Locks::thread_suspend_count_lock_);
pid_t GetLockOwner(); // For SignalCatcher.
// Thread suspension support.
@@ -93,7 +93,8 @@ class ThreadList {
Locks::thread_suspend_count_lock_);
size_t RunCheckpointOnRunnableThreads(Closure* checkpoint_function)
- LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_);
+ LOCKS_EXCLUDED(Locks::thread_list_lock_,
+ Locks::thread_suspend_count_lock_);
// Suspends all threads
void SuspendAllForDebugger()
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 691aec4f2c..8c37489e17 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -110,7 +110,7 @@ TEST_F(TransactionTest, StaticFieldsTest) {
Handle<mirror::Class> h_klass(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStaticFieldsTest;", class_loader)));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->EnsureInitialized(h_klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
ASSERT_TRUE(h_klass->IsInitialized());
// Lookup fields.
@@ -205,7 +205,7 @@ TEST_F(TransactionTest, InstanceFieldsTest) {
Handle<mirror::Class> h_klass(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LInstanceFieldsTest;", class_loader)));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->EnsureInitialized(h_klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
ASSERT_TRUE(h_klass->IsInitialized());
// Allocate an InstanceFieldTest object.
@@ -305,7 +305,7 @@ TEST_F(TransactionTest, StaticArrayFieldsTest) {
Handle<mirror::Class> h_klass(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStaticArrayFieldsTest;", class_loader)));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->EnsureInitialized(h_klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
ASSERT_TRUE(h_klass->IsInitialized());
// Lookup fields.
@@ -419,12 +419,12 @@ TEST_F(TransactionTest, EmptyClass) {
Handle<mirror::Class> h_klass(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LTransaction$EmptyStatic;", class_loader)));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->VerifyClass(h_klass);
+ class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
Transaction transaction;
Runtime::Current()->EnterTransactionMode(&transaction);
- class_linker_->EnsureInitialized(h_klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
Runtime::Current()->ExitTransactionMode();
ASSERT_FALSE(soa.Self()->IsExceptionPending());
}
@@ -440,12 +440,12 @@ TEST_F(TransactionTest, StaticFieldClass) {
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LTransaction$StaticFieldClass;",
class_loader)));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->VerifyClass(h_klass);
+ class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
Transaction transaction;
Runtime::Current()->EnterTransactionMode(&transaction);
- class_linker_->EnsureInitialized(h_klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
Runtime::Current()->ExitTransactionMode();
ASSERT_FALSE(soa.Self()->IsExceptionPending());
}
@@ -464,29 +464,29 @@ TEST_F(TransactionTest, BlacklistedClass) {
hs.NewHandle(class_linker_->FindSystemClass(soa.Self(),
"Ljava/lang/ExceptionInInitializerError;")));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->VerifyClass(h_klass);
+ class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
h_klass.Assign(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/InternalError;"));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->VerifyClass(h_klass);
+ class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
// Load and verify Transaction$NativeSupport used in class initialization.
h_klass.Assign(class_linker_->FindClass(soa.Self(), "LTransaction$NativeSupport;",
class_loader));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->VerifyClass(h_klass);
+ class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
h_klass.Assign(class_linker_->FindClass(soa.Self(), "LTransaction$BlacklistedClass;",
class_loader));
ASSERT_TRUE(h_klass.Get() != nullptr);
- class_linker_->VerifyClass(h_klass);
+ class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
Transaction transaction;
Runtime::Current()->EnterTransactionMode(&transaction);
- class_linker_->EnsureInitialized(h_klass, true, true);
+ class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
Runtime::Current()->ExitTransactionMode();
ASSERT_TRUE(soa.Self()->IsExceptionPending());
}
diff --git a/runtime/utils.cc b/runtime/utils.cc
index d15a09ab24..6135e5d844 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -823,7 +823,8 @@ bool IsValidMemberName(const char* s) {
}
enum ClassNameType { kName, kDescriptor };
-static bool IsValidClassName(const char* s, ClassNameType type, char separator) {
+template<ClassNameType kType, char kSeparator>
+static bool IsValidClassName(const char* s) {
int arrayCount = 0;
while (*s == '[') {
arrayCount++;
@@ -835,7 +836,8 @@ static bool IsValidClassName(const char* s, ClassNameType type, char separator)
return false;
}
- if (arrayCount != 0) {
+ ClassNameType type = kType;
+ if (type != kDescriptor && arrayCount != 0) {
/*
* If we're looking at an array of some sort, then it doesn't
* matter if what is being asked for is a class name; the
@@ -903,7 +905,7 @@ static bool IsValidClassName(const char* s, ClassNameType type, char separator)
return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0');
case '/':
case '.':
- if (c != separator) {
+ if (c != kSeparator) {
// The wrong separator character.
return false;
}
@@ -925,15 +927,15 @@ static bool IsValidClassName(const char* s, ClassNameType type, char separator)
}
bool IsValidBinaryClassName(const char* s) {
- return IsValidClassName(s, kName, '.');
+ return IsValidClassName<kName, '.'>(s);
}
bool IsValidJniClassName(const char* s) {
- return IsValidClassName(s, kName, '/');
+ return IsValidClassName<kName, '/'>(s);
}
bool IsValidDescriptor(const char* s) {
- return IsValidClassName(s, kDescriptor, '/');
+ return IsValidClassName<kDescriptor, '/'>(s);
}
void Split(const std::string& s, char separator, std::vector<std::string>& result) {
diff --git a/runtime/verifier/instruction_flags.cc b/runtime/verifier/instruction_flags.cc
index f76c226e90..ca3c68796d 100644
--- a/runtime/verifier/instruction_flags.cc
+++ b/runtime/verifier/instruction_flags.cc
@@ -22,13 +22,14 @@ namespace art {
namespace verifier {
std::string InstructionFlags::ToString() const {
- char encoding[7];
+ char encoding[8];
if (!IsOpcode()) {
- strncpy(encoding, "XXXXXX", sizeof(encoding));
+ strncpy(encoding, "XXXXXXX", sizeof(encoding));
} else {
- strncpy(encoding, "------", sizeof(encoding));
+ strncpy(encoding, "-------", sizeof(encoding));
if (IsVisited()) encoding[kVisited] = 'V';
if (IsChanged()) encoding[kChanged] = 'C';
+ if (IsOpcode()) encoding[kOpcode] = 'O';
if (IsInTry()) encoding[kInTry] = 'T';
if (IsBranchTarget()) encoding[kBranchTarget] = 'B';
if (IsCompileTimeInfoPoint()) encoding[kCompileTimeInfoPoint] = 'G';
diff --git a/runtime/verifier/instruction_flags.h b/runtime/verifier/instruction_flags.h
index f8abca05b8..36a6e554dd 100644
--- a/runtime/verifier/instruction_flags.h
+++ b/runtime/verifier/instruction_flags.h
@@ -20,24 +20,23 @@
#include <stdint.h>
#include <string>
-#include "base/logging.h"
+#include "base/macros.h"
namespace art {
namespace verifier {
-class InstructionFlags {
+class InstructionFlags FINAL {
public:
- InstructionFlags() : length_(0), flags_(0) {}
+ InstructionFlags() : flags_(0) {}
- void SetLengthInCodeUnits(size_t length) {
- DCHECK_LT(length, 65536u);
- length_ = length;
+ void SetIsOpcode() {
+ flags_ |= 1 << kOpcode;
}
- size_t GetLengthInCodeUnits() {
- return length_;
+ void ClearIsOpcode() {
+ flags_ &= ~(1 << kOpcode);
}
bool IsOpcode() const {
- return length_ != 0;
+ return (flags_ & (1 << kOpcode)) != 0;
}
void SetInTry() {
@@ -117,21 +116,22 @@ class InstructionFlags {
// Register type information flowing into the instruction changed and so the instruction must be
// reprocessed.
kChanged = 1,
+ // The item at this location is an opcode.
+ kOpcode = 2,
// Instruction is contained within a try region.
- kInTry = 2,
+ kInTry = 3,
// Instruction is the target of a branch (ie the start of a basic block).
- kBranchTarget = 3,
+ kBranchTarget = 4,
// Location of interest to the compiler for GC maps and verifier based method sharpening.
- kCompileTimeInfoPoint = 4,
+ kCompileTimeInfoPoint = 5,
// A return instruction.
- kReturn = 5,
+ kReturn = 6,
};
-
- // Size of instruction in code units.
- uint16_t length_;
uint8_t flags_;
};
+COMPILE_ASSERT(sizeof(InstructionFlags) == sizeof(uint8_t), err);
+
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9cde8daf11..f90da159a1 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -38,6 +38,7 @@
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "reg_type-inl.h"
#include "register_line-inl.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
@@ -87,7 +88,8 @@ PcToRegisterLineTable::~PcToRegisterLineTable() {
}
}
-MethodVerifier::FailureKind MethodVerifier::VerifyClass(mirror::Class* klass,
+MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
+ mirror::Class* klass,
bool allow_soft_failures,
std::string* error) {
if (klass->IsVerified()) {
@@ -99,13 +101,13 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(mirror::Class* klass,
const DexFile::ClassDef* class_def = klass->GetClassDef();
mirror::Class* super = klass->GetSuperClass();
std::string temp;
- if (super == NULL && strcmp("Ljava/lang/Object;", klass->GetDescriptor(&temp)) != 0) {
+ if (super == nullptr && strcmp("Ljava/lang/Object;", klass->GetDescriptor(&temp)) != 0) {
early_failure = true;
failure_message = " that has no super class";
- } else if (super != NULL && super->IsFinal()) {
+ } else if (super != nullptr && super->IsFinal()) {
early_failure = true;
failure_message = " that attempts to sub-class final class " + PrettyDescriptor(super);
- } else if (class_def == NULL) {
+ } else if (class_def == nullptr) {
early_failure = true;
failure_message = " that isn't present in dex file " + dex_file.GetLocation();
}
@@ -117,13 +119,14 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(mirror::Class* klass,
}
return kHardFailure;
}
- StackHandleScope<2> hs(Thread::Current());
+ StackHandleScope<2> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
- return VerifyClass(&dex_file, dex_cache, class_loader, class_def, allow_soft_failures, error);
+ return VerifyClass(self, &dex_file, dex_cache, class_loader, class_def, allow_soft_failures, error);
}
-MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
+MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
+ const DexFile* dex_file,
ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
@@ -131,7 +134,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
std::string* error) {
DCHECK(class_def != nullptr);
const byte* class_data = dex_file->GetClassData(*class_def);
- if (class_data == NULL) {
+ if (class_data == nullptr) {
// empty class, probably a marker interface
return kNoFailure;
}
@@ -139,12 +142,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
while (it.HasNextStaticField() || it.HasNextInstanceField()) {
it.Next();
}
- Thread* self = Thread::Current();
size_t error_count = 0;
bool hard_fail = false;
ClassLinker* linker = Runtime::Current()->GetClassLinker();
int64_t previous_direct_method_idx = -1;
while (it.HasNextDirectMethod()) {
+ self->AllowThreadSuspension();
uint32_t method_idx = it.GetMemberIndex();
if (method_idx == previous_direct_method_idx) {
// smali can create dex files with two encoded_methods sharing the same method_idx
@@ -157,14 +160,15 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
mirror::ArtMethod* method =
linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader,
NullHandle<mirror::ArtMethod>(), type);
- if (method == NULL) {
+ if (method == nullptr) {
DCHECK(self->IsExceptionPending());
// We couldn't resolve the method, but continue regardless.
self->ClearException();
}
StackHandleScope<1> hs(self);
Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
- MethodVerifier::FailureKind result = VerifyMethod(method_idx,
+ MethodVerifier::FailureKind result = VerifyMethod(self,
+ method_idx,
dex_file,
dex_cache,
class_loader,
@@ -191,6 +195,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
}
int64_t previous_virtual_method_idx = -1;
while (it.HasNextVirtualMethod()) {
+ self->AllowThreadSuspension();
uint32_t method_idx = it.GetMemberIndex();
if (method_idx == previous_virtual_method_idx) {
// smali can create dex files with two encoded_methods sharing the same method_idx
@@ -203,14 +208,15 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
mirror::ArtMethod* method =
linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader,
NullHandle<mirror::ArtMethod>(), type);
- if (method == NULL) {
+ if (method == nullptr) {
DCHECK(self->IsExceptionPending());
// We couldn't resolve the method, but continue regardless.
self->ClearException();
}
StackHandleScope<1> hs(self);
Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
- MethodVerifier::FailureKind result = VerifyMethod(method_idx,
+ MethodVerifier::FailureKind result = VerifyMethod(self,
+ method_idx,
dex_file,
dex_cache,
class_loader,
@@ -242,7 +248,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
}
}
-MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx,
+MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t method_idx,
const DexFile* dex_file,
ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
@@ -255,7 +261,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx,
MethodVerifier::FailureKind result = kNoFailure;
uint64_t start_ns = kTimeVerifyMethod ? NanoTime() : 0;
- MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def, code_item,
+ MethodVerifier verifier(self, dex_file, dex_cache, class_loader, class_def, code_item,
method_idx, method, method_access_flags, true, allow_soft_failures,
need_precise_constants);
if (verifier.Verify()) {
@@ -291,7 +297,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx,
return result;
}
-void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx,
+void MethodVerifier::VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t dex_method_idx,
const DexFile* dex_file,
ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
@@ -299,7 +305,7 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i
const DexFile::CodeItem* code_item,
ConstHandle<mirror::ArtMethod> method,
uint32_t method_access_flags) {
- MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def, code_item,
+ MethodVerifier verifier(self, dex_file, dex_cache, class_loader, class_def, code_item,
dex_method_idx, method, method_access_flags, true, true, true);
verifier.Verify();
verifier.DumpFailures(os);
@@ -307,14 +313,16 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i
verifier.Dump(os);
}
-MethodVerifier::MethodVerifier(const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
+MethodVerifier::MethodVerifier(Thread* self,
+ const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item, uint32_t dex_method_idx,
ConstHandle<mirror::ArtMethod> method, uint32_t method_access_flags,
bool can_load_classes, bool allow_soft_failures,
bool need_precise_constants)
- : reg_types_(can_load_classes),
+ : self_(self),
+ reg_types_(can_load_classes),
work_insn_idx_(-1),
dex_method_idx_(dex_method_idx),
mirror_method_(method),
@@ -325,7 +333,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, ConstHandle<mirror::DexC
class_loader_(class_loader),
class_def_(class_def),
code_item_(code_item),
- declaring_class_(NULL),
+ declaring_class_(nullptr),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(nullptr),
have_pending_hard_failure_(false),
@@ -348,11 +356,12 @@ MethodVerifier::~MethodVerifier() {
void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc,
std::vector<uint32_t>* monitor_enter_dex_pcs) {
- StackHandleScope<3> hs(Thread::Current());
+ Thread* self = Thread::Current();
+ StackHandleScope<3> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
Handle<mirror::ArtMethod> method(hs.NewHandle(m));
- MethodVerifier verifier(m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
+ MethodVerifier verifier(self, m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
m->GetCodeItem(), m->GetDexMethodIndex(), method, m->GetAccessFlags(),
false, true, false);
verifier.interesting_dex_pc_ = dex_pc;
@@ -361,8 +370,8 @@ void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc,
}
void MethodVerifier::FindLocksAtDexPc() {
- CHECK(monitor_enter_dex_pcs_ != NULL);
- CHECK(code_item_ != NULL); // This only makes sense for methods with code.
+ CHECK(monitor_enter_dex_pcs_ != nullptr);
+ CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -373,18 +382,19 @@ void MethodVerifier::FindLocksAtDexPc() {
mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m,
uint32_t dex_pc) {
- StackHandleScope<3> hs(Thread::Current());
+ Thread* self = Thread::Current();
+ StackHandleScope<3> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
Handle<mirror::ArtMethod> method(hs.NewHandle(m));
- MethodVerifier verifier(m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
+ MethodVerifier verifier(self, m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
m->GetCodeItem(), m->GetDexMethodIndex(), method, m->GetAccessFlags(),
true, true, false);
return verifier.FindAccessedFieldAtDexPc(dex_pc);
}
mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
- CHECK(code_item_ != NULL); // This only makes sense for methods with code.
+ CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -395,7 +405,7 @@ mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
return nullptr;
}
RegisterLine* register_line = reg_table_.GetLine(dex_pc);
- if (register_line == NULL) {
+ if (register_line == nullptr) {
return nullptr;
}
const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
@@ -404,18 +414,19 @@ mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m,
uint32_t dex_pc) {
- StackHandleScope<3> hs(Thread::Current());
+ Thread* self = Thread::Current();
+ StackHandleScope<3> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
Handle<mirror::ArtMethod> method(hs.NewHandle(m));
- MethodVerifier verifier(m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
+ MethodVerifier verifier(self, m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
m->GetCodeItem(), m->GetDexMethodIndex(), method, m->GetAccessFlags(),
true, true, false);
return verifier.FindInvokedMethodAtDexPc(dex_pc);
}
mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
- CHECK(code_item_ != NULL); // This only makes sense for methods with code.
+ CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -423,11 +434,11 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
// got what we wanted.
bool success = Verify();
if (!success) {
- return NULL;
+ return nullptr;
}
RegisterLine* register_line = reg_table_.GetLine(dex_pc);
- if (register_line == NULL) {
- return NULL;
+ if (register_line == nullptr) {
+ return nullptr;
}
const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
@@ -436,7 +447,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
bool MethodVerifier::Verify() {
// If there aren't any instructions, make sure that's expected, then exit successfully.
- if (code_item_ == NULL) {
+ if (code_item_ == nullptr) {
if ((method_access_flags_ & (kAccNative | kAccAbstract)) == 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "zero-length code in concrete non-native method";
return false;
@@ -569,9 +580,9 @@ bool MethodVerifier::ComputeWidthsAndCountOps() {
break;
}
size_t inst_size = inst->SizeInCodeUnits();
- insn_flags_[dex_pc].SetLengthInCodeUnits(inst_size);
+ insn_flags_[dex_pc].SetIsOpcode();
dex_pc += inst_size;
- inst = inst->Next();
+ inst = inst->RelativeAt(inst_size);
}
if (dex_pc != insns_size) {
@@ -607,9 +618,13 @@ bool MethodVerifier::ScanTryCatchBlocks() {
<< "'try' block starts inside an instruction (" << start << ")";
return false;
}
- for (uint32_t dex_pc = start; dex_pc < end;
- dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits()) {
+ uint32_t dex_pc = start;
+ const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ while (dex_pc < end) {
insn_flags_[dex_pc].SetInTry();
+ size_t insn_size = inst->SizeInCodeUnits();
+ dex_pc += insn_size;
+ inst = inst->RelativeAt(insn_size);
}
}
// Iterate over each of the handlers to verify target addresses.
@@ -632,9 +647,9 @@ bool MethodVerifier::ScanTryCatchBlocks() {
mirror::Class* exception_type = linker->ResolveType(*dex_file_,
iterator.GetHandlerTypeIndex(),
dex_cache_, class_loader_);
- if (exception_type == NULL) {
- DCHECK(Thread::Current()->IsExceptionPending());
- Thread::Current()->ClearException();
+ if (exception_type == nullptr) {
+ DCHECK(self_->IsExceptionPending());
+ self_->ClearException();
}
}
}
@@ -766,7 +781,7 @@ bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_of
return result;
}
-bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
+inline bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
if (idx >= code_item_->registers_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register index out of range (" << idx << " >= "
<< code_item_->registers_size_ << ")";
@@ -775,7 +790,7 @@ bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
return true;
}
-bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
+inline bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
if (idx + 1 >= code_item_->registers_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register index out of range (" << idx
<< "+1 >= " << code_item_->registers_size_ << ")";
@@ -784,7 +799,7 @@ bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
return true;
}
-bool MethodVerifier::CheckFieldIndex(uint32_t idx) {
+inline bool MethodVerifier::CheckFieldIndex(uint32_t idx) {
if (idx >= dex_file_->GetHeader().field_ids_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad field index " << idx << " (max "
<< dex_file_->GetHeader().field_ids_size_ << ")";
@@ -793,7 +808,7 @@ bool MethodVerifier::CheckFieldIndex(uint32_t idx) {
return true;
}
-bool MethodVerifier::CheckMethodIndex(uint32_t idx) {
+inline bool MethodVerifier::CheckMethodIndex(uint32_t idx) {
if (idx >= dex_file_->GetHeader().method_ids_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad method index " << idx << " (max "
<< dex_file_->GetHeader().method_ids_size_ << ")";
@@ -802,7 +817,7 @@ bool MethodVerifier::CheckMethodIndex(uint32_t idx) {
return true;
}
-bool MethodVerifier::CheckNewInstance(uint32_t idx) {
+inline bool MethodVerifier::CheckNewInstance(uint32_t idx) {
if (idx >= dex_file_->GetHeader().type_ids_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
@@ -817,7 +832,7 @@ bool MethodVerifier::CheckNewInstance(uint32_t idx) {
return true;
}
-bool MethodVerifier::CheckStringIndex(uint32_t idx) {
+inline bool MethodVerifier::CheckStringIndex(uint32_t idx) {
if (idx >= dex_file_->GetHeader().string_ids_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad string index " << idx << " (max "
<< dex_file_->GetHeader().string_ids_size_ << ")";
@@ -826,7 +841,7 @@ bool MethodVerifier::CheckStringIndex(uint32_t idx) {
return true;
}
-bool MethodVerifier::CheckTypeIndex(uint32_t idx) {
+inline bool MethodVerifier::CheckTypeIndex(uint32_t idx) {
if (idx >= dex_file_->GetHeader().type_ids_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
@@ -1129,7 +1144,7 @@ extern "C" void MethodVerifierGdbDump(MethodVerifier* v)
}
void MethodVerifier::Dump(std::ostream& os) {
- if (code_item_ == NULL) {
+ if (code_item_ == nullptr) {
os << "Native method\n";
return;
}
@@ -1144,10 +1159,10 @@ void MethodVerifier::Dump(std::ostream& os) {
std::ostream indent_os(&indent_filter);
const Instruction* inst = Instruction::At(code_item_->insns_);
for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
- dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits()) {
+ dex_pc += inst->SizeInCodeUnits()) {
RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
- if (reg_line != NULL) {
- indent_os << reg_line->Dump() << "\n";
+ if (reg_line != nullptr) {
+ indent_os << reg_line->Dump(this) << "\n";
}
indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].ToString() << " ";
const bool kDumpHexOfInstruction = false;
@@ -1189,10 +1204,10 @@ bool MethodVerifier::SetTypesFromSignature() {
// called.
const RegType& declaring_class = GetDeclaringClass();
if (IsConstructor() && !declaring_class.IsJavaLangObject()) {
- reg_line->SetRegisterType(arg_start + cur_arg,
+ reg_line->SetRegisterType(this, arg_start + cur_arg,
reg_types_.UninitializedThisArgument(declaring_class));
} else {
- reg_line->SetRegisterType(arg_start + cur_arg, declaring_class);
+ reg_line->SetRegisterType(this, arg_start + cur_arg, declaring_class);
}
cur_arg++;
}
@@ -1203,7 +1218,7 @@ bool MethodVerifier::SetTypesFromSignature() {
for (; iterator.HasNext(); iterator.Next()) {
const char* descriptor = iterator.GetDescriptor();
- if (descriptor == NULL) {
+ if (descriptor == nullptr) {
LOG(FATAL) << "Null descriptor";
}
if (cur_arg >= expected_args) {
@@ -1224,26 +1239,26 @@ bool MethodVerifier::SetTypesFromSignature() {
DCHECK(HasFailures());
return false;
}
- reg_line->SetRegisterType(arg_start + cur_arg, reg_type);
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_type);
}
break;
case 'Z':
- reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Boolean());
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_types_.Boolean());
break;
case 'C':
- reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Char());
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_types_.Char());
break;
case 'B':
- reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Byte());
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_types_.Byte());
break;
case 'I':
- reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Integer());
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_types_.Integer());
break;
case 'S':
- reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Short());
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_types_.Short());
break;
case 'F':
- reg_line->SetRegisterType(arg_start + cur_arg, reg_types_.Float());
+ reg_line->SetRegisterType(this, arg_start + cur_arg, reg_types_.Float());
break;
case 'J':
case 'D': {
@@ -1253,9 +1268,16 @@ bool MethodVerifier::SetTypesFromSignature() {
return false;
}
- const RegType& lo_half = descriptor[0] == 'J' ? reg_types_.LongLo() : reg_types_.DoubleLo();
- const RegType& hi_half = descriptor[0] == 'J' ? reg_types_.LongHi() : reg_types_.DoubleHi();
- reg_line->SetRegisterTypeWide(arg_start + cur_arg, lo_half, hi_half);
+ const RegType* lo_half;
+ const RegType* hi_half;
+ if (descriptor[0] == 'J') {
+ lo_half = &reg_types_.LongLo();
+ hi_half = &reg_types_.LongHi();
+ } else {
+ lo_half = &reg_types_.DoubleLo();
+ hi_half = &reg_types_.DoubleHi();
+ }
+ reg_line->SetRegisterTypeWide(this, arg_start + cur_arg, *lo_half, *hi_half);
cur_arg++;
break;
}
@@ -1317,6 +1339,7 @@ bool MethodVerifier::CodeFlowVerifyMethod() {
/* Continue until no instructions are marked "changed". */
while (true) {
+ self_->AllowThreadSuspension();
// Find the first marked one. Use "start_guess" as a way to find one quickly.
uint32_t insn_idx = start_guess;
for (; insn_idx < insns_size; insn_idx++) {
@@ -1348,14 +1371,14 @@ bool MethodVerifier::CodeFlowVerifyMethod() {
* a full table) and make sure it actually matches.
*/
RegisterLine* register_line = reg_table_.GetLine(insn_idx);
- if (register_line != NULL) {
+ if (register_line != nullptr) {
if (work_line_->CompareLine(register_line) != 0) {
Dump(std::cout);
std::cout << info_messages_.str();
LOG(FATAL) << "work_line diverged in " << PrettyMethod(dex_method_idx_, *dex_file_)
<< "@" << reinterpret_cast<void*>(work_insn_idx_) << "\n"
- << " work_line=" << *work_line_ << "\n"
- << " expected=" << *register_line;
+ << " work_line=" << work_line_->Dump(this) << "\n"
+ << " expected=" << register_line->Dump(this);
}
}
}
@@ -1381,7 +1404,8 @@ bool MethodVerifier::CodeFlowVerifyMethod() {
*/
int dead_start = -1;
uint32_t insn_idx = 0;
- for (; insn_idx < insns_size; insn_idx += insn_flags_[insn_idx].GetLengthInCodeUnits()) {
+ for (; insn_idx < insns_size;
+ insn_idx += Instruction::At(code_item_->insns_ + insn_idx)->SizeInCodeUnits()) {
/*
* Switch-statement data doesn't get "visited" by scanner. It
* may or may not be preceded by a padding NOP (for alignment).
@@ -1423,7 +1447,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
// We want the state _before_ the instruction, for the case where the dex pc we're
// interested in is itself a monitor-enter instruction (which is a likely place
// for a thread to be suspended).
- if (monitor_enter_dex_pcs_ != NULL && work_insn_idx_ == interesting_dex_pc_) {
+ if (monitor_enter_dex_pcs_ != nullptr && work_insn_idx_ == interesting_dex_pc_) {
monitor_enter_dex_pcs_->clear(); // The new work line is more accurate than the previous one.
for (size_t i = 0; i < work_line_->GetMonitorEnterCount(); ++i) {
monitor_enter_dex_pcs_->push_back(work_line_->GetMonitorEnterDexPc(i));
@@ -1457,7 +1481,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
if (gDebugVerify) {
// Generate processing back trace to debug verifier
LogVerifyInfo() << "Processing " << inst->DumpString(dex_file_) << "\n"
- << *work_line_.get() << "\n";
+ << work_line_->Dump(this) << "\n";
}
/*
@@ -1493,31 +1517,31 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
break;
case Instruction::MOVE:
- work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategory1nr);
+ work_line_->CopyRegister1(this, inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategory1nr);
break;
case Instruction::MOVE_FROM16:
- work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategory1nr);
+ work_line_->CopyRegister1(this, inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategory1nr);
break;
case Instruction::MOVE_16:
- work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategory1nr);
+ work_line_->CopyRegister1(this, inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategory1nr);
break;
case Instruction::MOVE_WIDE:
- work_line_->CopyRegister2(inst->VRegA_12x(), inst->VRegB_12x());
+ work_line_->CopyRegister2(this, inst->VRegA_12x(), inst->VRegB_12x());
break;
case Instruction::MOVE_WIDE_FROM16:
- work_line_->CopyRegister2(inst->VRegA_22x(), inst->VRegB_22x());
+ work_line_->CopyRegister2(this, inst->VRegA_22x(), inst->VRegB_22x());
break;
case Instruction::MOVE_WIDE_16:
- work_line_->CopyRegister2(inst->VRegA_32x(), inst->VRegB_32x());
+ work_line_->CopyRegister2(this, inst->VRegA_32x(), inst->VRegB_32x());
break;
case Instruction::MOVE_OBJECT:
- work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategoryRef);
+ work_line_->CopyRegister1(this, inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategoryRef);
break;
case Instruction::MOVE_OBJECT_FROM16:
- work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategoryRef);
+ work_line_->CopyRegister1(this, inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategoryRef);
break;
case Instruction::MOVE_OBJECT_16:
- work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategoryRef);
+ work_line_->CopyRegister1(this, inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategoryRef);
break;
/*
@@ -1532,13 +1556,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* easier to read in some cases.)
*/
case Instruction::MOVE_RESULT:
- work_line_->CopyResultRegister1(inst->VRegA_11x(), false);
+ work_line_->CopyResultRegister1(this, inst->VRegA_11x(), false);
break;
case Instruction::MOVE_RESULT_WIDE:
- work_line_->CopyResultRegister2(inst->VRegA_11x());
+ work_line_->CopyResultRegister2(this, inst->VRegA_11x());
break;
case Instruction::MOVE_RESULT_OBJECT:
- work_line_->CopyResultRegister1(inst->VRegA_11x(), true);
+ work_line_->CopyResultRegister1(this, inst->VRegA_11x(), true);
break;
case Instruction::MOVE_EXCEPTION: {
@@ -1547,18 +1571,18 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* that as part of extracting the exception type from the catch block list.
*/
const RegType& res_type = GetCaughtExceptionType();
- work_line_->SetRegisterType(inst->VRegA_11x(), res_type);
+ work_line_->SetRegisterType(this, inst->VRegA_11x(), res_type);
break;
}
case Instruction::RETURN_VOID:
- if (!IsConstructor() || work_line_->CheckConstructorReturn()) {
+ if (!IsConstructor() || work_line_->CheckConstructorReturn(this)) {
if (!GetMethodReturnType().IsConflict()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void not expected";
}
}
break;
case Instruction::RETURN:
- if (!IsConstructor() || work_line_->CheckConstructorReturn()) {
+ if (!IsConstructor() || work_line_->CheckConstructorReturn(this)) {
/* check the method signature */
const RegType& return_type = GetMethodReturnType();
if (!return_type.IsCategory1Types()) {
@@ -1568,14 +1592,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
// Compilers may generate synthetic functions that write byte values into boolean fields.
// Also, it may use integer values for boolean, byte, short, and character return types.
const uint32_t vregA = inst->VRegA_11x();
- const RegType& src_type = work_line_->GetRegisterType(vregA);
+ const RegType& src_type = work_line_->GetRegisterType(this, vregA);
bool use_src = ((return_type.IsBoolean() && src_type.IsByte()) ||
((return_type.IsBoolean() || return_type.IsByte() ||
return_type.IsShort() || return_type.IsChar()) &&
src_type.IsInteger()));
/* check the register contents */
bool success =
- work_line_->VerifyRegisterType(vregA, use_src ? src_type : return_type);
+ work_line_->VerifyRegisterType(this, vregA, use_src ? src_type : return_type);
if (!success) {
AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", vregA));
}
@@ -1583,7 +1607,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
break;
case Instruction::RETURN_WIDE:
- if (!IsConstructor() || work_line_->CheckConstructorReturn()) {
+ if (!IsConstructor() || work_line_->CheckConstructorReturn(this)) {
/* check the method signature */
const RegType& return_type = GetMethodReturnType();
if (!return_type.IsCategory2Types()) {
@@ -1591,7 +1615,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
} else {
/* check the register contents */
const uint32_t vregA = inst->VRegA_11x();
- bool success = work_line_->VerifyRegisterType(vregA, return_type);
+ bool success = work_line_->VerifyRegisterType(this, vregA, return_type);
if (!success) {
AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", vregA));
}
@@ -1599,7 +1623,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
break;
case Instruction::RETURN_OBJECT:
- if (!IsConstructor() || work_line_->CheckConstructorReturn()) {
+ if (!IsConstructor() || work_line_->CheckConstructorReturn(this)) {
const RegType& return_type = GetMethodReturnType();
if (!return_type.IsReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object not expected";
@@ -1608,7 +1632,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
DCHECK(!return_type.IsZero());
DCHECK(!return_type.IsUninitializedReference());
const uint32_t vregA = inst->VRegA_11x();
- const RegType& reg_type = work_line_->GetRegisterType(vregA);
+ const RegType& reg_type = work_line_->GetRegisterType(this, vregA);
// Disallow returning uninitialized values and verify that the reference in vAA is an
// instance of the "return_type"
if (reg_type.IsUninitializedTypes()) {
@@ -1630,25 +1654,25 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
/* could be boolean, int, float, or a null reference */
case Instruction::CONST_4: {
int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
- work_line_->SetRegisterType(inst->VRegA_11n(),
+ work_line_->SetRegisterType(this, inst->VRegA_11n(),
DetermineCat1Constant(val, need_precise_constants_));
break;
}
case Instruction::CONST_16: {
int16_t val = static_cast<int16_t>(inst->VRegB_21s());
- work_line_->SetRegisterType(inst->VRegA_21s(),
+ work_line_->SetRegisterType(this, inst->VRegA_21s(),
DetermineCat1Constant(val, need_precise_constants_));
break;
}
case Instruction::CONST: {
int32_t val = inst->VRegB_31i();
- work_line_->SetRegisterType(inst->VRegA_31i(),
+ work_line_->SetRegisterType(this, inst->VRegA_31i(),
DetermineCat1Constant(val, need_precise_constants_));
break;
}
case Instruction::CONST_HIGH16: {
int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
- work_line_->SetRegisterType(inst->VRegA_21h(),
+ work_line_->SetRegisterType(this, inst->VRegA_21h(),
DetermineCat1Constant(val, need_precise_constants_));
break;
}
@@ -1657,48 +1681,48 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
int64_t val = static_cast<int16_t>(inst->VRegB_21s());
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(inst->VRegA_21s(), lo, hi);
+ work_line_->SetRegisterTypeWide(this, inst->VRegA_21s(), lo, hi);
break;
}
case Instruction::CONST_WIDE_32: {
int64_t val = static_cast<int32_t>(inst->VRegB_31i());
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(inst->VRegA_31i(), lo, hi);
+ work_line_->SetRegisterTypeWide(this, inst->VRegA_31i(), lo, hi);
break;
}
case Instruction::CONST_WIDE: {
int64_t val = inst->VRegB_51l();
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(inst->VRegA_51l(), lo, hi);
+ work_line_->SetRegisterTypeWide(this, inst->VRegA_51l(), lo, hi);
break;
}
case Instruction::CONST_WIDE_HIGH16: {
int64_t val = static_cast<uint64_t>(inst->VRegB_21h()) << 48;
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(inst->VRegA_21h(), lo, hi);
+ work_line_->SetRegisterTypeWide(this, inst->VRegA_21h(), lo, hi);
break;
}
case Instruction::CONST_STRING:
- work_line_->SetRegisterType(inst->VRegA_21c(), reg_types_.JavaLangString());
+ work_line_->SetRegisterType(this, inst->VRegA_21c(), reg_types_.JavaLangString());
break;
case Instruction::CONST_STRING_JUMBO:
- work_line_->SetRegisterType(inst->VRegA_31c(), reg_types_.JavaLangString());
+ work_line_->SetRegisterType(this, inst->VRegA_31c(), reg_types_.JavaLangString());
break;
case Instruction::CONST_CLASS: {
// Get type from instruction if unresolved then we need an access check
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
// Register holds class, ie its type is class, on error it will hold Conflict.
- work_line_->SetRegisterType(inst->VRegA_21c(),
+ work_line_->SetRegisterType(this, inst->VRegA_21c(),
res_type.IsConflict() ? res_type
- : reg_types_.JavaLangClass(true));
+ : reg_types_.JavaLangClass());
break;
}
case Instruction::MONITOR_ENTER:
- work_line_->PushMonitor(inst->VRegA_11x(), work_insn_idx_);
+ work_line_->PushMonitor(this, inst->VRegA_11x(), work_insn_idx_);
break;
case Instruction::MONITOR_EXIT:
/*
@@ -1722,7 +1746,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* "live" so we still need to check it.
*/
opcode_flags &= ~Instruction::kThrow;
- work_line_->PopMonitor(inst->VRegA_11x());
+ work_line_->PopMonitor(this, inst->VRegA_11x());
break;
case Instruction::CHECK_CAST:
@@ -1749,13 +1773,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
DCHECK_NE(failures_.size(), 0U);
if (!is_checkcast) {
- work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
+ work_line_->SetRegisterType(this, inst->VRegA_22c(), reg_types_.Boolean());
}
break; // bad class
}
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
uint32_t orig_type_reg = (is_checkcast) ? inst->VRegA_21c() : inst->VRegB_22c();
- const RegType& orig_type = work_line_->GetRegisterType(orig_type_reg);
+ const RegType& orig_type = work_line_->GetRegisterType(this, orig_type_reg);
if (!res_type.IsNonZeroReferenceTypes()) {
if (is_checkcast) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
@@ -1770,20 +1794,20 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
} else {
if (is_checkcast) {
- work_line_->SetRegisterType(inst->VRegA_21c(), res_type);
+ work_line_->SetRegisterType(this, inst->VRegA_21c(), res_type);
} else {
- work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
+ work_line_->SetRegisterType(this, inst->VRegA_22c(), reg_types_.Boolean());
}
}
break;
}
case Instruction::ARRAY_LENGTH: {
- const RegType& res_type = work_line_->GetRegisterType(inst->VRegB_12x());
+ const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegB_12x());
if (res_type.IsReferenceTypes()) {
if (!res_type.IsArrayTypes() && !res_type.IsZero()) { // ie not an array or null
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
} else {
- work_line_->SetRegisterType(inst->VRegA_12x(), reg_types_.Integer());
+ work_line_->SetRegisterType(this, inst->VRegA_12x(), reg_types_.Integer());
}
} else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
@@ -1806,9 +1830,9 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
const RegType& uninit_type = reg_types_.Uninitialized(res_type, work_insn_idx_);
// Any registers holding previous allocations from this address that have not yet been
// initialized must be marked invalid.
- work_line_->MarkUninitRefsAsInvalid(uninit_type);
+ work_line_->MarkUninitRefsAsInvalid(this, uninit_type);
// add the new uninitialized reference to the register state
- work_line_->SetRegisterType(inst->VRegA_21c(), uninit_type);
+ work_line_->SetRegisterType(this, inst->VRegA_21c(), uninit_type);
break;
}
case Instruction::NEW_ARRAY:
@@ -1824,39 +1848,39 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
break;
case Instruction::CMPL_FLOAT:
case Instruction::CMPG_FLOAT:
- if (!work_line_->VerifyRegisterType(inst->VRegB_23x(), reg_types_.Float())) {
+ if (!work_line_->VerifyRegisterType(this, inst->VRegB_23x(), reg_types_.Float())) {
break;
}
- if (!work_line_->VerifyRegisterType(inst->VRegC_23x(), reg_types_.Float())) {
+ if (!work_line_->VerifyRegisterType(this, inst->VRegC_23x(), reg_types_.Float())) {
break;
}
- work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
+ work_line_->SetRegisterType(this, inst->VRegA_23x(), reg_types_.Integer());
break;
case Instruction::CMPL_DOUBLE:
case Instruction::CMPG_DOUBLE:
- if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.DoubleLo(),
+ if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegB_23x(), reg_types_.DoubleLo(),
reg_types_.DoubleHi())) {
break;
}
- if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.DoubleLo(),
+ if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegC_23x(), reg_types_.DoubleLo(),
reg_types_.DoubleHi())) {
break;
}
- work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
+ work_line_->SetRegisterType(this, inst->VRegA_23x(), reg_types_.Integer());
break;
case Instruction::CMP_LONG:
- if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.LongLo(),
+ if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegB_23x(), reg_types_.LongLo(),
reg_types_.LongHi())) {
break;
}
- if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.LongLo(),
+ if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegC_23x(), reg_types_.LongLo(),
reg_types_.LongHi())) {
break;
}
- work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
+ work_line_->SetRegisterType(this, inst->VRegA_23x(), reg_types_.Integer());
break;
case Instruction::THROW: {
- const RegType& res_type = work_line_->GetRegisterType(inst->VRegA_11x());
+ const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegA_11x());
if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
Fail(res_type.IsUnresolvedTypes() ? VERIFY_ERROR_NO_CLASS : VERIFY_ERROR_BAD_CLASS_SOFT)
<< "thrown class " << res_type << " not instanceof Throwable";
@@ -1872,12 +1896,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::PACKED_SWITCH:
case Instruction::SPARSE_SWITCH:
/* verify that vAA is an integer, or can be converted to one */
- work_line_->VerifyRegisterType(inst->VRegA_31t(), reg_types_.Integer());
+ work_line_->VerifyRegisterType(this, inst->VRegA_31t(), reg_types_.Integer());
break;
case Instruction::FILL_ARRAY_DATA: {
/* Similar to the verification done for APUT */
- const RegType& array_type = work_line_->GetRegisterType(inst->VRegA_31t());
+ const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegA_31t());
/* array_type can be null if the reg type is Zero */
if (!array_type.IsZero()) {
if (!array_type.IsArrayTypes()) {
@@ -1911,8 +1935,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::IF_EQ:
case Instruction::IF_NE: {
- const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
- const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
+ const RegType& reg_type1 = work_line_->GetRegisterType(this, inst->VRegA_22t());
+ const RegType& reg_type2 = work_line_->GetRegisterType(this, inst->VRegB_22t());
bool mismatch = false;
if (reg_type1.IsZero()) { // zero then integral or reference expected
mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
@@ -1931,8 +1955,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::IF_GE:
case Instruction::IF_GT:
case Instruction::IF_LE: {
- const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
- const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
+ const RegType& reg_type1 = work_line_->GetRegisterType(this, inst->VRegA_22t());
+ const RegType& reg_type2 = work_line_->GetRegisterType(this, inst->VRegB_22t());
if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to 'if' (" << reg_type1 << ","
<< reg_type2 << ") must be integral";
@@ -1941,7 +1965,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::IF_EQZ:
case Instruction::IF_NEZ: {
- const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
+ const RegType& reg_type = work_line_->GetRegisterType(this, inst->VRegA_21t());
if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
<< " unexpected as arg to if-eqz/if-nez";
@@ -1987,7 +2011,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
// type is assignable to the original then allow optimization. This check is performed to
// ensure that subsequent merges don't lose type information - such as becoming an
// interface from a class that would lose information relevant to field checks.
- const RegType& orig_type = work_line_->GetRegisterType(instance_of_inst->VRegB_22c());
+ const RegType& orig_type = work_line_->GetRegisterType(this, instance_of_inst->VRegB_22c());
const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
if (!orig_type.Equals(cast_type) &&
@@ -2003,7 +2027,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
branch_line.reset(update_line);
}
update_line->CopyFromLine(work_line_.get());
- update_line->SetRegisterType(instance_of_inst->VRegB_22c(), cast_type);
+ update_line->SetRegisterType(this, instance_of_inst->VRegB_22c(), cast_type);
if (!insn_flags_[instance_of_idx].IsBranchTarget() && 0 != instance_of_idx) {
// See if instance-of was preceded by a move-object operation, common due to the small
// register encoding space of instance-of, and propagate type information to the source
@@ -2017,17 +2041,17 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
switch (move_inst->Opcode()) {
case Instruction::MOVE_OBJECT:
if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) {
- update_line->SetRegisterType(move_inst->VRegB_12x(), cast_type);
+ update_line->SetRegisterType(this, move_inst->VRegB_12x(), cast_type);
}
break;
case Instruction::MOVE_OBJECT_FROM16:
if (move_inst->VRegA_22x() == instance_of_inst->VRegB_22c()) {
- update_line->SetRegisterType(move_inst->VRegB_22x(), cast_type);
+ update_line->SetRegisterType(this, move_inst->VRegB_22x(), cast_type);
}
break;
case Instruction::MOVE_OBJECT_16:
if (move_inst->VRegA_32x() == instance_of_inst->VRegB_22c()) {
- update_line->SetRegisterType(move_inst->VRegB_32x(), cast_type);
+ update_line->SetRegisterType(this, move_inst->VRegB_32x(), cast_type);
}
break;
default:
@@ -2043,7 +2067,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::IF_GEZ:
case Instruction::IF_GTZ:
case Instruction::IF_LEZ: {
- const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
+ const RegType& reg_type = work_line_->GetRegisterType(this, inst->VRegA_21t());
if (!reg_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
<< " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez";
@@ -2194,8 +2218,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
is_super);
const RegType* return_type = nullptr;
if (called_method != nullptr) {
- Thread* self = Thread::Current();
- StackHandleScope<1> hs(self);
+ StackHandleScope<1> hs(self_);
Handle<mirror::ArtMethod> h_called_method(hs.NewHandle(called_method));
MethodHelper mh(h_called_method);
mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
@@ -2204,8 +2227,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
return_type_class,
return_type_class->CannotBeAssignedFromOtherTypes());
} else {
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ DCHECK(!can_load_classes_ || self_->IsExceptionPending());
+ self_->ClearException();
}
}
if (return_type == nullptr) {
@@ -2216,7 +2239,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
return_type = &reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
}
if (!return_type->IsLowHalf()) {
- work_line_->SetResultRegisterType(*return_type);
+ work_line_->SetResultRegisterType(this, *return_type);
} else {
work_line_->SetResultRegisterTypeWide(*return_type, return_type->HighHalf(&reg_types_));
}
@@ -2231,7 +2254,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
const char* return_type_descriptor;
bool is_constructor;
const RegType* return_type = nullptr;
- if (called_method == NULL) {
+ if (called_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
is_constructor = strcmp("<init>", dex_file_->StringDataByIdx(method_id.name_idx_)) == 0;
@@ -2240,8 +2263,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
} else {
is_constructor = called_method->IsConstructor();
return_type_descriptor = called_method->GetReturnTypeDescriptor();
- Thread* self = Thread::Current();
- StackHandleScope<1> hs(self);
+ StackHandleScope<1> hs(self_);
Handle<mirror::ArtMethod> h_called_method(hs.NewHandle(called_method));
MethodHelper mh(h_called_method);
mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
@@ -2250,8 +2272,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
return_type_class,
return_type_class->CannotBeAssignedFromOtherTypes());
} else {
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ DCHECK(!can_load_classes_ || self_->IsExceptionPending());
+ self_->ClearException();
}
}
if (is_constructor) {
@@ -2262,7 +2284,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* allowing the latter only if the "this" argument is the same as the "this" argument to
* this method (which implies that we're in a constructor ourselves).
*/
- const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
+ const RegType& this_type = work_line_->GetInvocationThis(this, inst, is_range);
if (this_type.IsConflict()) // failure.
break;
@@ -2292,14 +2314,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* Replace the uninitialized reference with an initialized one. We need to do this for all
* registers that have the same object instance in them, not just the "this" register.
*/
- work_line_->MarkRefsAsInitialized(this_type);
+ work_line_->MarkRefsAsInitialized(this, this_type);
}
if (return_type == nullptr) {
return_type = &reg_types_.FromDescriptor(GetClassLoader(), return_type_descriptor,
false);
}
if (!return_type->IsLowHalf()) {
- work_line_->SetResultRegisterType(*return_type);
+ work_line_->SetResultRegisterType(this, *return_type);
} else {
work_line_->SetResultRegisterTypeWide(*return_type, return_type->HighHalf(&reg_types_));
}
@@ -2314,7 +2336,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
is_range,
false);
const char* descriptor;
- if (called_method == NULL) {
+ if (called_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -2324,7 +2346,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
const RegType& return_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
if (!return_type.IsLowHalf()) {
- work_line_->SetResultRegisterType(return_type);
+ work_line_->SetResultRegisterType(this, return_type);
} else {
work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
}
@@ -2338,7 +2360,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
METHOD_INTERFACE,
is_range,
false);
- if (abs_method != NULL) {
+ if (abs_method != nullptr) {
mirror::Class* called_interface = abs_method->GetDeclaringClass();
if (!called_interface->IsInterface() && !called_interface->IsObjectClass()) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected interface class in invoke-interface '"
@@ -2349,7 +2371,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
/* Get the type of the "this" arg, which should either be a sub-interface of called
* interface or Object (see comments in RegType::JoinClass).
*/
- const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
+ const RegType& this_type = work_line_->GetInvocationThis(this, inst, is_range);
if (this_type.IsZero()) {
/* null pointer always passes (and always fails at runtime) */
} else {
@@ -2371,7 +2393,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* the type information is in the abstract method, so we're good.
*/
const char* descriptor;
- if (abs_method == NULL) {
+ if (abs_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -2381,7 +2403,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
const RegType& return_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
if (!return_type.IsLowHalf()) {
- work_line_->SetResultRegisterType(return_type);
+ work_line_->SetResultRegisterType(this, return_type);
} else {
work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
}
@@ -2390,74 +2412,74 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::NEG_INT:
case Instruction::NOT_INT:
- work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Integer(), reg_types_.Integer());
break;
case Instruction::NEG_LONG:
case Instruction::NOT_LONG:
- work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::NEG_FLOAT:
- work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Float());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Float(), reg_types_.Float());
break;
case Instruction::NEG_DOUBLE:
- work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::INT_TO_LONG:
- work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpToWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Integer());
break;
case Instruction::INT_TO_FLOAT:
- work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Float(), reg_types_.Integer());
break;
case Instruction::INT_TO_DOUBLE:
- work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpToWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.Integer());
break;
case Instruction::LONG_TO_INT:
- work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
+ work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Integer(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::LONG_TO_FLOAT:
- work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
+ work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Float(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::LONG_TO_DOUBLE:
- work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::FLOAT_TO_INT:
- work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Float());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Integer(), reg_types_.Float());
break;
case Instruction::FLOAT_TO_LONG:
- work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpToWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Float());
break;
case Instruction::FLOAT_TO_DOUBLE:
- work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpToWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.Float());
break;
case Instruction::DOUBLE_TO_INT:
- work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
+ work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Integer(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::DOUBLE_TO_LONG:
- work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::DOUBLE_TO_FLOAT:
- work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
+ work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Float(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::INT_TO_BYTE:
- work_line_->CheckUnaryOp(inst, reg_types_.Byte(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Byte(), reg_types_.Integer());
break;
case Instruction::INT_TO_CHAR:
- work_line_->CheckUnaryOp(inst, reg_types_.Char(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Char(), reg_types_.Integer());
break;
case Instruction::INT_TO_SHORT:
- work_line_->CheckUnaryOp(inst, reg_types_.Short(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(this, inst, reg_types_.Short(), reg_types_.Integer());
break;
case Instruction::ADD_INT:
@@ -2468,13 +2490,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHL_INT:
case Instruction::SHR_INT:
case Instruction::USHR_INT:
- work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
+ work_line_->CheckBinaryOp(this, inst, reg_types_.Integer(), reg_types_.Integer(),
reg_types_.Integer(), false);
break;
case Instruction::AND_INT:
case Instruction::OR_INT:
case Instruction::XOR_INT:
- work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
+ work_line_->CheckBinaryOp(this, inst, reg_types_.Integer(), reg_types_.Integer(),
reg_types_.Integer(), true);
break;
case Instruction::ADD_LONG:
@@ -2485,7 +2507,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::AND_LONG:
case Instruction::OR_LONG:
case Instruction::XOR_LONG:
- work_line_->CheckBinaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOpWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
@@ -2493,7 +2515,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHR_LONG:
case Instruction::USHR_LONG:
/* shift distance is Int, making these different from other binary operations */
- work_line_->CheckBinaryOpWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOpWideShift(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Integer());
break;
case Instruction::ADD_FLOAT:
@@ -2501,18 +2523,15 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::MUL_FLOAT:
case Instruction::DIV_FLOAT:
case Instruction::REM_FLOAT:
- work_line_->CheckBinaryOp(inst,
- reg_types_.Float(),
- reg_types_.Float(),
- reg_types_.Float(),
- false);
+ work_line_->CheckBinaryOp(this, inst, reg_types_.Float(), reg_types_.Float(),
+ reg_types_.Float(), false);
break;
case Instruction::ADD_DOUBLE:
case Instruction::SUB_DOUBLE:
case Instruction::MUL_DOUBLE:
case Instruction::DIV_DOUBLE:
case Instruction::REM_DOUBLE:
- work_line_->CheckBinaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckBinaryOpWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
@@ -2523,27 +2542,18 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHL_INT_2ADDR:
case Instruction::SHR_INT_2ADDR:
case Instruction::USHR_INT_2ADDR:
- work_line_->CheckBinaryOp2addr(inst,
- reg_types_.Integer(),
- reg_types_.Integer(),
- reg_types_.Integer(),
- false);
+ work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Integer(), reg_types_.Integer(),
+ reg_types_.Integer(), false);
break;
case Instruction::AND_INT_2ADDR:
case Instruction::OR_INT_2ADDR:
case Instruction::XOR_INT_2ADDR:
- work_line_->CheckBinaryOp2addr(inst,
- reg_types_.Integer(),
- reg_types_.Integer(),
- reg_types_.Integer(),
- true);
+ work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Integer(), reg_types_.Integer(),
+ reg_types_.Integer(), true);
break;
case Instruction::DIV_INT_2ADDR:
- work_line_->CheckBinaryOp2addr(inst,
- reg_types_.Integer(),
- reg_types_.Integer(),
- reg_types_.Integer(),
- false);
+ work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Integer(), reg_types_.Integer(),
+ reg_types_.Integer(), false);
break;
case Instruction::ADD_LONG_2ADDR:
case Instruction::SUB_LONG_2ADDR:
@@ -2553,14 +2563,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::AND_LONG_2ADDR:
case Instruction::OR_LONG_2ADDR:
case Instruction::XOR_LONG_2ADDR:
- work_line_->CheckBinaryOp2addrWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOp2addrWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::SHL_LONG_2ADDR:
case Instruction::SHR_LONG_2ADDR:
case Instruction::USHR_LONG_2ADDR:
- work_line_->CheckBinaryOp2addrWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOp2addrWideShift(this, inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Integer());
break;
case Instruction::ADD_FLOAT_2ADDR:
@@ -2568,18 +2578,15 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::MUL_FLOAT_2ADDR:
case Instruction::DIV_FLOAT_2ADDR:
case Instruction::REM_FLOAT_2ADDR:
- work_line_->CheckBinaryOp2addr(inst,
- reg_types_.Float(),
- reg_types_.Float(),
- reg_types_.Float(),
- false);
+ work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Float(), reg_types_.Float(),
+ reg_types_.Float(), false);
break;
case Instruction::ADD_DOUBLE_2ADDR:
case Instruction::SUB_DOUBLE_2ADDR:
case Instruction::MUL_DOUBLE_2ADDR:
case Instruction::DIV_DOUBLE_2ADDR:
case Instruction::REM_DOUBLE_2ADDR:
- work_line_->CheckBinaryOp2addrWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckBinaryOp2addrWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
@@ -2588,12 +2595,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::MUL_INT_LIT16:
case Instruction::DIV_INT_LIT16:
case Instruction::REM_INT_LIT16:
- work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, true);
+ work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), false,
+ true);
break;
case Instruction::AND_INT_LIT16:
case Instruction::OR_INT_LIT16:
case Instruction::XOR_INT_LIT16:
- work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, true);
+ work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), true,
+ true);
break;
case Instruction::ADD_INT_LIT8:
case Instruction::RSUB_INT_LIT8:
@@ -2603,12 +2612,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHL_INT_LIT8:
case Instruction::SHR_INT_LIT8:
case Instruction::USHR_INT_LIT8:
- work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, false);
+ work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), false,
+ false);
break;
case Instruction::AND_INT_LIT8:
case Instruction::OR_INT_LIT8:
case Instruction::XOR_INT_LIT8:
- work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, false);
+ work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), true,
+ false);
break;
// Special instructions.
@@ -2654,11 +2665,11 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
mirror::ArtMethod* called_method = VerifyInvokeVirtualQuickArgs(inst, is_range);
- if (called_method != NULL) {
+ if (called_method != nullptr) {
const char* descriptor = called_method->GetReturnTypeDescriptor();
const RegType& return_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
if (!return_type.IsLowHalf()) {
- work_line_->SetResultRegisterType(return_type);
+ work_line_->SetResultRegisterType(this, return_type);
} else {
work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
}
@@ -2720,7 +2731,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* not expensive and it makes our debugging output cleaner.)
*/
if (!just_set_result) {
- work_line_->SetResultTypeToUnknown();
+ work_line_->SetResultTypeToUnknown(this);
}
@@ -2749,7 +2760,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
return false;
}
/* update branch target, set "changed" if appropriate */
- if (NULL != branch_line.get()) {
+ if (nullptr != branch_line.get()) {
if (!UpdateRegisters(work_insn_idx_ + branch_target, branch_line.get(), false)) {
return false;
}
@@ -2825,9 +2836,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
} else {
// Clear exception.
- Thread* self = Thread::Current();
- DCHECK(self->IsExceptionPending());
- self->ClearException();
+ DCHECK(self_->IsExceptionPending());
+ self_->ClearException();
}
}
/*
@@ -2864,7 +2874,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* and this change should not be used in those cases.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
+ DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+ uint32_t next_insn_idx = work_insn_idx_ + inst->SizeInCodeUnits();
if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
return false;
@@ -2874,7 +2885,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
return false;
}
- if (NULL != fallthrough_line.get()) {
+ if (nullptr != fallthrough_line.get()) {
// Make workline consistent with fallthrough computed from peephole optimization.
work_line_->CopyFromLine(fallthrough_line.get());
}
@@ -2883,17 +2894,17 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx);
Instruction::Code opcode = ret_inst->Opcode();
if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) {
- work_line_->MarkAllRegistersAsConflicts();
+ work_line_->MarkAllRegistersAsConflicts(this);
} else {
if (opcode == Instruction::RETURN_WIDE) {
- work_line_->MarkAllRegistersAsConflictsExceptWide(ret_inst->VRegA_11x());
+ work_line_->MarkAllRegistersAsConflictsExceptWide(this, ret_inst->VRegA_11x());
} else {
- work_line_->MarkAllRegistersAsConflictsExcept(ret_inst->VRegA_11x());
+ work_line_->MarkAllRegistersAsConflictsExcept(this, ret_inst->VRegA_11x());
}
}
}
RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
- if (next_line != NULL) {
+ if (next_line != nullptr) {
// Merge registers into what we have for the next instruction, and set the "changed" flag if
// needed. If the merge changes the state of the registers then the work line will be
// updated.
@@ -2911,7 +2922,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
/* If we're returning from the method, make sure monitor stack is empty. */
if ((opcode_flags & Instruction::kReturn) != 0) {
- if (!work_line_->VerifyMonitorStackEmpty()) {
+ if (!work_line_->VerifyMonitorStackEmpty(this)) {
return false;
}
}
@@ -2923,7 +2934,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* alone and let the caller sort it out.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- *start_guess = work_insn_idx_ + insn_flags_[work_insn_idx_].GetLengthInCodeUnits();
+ DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+ *start_guess = work_insn_idx_ + inst->SizeInCodeUnits();
} else if ((opcode_flags & Instruction::kBranch) != 0) {
/* we're still okay if branch_target is zero */
*start_guess = work_insn_idx_ + branch_target;
@@ -2939,7 +2951,7 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
const char* descriptor = dex_file_->StringByTypeIdx(class_idx);
const RegType& referrer = GetDeclaringClass();
mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
- const RegType& result = klass != NULL ?
+ const RegType& result = klass != nullptr ?
reg_types_.FromClass(descriptor, klass, klass->CannotBeAssignedFromOtherTypes()) :
reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
if (result.IsConflict()) {
@@ -2947,7 +2959,7 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
<< "' in " << referrer;
return result;
}
- if (klass == NULL && !result.IsUnresolvedTypes()) {
+ if (klass == nullptr && !result.IsUnresolvedTypes()) {
dex_cache_->SetResolvedType(class_idx, result.GetClass());
}
// Check if access is allowed. Unresolved types use xxxWithAccessCheck to
@@ -2962,7 +2974,7 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
}
const RegType& MethodVerifier::GetCaughtExceptionType() {
- const RegType* common_super = NULL;
+ const RegType* common_super = nullptr;
if (code_item_->tries_size_ != 0) {
const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
@@ -2997,7 +3009,7 @@ const RegType& MethodVerifier::GetCaughtExceptionType() {
handlers_ptr = iterator.EndDataPointer();
}
}
- if (common_super == NULL) {
+ if (common_super == nullptr) {
/* no catch blocks, or no catches with classes we can find */
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "unable to find exception handler";
return reg_types_.Conflict();
@@ -3013,15 +3025,15 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth
std::string append(" in attempt to access method ");
append += dex_file_->GetMethodName(method_id);
AppendToLastFailMessage(append);
- return NULL;
+ return nullptr;
}
if (klass_type.IsUnresolvedTypes()) {
- return NULL; // Can't resolve Class so no more to do here
+ return nullptr; // Can't resolve Class so no more to do here
}
mirror::Class* klass = klass_type.GetClass();
const RegType& referrer = GetDeclaringClass();
mirror::ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx);
- if (res_method == NULL) {
+ if (res_method == nullptr) {
const char* name = dex_file_->GetMethodName(method_id);
const Signature signature = dex_file_->GetMethodSignature(method_id);
@@ -3032,7 +3044,7 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth
} else {
res_method = klass->FindVirtualMethod(name, signature);
}
- if (res_method != NULL) {
+ if (res_method != nullptr) {
dex_cache_->SetResolvedMethod(dex_method_idx, res_method);
} else {
// If a virtual or interface method wasn't found with the expected type, look in
@@ -3041,11 +3053,11 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth
if (method_type == METHOD_INTERFACE || method_type == METHOD_VIRTUAL) {
res_method = klass->FindDirectMethod(name, signature);
}
- if (res_method == NULL) {
+ if (res_method == nullptr) {
Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
<< PrettyDescriptor(klass) << "." << name
<< " " << signature;
- return NULL;
+ return nullptr;
}
}
}
@@ -3054,13 +3066,13 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth
if (res_method->IsConstructor() && method_type != METHOD_DIRECT) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "rejecting non-direct call to constructor "
<< PrettyMethod(res_method);
- return NULL;
+ return nullptr;
}
// Disallow any calls to class initializers.
if (res_method->IsClassInitializer()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "rejecting call to class initializer "
<< PrettyMethod(res_method);
- return NULL;
+ return nullptr;
}
// Check if access is allowed.
if (!referrer.CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
@@ -3072,17 +3084,17 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth
if (res_method->IsPrivate() && method_type == METHOD_VIRTUAL) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke-super/virtual can't be used on private method "
<< PrettyMethod(res_method);
- return NULL;
+ return nullptr;
}
// Check that interface methods match interface classes.
if (klass->IsInterface() && method_type != METHOD_INTERFACE) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "non-interface method " << PrettyMethod(res_method)
<< " is in an interface class " << PrettyClass(klass);
- return NULL;
+ return nullptr;
} else if (!klass->IsInterface() && method_type == METHOD_INTERFACE) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "interface method " << PrettyMethod(res_method)
<< " is in a non-interface class " << PrettyClass(klass);
- return NULL;
+ return nullptr;
}
// See if the method type implied by the invoke instruction matches the access flags for the
// target method.
@@ -3092,7 +3104,7 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth
) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "invoke type (" << method_type << ") does not match method "
" type of " << PrettyMethod(res_method);
- return NULL;
+ return nullptr;
}
return res_method;
}
@@ -3126,7 +3138,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator(T* it, const
* rigorous check here (which is okay since we have to do it at runtime).
*/
if (method_type != METHOD_STATIC) {
- const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst, is_range);
if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
CHECK(have_pending_hard_failure_);
return nullptr;
@@ -3193,13 +3205,13 @@ mirror::ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator(T* it, const
uint32_t get_reg = is_range ? inst->VRegC_3rc() + static_cast<uint32_t>(sig_registers) :
arg[sig_registers];
if (reg_type.IsIntegralTypes()) {
- const RegType& src_type = work_line_->GetRegisterType(get_reg);
+ const RegType& src_type = work_line_->GetRegisterType(this, get_reg);
if (!src_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << get_reg << " has type " << src_type
<< " but expected " << reg_type;
return res_method;
}
- } else if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
+ } else if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
// Continue on soft failures. We need to find possible hard failures to avoid problems in the
// compiler.
if (have_pending_hard_failure_) {
@@ -3264,7 +3276,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvocationArgs(const Instruction* inst,
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
mirror::ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
- if (res_method == NULL) { // error or class is unresolved
+ if (res_method == nullptr) { // error or class is unresolved
// Check what we can statically.
if (!have_pending_hard_failure_) {
VerifyInvocationArgsUnresolvedMethod(inst, method_type, is_range);
@@ -3304,7 +3316,7 @@ mirror::ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst
RegisterLine* reg_line, bool is_range) {
DCHECK(inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK ||
inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
- const RegType& actual_arg_type = reg_line->GetInvocationThis(inst, is_range);
+ const RegType& actual_arg_type = reg_line->GetInvocationThis(this, inst, is_range);
if (!actual_arg_type.HasClass()) {
VLOG(verifier) << "Failed to get mirror::Class* from '" << actual_arg_type << "'";
return nullptr;
@@ -3324,7 +3336,7 @@ mirror::ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst
CHECK_LT(static_cast<int32_t>(vtable_index), dispatch_class->GetVTableLength())
<< PrettyDescriptor(klass);
mirror::ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index);
- CHECK(!Thread::Current()->IsExceptionPending());
+ CHECK(!self_->IsExceptionPending());
return res_method;
}
@@ -3333,18 +3345,18 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
DCHECK(Runtime::Current()->IsStarted());
mirror::ArtMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(),
is_range);
- if (res_method == NULL) {
+ if (res_method == nullptr) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name();
- return NULL;
+ return nullptr;
}
CHECK(!res_method->IsDirect() && !res_method->IsStatic());
// We use vAA as our expected arg count, rather than res_method->insSize, because we need to
// match the call to the signature. Also, we might be calling through an abstract method
// definition (which doesn't have register count values).
- const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst, is_range);
if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
- return NULL;
+ return nullptr;
}
const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
/* caught by static verifier */
@@ -3352,7 +3364,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
if (expected_args > code_item_->outs_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
<< ") exceeds outsSize (" << code_item_->outs_size_ << ")";
- return NULL;
+ return nullptr;
}
/*
@@ -3362,7 +3374,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
*/
if (actual_arg_type.IsUninitializedReference() && !res_method->IsConstructor()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
- return NULL;
+ return nullptr;
}
if (!actual_arg_type.IsZero()) {
mirror::Class* klass = res_method->GetDeclaringClass();
@@ -3374,7 +3386,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
Fail(actual_arg_type.IsUnresolvedTypes() ? VERIFY_ERROR_NO_CLASS :
VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
<< "' not instance of '" << res_method_class << "'";
- return NULL;
+ return nullptr;
}
}
/*
@@ -3382,7 +3394,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
* have been verified, so we can't assume it's properly formed.
*/
const DexFile::TypeList* params = res_method->GetParameterTypeList();
- size_t params_size = params == NULL ? 0 : params->Size();
+ size_t params_size = params == nullptr ? 0 : params->Size();
uint32_t arg[5];
if (!is_range) {
inst->GetVarArgs(arg);
@@ -3394,18 +3406,18 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
<< "'. Expected " << expected_args
<< " arguments, processing argument " << actual_args
<< " (where longs/doubles count twice).";
- return NULL;
+ return nullptr;
}
const char* descriptor =
res_method->GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
- if (descriptor == NULL) {
+ if (descriptor == nullptr) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
<< " missing signature component";
- return NULL;
+ return nullptr;
}
const RegType& reg_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
- if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
+ if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
return res_method;
}
actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
@@ -3413,7 +3425,7 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
if (actual_args != expected_args) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
<< " expected " << expected_args << " arguments, found " << actual_args;
- return NULL;
+ return nullptr;
} else {
return res_method;
}
@@ -3440,10 +3452,10 @@ void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, boo
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "new-array on non-array class " << res_type;
} else if (!is_filled) {
/* make sure "size" register is valid type */
- work_line_->VerifyRegisterType(inst->VRegB_22c(), reg_types_.Integer());
+ work_line_->VerifyRegisterType(this, inst->VRegB_22c(), reg_types_.Integer());
/* set register type to array class */
const RegType& precise_type = reg_types_.FromUninitialized(res_type);
- work_line_->SetRegisterType(inst->VRegA_22c(), precise_type);
+ work_line_->SetRegisterType(this, inst->VRegA_22c(), precise_type);
} else {
// Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of
// the list and fail. It's legal, if silly, for arg_count to be zero.
@@ -3455,34 +3467,35 @@ void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, boo
}
for (size_t ui = 0; ui < arg_count; ui++) {
uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui];
- if (!work_line_->VerifyRegisterType(get_reg, expected_type)) {
- work_line_->SetResultRegisterType(reg_types_.Conflict());
+ if (!work_line_->VerifyRegisterType(this, get_reg, expected_type)) {
+ work_line_->SetResultRegisterType(this, reg_types_.Conflict());
return;
}
}
// filled-array result goes into "result" register
const RegType& precise_type = reg_types_.FromUninitialized(res_type);
- work_line_->SetResultRegisterType(precise_type);
+ work_line_->SetResultRegisterType(this, precise_type);
}
}
}
void MethodVerifier::VerifyAGet(const Instruction* inst,
const RegType& insn_type, bool is_primitive) {
- const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
+ const RegType& index_type = work_line_->GetRegisterType(this, inst->VRegC_23x());
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
} else {
- const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
+ const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
if (array_type.IsZero()) {
// Null array class; this code path will fail at runtime. Infer a merge-able type from the
// instruction type. TODO: have a proper notion of bottom here.
if (!is_primitive || insn_type.IsCategory1Types()) {
// Reference or category 1
- work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Zero());
+ work_line_->SetRegisterType(this, inst->VRegA_23x(), reg_types_.Zero());
} else {
// Category 2
- work_line_->SetRegisterTypeWide(inst->VRegA_23x(), reg_types_.FromCat2ConstLo(0, false),
+ work_line_->SetRegisterTypeWide(this, inst->VRegA_23x(),
+ reg_types_.FromCat2ConstLo(0, false),
reg_types_.FromCat2ConstHi(0, false));
}
} else if (!array_type.IsArrayTypes()) {
@@ -3506,9 +3519,9 @@ void MethodVerifier::VerifyAGet(const Instruction* inst,
// instruction, which can't differentiate object types and ints from floats, longs from
// doubles.
if (!component_type.IsLowHalf()) {
- work_line_->SetRegisterType(inst->VRegA_23x(), component_type);
+ work_line_->SetRegisterType(this, inst->VRegA_23x(), component_type);
} else {
- work_line_->SetRegisterTypeWide(inst->VRegA_23x(), component_type,
+ work_line_->SetRegisterTypeWide(this, inst->VRegA_23x(), component_type,
component_type.HighHalf(&reg_types_));
}
}
@@ -3521,7 +3534,7 @@ void MethodVerifier::VerifyPrimitivePut(const RegType& target_type, const RegTyp
// Primitive assignability rules are weaker than regular assignability rules.
bool instruction_compatible;
bool value_compatible;
- const RegType& value_type = work_line_->GetRegisterType(vregA);
+ const RegType& value_type = work_line_->GetRegisterType(this, vregA);
if (target_type.IsIntegralTypes()) {
instruction_compatible = target_type.Equals(insn_type);
value_compatible = value_type.IsIntegralTypes();
@@ -3533,7 +3546,7 @@ void MethodVerifier::VerifyPrimitivePut(const RegType& target_type, const RegTyp
// Additional register check: this is not checked statically (as part of VerifyInstructions),
// as target_type depends on the resolved type of the field.
if (instruction_compatible && work_line_->NumRegs() > vregA + 1) {
- const RegType& value_type_hi = work_line_->GetRegisterType(vregA + 1);
+ const RegType& value_type_hi = work_line_->GetRegisterType(this, vregA + 1);
value_compatible = value_type.IsLongTypes() && value_type.CheckWidePair(value_type_hi);
} else {
value_compatible = false;
@@ -3543,7 +3556,7 @@ void MethodVerifier::VerifyPrimitivePut(const RegType& target_type, const RegTyp
// Additional register check: this is not checked statically (as part of VerifyInstructions),
// as target_type depends on the resolved type of the field.
if (instruction_compatible && work_line_->NumRegs() > vregA + 1) {
- const RegType& value_type_hi = work_line_->GetRegisterType(vregA + 1);
+ const RegType& value_type_hi = work_line_->GetRegisterType(this, vregA + 1);
value_compatible = value_type.IsDoubleTypes() && value_type.CheckWidePair(value_type_hi);
} else {
value_compatible = false;
@@ -3569,11 +3582,11 @@ void MethodVerifier::VerifyPrimitivePut(const RegType& target_type, const RegTyp
void MethodVerifier::VerifyAPut(const Instruction* inst,
const RegType& insn_type, bool is_primitive) {
- const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
+ const RegType& index_type = work_line_->GetRegisterType(this, inst->VRegC_23x());
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
} else {
- const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
+ const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
if (array_type.IsZero()) {
// Null array type; this code path will fail at runtime. Infer a merge-able type from the
// instruction type.
@@ -3592,7 +3605,7 @@ void MethodVerifier::VerifyAPut(const Instruction* inst,
// The instruction agrees with the type of array, confirm the value to be stored does too
// Note: we use the instruction type (rather than the component type) for aput-object as
// incompatible classes will be caught at runtime as an array store exception
- work_line_->VerifyRegisterType(vregA, insn_type);
+ work_line_->VerifyRegisterType(this, vregA, insn_type);
}
}
}
@@ -3607,29 +3620,29 @@ mirror::ArtField* MethodVerifier::GetStaticField(int field_idx) {
AppendToLastFailMessage(StringPrintf(" in attempt to access static field %d (%s) in %s",
field_idx, dex_file_->GetFieldName(field_id),
dex_file_->GetFieldDeclaringClassDescriptor(field_id)));
- return NULL;
+ return nullptr;
}
if (klass_type.IsUnresolvedTypes()) {
- return NULL; // Can't resolve Class so no more to do here, will do checking at runtime.
+ return nullptr; // Can't resolve Class so no more to do here, will do checking at runtime.
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::ArtField* field = class_linker->ResolveFieldJLS(*dex_file_, field_idx, dex_cache_,
class_loader_);
- if (field == NULL) {
+ if (field == nullptr) {
VLOG(verifier) << "Unable to resolve static field " << field_idx << " ("
<< dex_file_->GetFieldName(field_id) << ") in "
<< dex_file_->GetFieldDeclaringClassDescriptor(field_id);
- DCHECK(Thread::Current()->IsExceptionPending());
- Thread::Current()->ClearException();
- return NULL;
+ DCHECK(self_->IsExceptionPending());
+ self_->ClearException();
+ return nullptr;
} else if (!GetDeclaringClass().CanAccessMember(field->GetDeclaringClass(),
field->GetAccessFlags())) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot access static field " << PrettyField(field)
<< " from " << GetDeclaringClass();
- return NULL;
+ return nullptr;
} else if (!field->IsStatic()) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected field " << PrettyField(field) << " to be static";
- return NULL;
+ return nullptr;
}
return field;
}
@@ -3642,30 +3655,30 @@ mirror::ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int
AppendToLastFailMessage(StringPrintf(" in attempt to access instance field %d (%s) in %s",
field_idx, dex_file_->GetFieldName(field_id),
dex_file_->GetFieldDeclaringClassDescriptor(field_id)));
- return NULL;
+ return nullptr;
}
if (klass_type.IsUnresolvedTypes()) {
- return NULL; // Can't resolve Class so no more to do here
+ return nullptr; // Can't resolve Class so no more to do here
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::ArtField* field = class_linker->ResolveFieldJLS(*dex_file_, field_idx, dex_cache_,
class_loader_);
- if (field == NULL) {
+ if (field == nullptr) {
VLOG(verifier) << "Unable to resolve instance field " << field_idx << " ("
<< dex_file_->GetFieldName(field_id) << ") in "
<< dex_file_->GetFieldDeclaringClassDescriptor(field_id);
- DCHECK(Thread::Current()->IsExceptionPending());
- Thread::Current()->ClearException();
- return NULL;
+ DCHECK(self_->IsExceptionPending());
+ self_->ClearException();
+ return nullptr;
} else if (!GetDeclaringClass().CanAccessMember(field->GetDeclaringClass(),
field->GetAccessFlags())) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot access instance field " << PrettyField(field)
<< " from " << GetDeclaringClass();
- return NULL;
+ return nullptr;
} else if (field->IsStatic()) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "expected field " << PrettyField(field)
<< " to not be static";
- return NULL;
+ return nullptr;
} else if (obj_type.IsZero()) {
// Cannot infer and check type, however, access will cause null pointer exception
return field;
@@ -3673,7 +3686,7 @@ mirror::ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int
// Trying to read a field from something that isn't a reference
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance field access on object that has "
<< "non-reference type " << obj_type;
- return NULL;
+ return nullptr;
} else {
mirror::Class* klass = field->GetDeclaringClass();
const RegType& field_klass =
@@ -3687,14 +3700,14 @@ mirror::ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "cannot access instance field " << PrettyField(field)
<< " of a not fully initialized object within the context"
<< " of " << PrettyMethod(dex_method_idx_, *dex_file_);
- return NULL;
+ return nullptr;
} else if (!field_klass.IsAssignableFrom(obj_type)) {
// Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
// of C1. For resolution to occur the declared class of the field must be compatible with
// obj_type, we've discovered this wasn't so, so report the field didn't exist.
Fail(VERIFY_ERROR_NO_FIELD) << "cannot access instance field " << PrettyField(field)
<< " from object of type " << obj_type;
- return NULL;
+ return nullptr;
} else {
return field;
}
@@ -3708,15 +3721,14 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty
if (is_static) {
field = GetStaticField(field_idx);
} else {
- const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
+ const RegType& object_type = work_line_->GetRegisterType(this, inst->VRegB_22c());
field = GetInstanceField(object_type, field_idx);
}
const RegType* field_type = nullptr;
- if (field != NULL) {
- Thread* self = Thread::Current();
+ if (field != nullptr) {
mirror::Class* field_type_class;
{
- StackHandleScope<1> hs(self);
+ StackHandleScope<1> hs(self_);
HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
field_type_class = FieldHelper(h_field).GetType(can_load_classes_);
}
@@ -3724,8 +3736,8 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty
field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
field_type_class->CannotBeAssignedFromOtherTypes());
} else {
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ DCHECK(!can_load_classes_ || self_->IsExceptionPending());
+ self_->ClearException();
}
}
if (field_type == nullptr) {
@@ -3756,14 +3768,14 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty
<< " to be compatible with type '" << insn_type
<< "' but found type '" << *field_type
<< "' in Get-object";
- work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+ work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
return;
}
}
if (!field_type->IsLowHalf()) {
- work_line_->SetRegisterType(vregA, *field_type);
+ work_line_->SetRegisterType(this, vregA, *field_type);
} else {
- work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(&reg_types_));
+ work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
}
}
@@ -3774,11 +3786,11 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty
if (is_static) {
field = GetStaticField(field_idx);
} else {
- const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
+ const RegType& object_type = work_line_->GetRegisterType(this, inst->VRegB_22c());
field = GetInstanceField(object_type, field_idx);
}
const RegType* field_type = nullptr;
- if (field != NULL) {
+ if (field != nullptr) {
if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
<< " from other class " << GetDeclaringClass();
@@ -3786,7 +3798,7 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty
}
mirror::Class* field_type_class;
{
- StackHandleScope<1> hs(Thread::Current());
+ StackHandleScope<1> hs(self_);
HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
FieldHelper fh(h_field);
field_type_class = fh.GetType(can_load_classes_);
@@ -3795,9 +3807,8 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty
field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
field_type_class->CannotBeAssignedFromOtherTypes());
} else {
- Thread* self = Thread::Current();
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ DCHECK(!can_load_classes_ || self_->IsExceptionPending());
+ self_->ClearException();
}
}
if (field_type == nullptr) {
@@ -3817,7 +3828,7 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty
<< "' in put-object";
return;
}
- work_line_->VerifyRegisterType(vregA, *field_type);
+ work_line_->VerifyRegisterType(this, vregA, *field_type);
}
}
@@ -3829,7 +3840,7 @@ mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
inst->Opcode() == Instruction::IPUT_QUICK ||
inst->Opcode() == Instruction::IPUT_WIDE_QUICK ||
inst->Opcode() == Instruction::IPUT_OBJECT_QUICK);
- const RegType& object_type = reg_line->GetRegisterType(inst->VRegB_22c());
+ const RegType& object_type = reg_line->GetRegisterType(this, inst->VRegB_22c());
if (!object_type.HasClass()) {
VLOG(verifier) << "Failed to get mirror::Class* from '" << object_type << "'";
return nullptr;
@@ -3848,13 +3859,13 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins
bool is_primitive) {
DCHECK(Runtime::Current()->IsStarted());
mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
- if (field == NULL) {
+ if (field == nullptr) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
return;
}
mirror::Class* field_type_class;
{
- StackHandleScope<1> hs(Thread::Current());
+ StackHandleScope<1> hs(self_);
HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
FieldHelper fh(h_field);
field_type_class = fh.GetType(can_load_classes_);
@@ -3864,9 +3875,8 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins
field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
field_type_class->CannotBeAssignedFromOtherTypes());
} else {
- Thread* self = Thread::Current();
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ DCHECK(!can_load_classes_ || self_->IsExceptionPending());
+ self_->ClearException();
field_type = &reg_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
field->GetTypeDescriptor(), false);
}
@@ -3893,14 +3903,14 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins
<< " to be compatible with type '" << insn_type
<< "' but found type '" << *field_type
<< "' in get-object";
- work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+ work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
return;
}
}
if (!field_type->IsLowHalf()) {
- work_line_->SetRegisterType(vregA, *field_type);
+ work_line_->SetRegisterType(this, vregA, *field_type);
} else {
- work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(&reg_types_));
+ work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
}
}
@@ -3908,14 +3918,14 @@ void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& ins
bool is_primitive) {
DCHECK(Runtime::Current()->IsStarted());
mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
- if (field == NULL) {
+ if (field == nullptr) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
return;
}
const char* descriptor = field->GetTypeDescriptor();
mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
- if (field != NULL) {
+ if (field != nullptr) {
if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
<< " from other class " << GetDeclaringClass();
@@ -3927,7 +3937,7 @@ void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& ins
// Primitive field assignability rules are weaker than regular assignability rules
bool instruction_compatible;
bool value_compatible;
- const RegType& value_type = work_line_->GetRegisterType(vregA);
+ const RegType& value_type = work_line_->GetRegisterType(this, vregA);
if (field_type.IsIntegralTypes()) {
instruction_compatible = insn_type.IsIntegralTypes();
value_compatible = value_type.IsIntegralTypes();
@@ -3969,7 +3979,7 @@ void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& ins
<< "' in put-object";
return;
}
- work_line_->VerifyRegisterType(vregA, field_type);
+ work_line_->VerifyRegisterType(this, vregA, field_type);
}
}
@@ -3995,7 +4005,7 @@ bool MethodVerifier::UpdateRegisters(uint32_t next_insn, RegisterLine* merge_lin
target_line->CopyFromLine(merge_line);
} else {
// Verify that the monitor stack is empty on return.
- if (!merge_line->VerifyMonitorStackEmpty()) {
+ if (!merge_line->VerifyMonitorStackEmpty(this)) {
return false;
}
// For returns we only care about the operand to the return, all other registers are dead.
@@ -4003,33 +4013,33 @@ bool MethodVerifier::UpdateRegisters(uint32_t next_insn, RegisterLine* merge_lin
const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
Instruction::Code opcode = ret_inst->Opcode();
if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) {
- target_line->MarkAllRegistersAsConflicts();
+ target_line->MarkAllRegistersAsConflicts(this);
} else {
target_line->CopyFromLine(merge_line);
if (opcode == Instruction::RETURN_WIDE) {
- target_line->MarkAllRegistersAsConflictsExceptWide(ret_inst->VRegA_11x());
+ target_line->MarkAllRegistersAsConflictsExceptWide(this, ret_inst->VRegA_11x());
} else {
- target_line->MarkAllRegistersAsConflictsExcept(ret_inst->VRegA_11x());
+ target_line->MarkAllRegistersAsConflictsExcept(this, ret_inst->VRegA_11x());
}
}
}
} else {
std::unique_ptr<RegisterLine> copy(gDebugVerify ?
RegisterLine::Create(target_line->NumRegs(), this) :
- NULL);
+ nullptr);
if (gDebugVerify) {
copy->CopyFromLine(target_line);
}
- changed = target_line->MergeRegisters(merge_line);
+ changed = target_line->MergeRegisters(this, merge_line);
if (have_pending_hard_failure_) {
return false;
}
if (gDebugVerify && changed) {
LogVerifyInfo() << "Merging at [" << reinterpret_cast<void*>(work_insn_idx_) << "]"
<< " to [" << reinterpret_cast<void*>(next_insn) << "]: " << "\n"
- << *copy.get() << " MERGE\n"
- << *merge_line << " ==\n"
- << *target_line << "\n";
+ << copy->Dump(this) << " MERGE\n"
+ << merge_line->Dump(this) << " ==\n"
+ << target_line->Dump(this) << "\n";
}
if (update_merge_line && changed) {
merge_line->CopyFromLine(target_line);
@@ -4048,8 +4058,7 @@ InstructionFlags* MethodVerifier::CurrentInsnFlags() {
const RegType& MethodVerifier::GetMethodReturnType() {
if (return_type_ == nullptr) {
if (mirror_method_.Get() != nullptr) {
- Thread* self = Thread::Current();
- StackHandleScope<1> hs(self);
+ StackHandleScope<1> hs(self_);
mirror::Class* return_type_class =
MethodHelper(hs.NewHandle(mirror_method_.Get())).GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
@@ -4057,8 +4066,8 @@ const RegType& MethodVerifier::GetMethodReturnType() {
return_type_class,
return_type_class->CannotBeAssignedFromOtherTypes());
} else {
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ DCHECK(!can_load_classes_ || self_->IsExceptionPending());
+ self_->ClearException();
}
}
if (return_type_ == nullptr) {
@@ -4073,7 +4082,7 @@ const RegType& MethodVerifier::GetMethodReturnType() {
}
const RegType& MethodVerifier::GetDeclaringClass() {
- if (declaring_class_ == NULL) {
+ if (declaring_class_ == nullptr) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const char* descriptor
= dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
@@ -4093,16 +4102,19 @@ std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) {
DCHECK(line != nullptr) << "No register line at DEX pc " << StringPrintf("0x%x", dex_pc);
std::vector<int32_t> result;
for (size_t i = 0; i < line->NumRegs(); ++i) {
- const RegType& type = line->GetRegisterType(i);
+ const RegType& type = line->GetRegisterType(this, i);
if (type.IsConstant()) {
result.push_back(type.IsPreciseConstant() ? kConstant : kImpreciseConstant);
- result.push_back(type.ConstantValue());
+ const ConstantType* const_val = down_cast<const ConstantType*>(&type);
+ result.push_back(const_val->ConstantValue());
} else if (type.IsConstantLo()) {
result.push_back(type.IsPreciseConstantLo() ? kConstant : kImpreciseConstant);
- result.push_back(type.ConstantValueLo());
+ const ConstantType* const_val = down_cast<const ConstantType*>(&type);
+ result.push_back(const_val->ConstantValueLo());
} else if (type.IsConstantHi()) {
result.push_back(type.IsPreciseConstantHi() ? kConstant : kImpreciseConstant);
- result.push_back(type.ConstantValueHi());
+ const ConstantType* const_val = down_cast<const ConstantType*>(&type);
+ result.push_back(const_val->ConstantValueHi());
} else if (type.IsIntegralTypes()) {
result.push_back(kIntVReg);
result.push_back(0);
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 45c0a0318a..81ab960ec7 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -140,16 +140,18 @@ class MethodVerifier {
};
/* Verify a class. Returns "kNoFailure" on success. */
- static FailureKind VerifyClass(mirror::Class* klass, bool allow_soft_failures, std::string* error)
+ static FailureKind VerifyClass(Thread* self, mirror::Class* klass, bool allow_soft_failures,
+ std::string* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static FailureKind VerifyClass(const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
+ static FailureKind VerifyClass(Thread* self, const DexFile* dex_file,
+ ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
bool allow_soft_failures, std::string* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file,
- ConstHandle<mirror::DexCache> dex_cache,
+ static void VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t method_idx,
+ const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item,
@@ -202,7 +204,7 @@ class MethodVerifier {
return can_load_classes_;
}
- MethodVerifier(const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
+ MethodVerifier(Thread* self, const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item, uint32_t method_idx,
ConstHandle<mirror::ArtMethod> method,
@@ -253,7 +255,7 @@ class MethodVerifier {
* (3) Iterate through the method, checking type safety and looking
* for code flow problems.
*/
- static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file,
+ static FailureKind VerifyMethod(Thread* self, uint32_t method_idx, const DexFile* dex_file,
ConstHandle<mirror::DexCache> dex_cache,
ConstHandle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def_idx,
@@ -625,6 +627,9 @@ class MethodVerifier {
const RegType& DetermineCat1Constant(int32_t value, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // The thread we're verifying on.
+ Thread* const self_;
+
RegTypeCache reg_types_;
PcToRegisterLineTable reg_table_;
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index a5895e6dbf..770ca7e7fb 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -32,11 +32,12 @@ class MethodVerifierTest : public CommonRuntimeTest {
void VerifyClass(const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ASSERT_TRUE(descriptor != NULL);
- mirror::Class* klass = class_linker_->FindSystemClass(Thread::Current(), descriptor.c_str());
+ Thread* self = Thread::Current();
+ mirror::Class* klass = class_linker_->FindSystemClass(self, descriptor.c_str());
// Verify the class
std::string error_msg;
- ASSERT_TRUE(MethodVerifier::VerifyClass(klass, true, &error_msg) == MethodVerifier::kNoFailure)
+ ASSERT_TRUE(MethodVerifier::VerifyClass(self, klass, true, &error_msg) == MethodVerifier::kNoFailure)
<< error_msg;
}
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
new file mode 100644
index 0000000000..480ed40ba8
--- /dev/null
+++ b/runtime/verifier/reg_type-inl.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_
+#define ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_
+
+#include "reg_type.h"
+
+#include "base/casts.h"
+#include "mirror/class.h"
+
+namespace art {
+namespace verifier {
+
+inline bool RegType::CanAccess(const RegType& other) const {
+ if (Equals(other)) {
+ return true; // Trivial accessibility.
+ } else {
+ bool this_unresolved = IsUnresolvedTypes();
+ bool other_unresolved = other.IsUnresolvedTypes();
+ if (!this_unresolved && !other_unresolved) {
+ return GetClass()->CanAccess(other.GetClass());
+ } else if (!other_unresolved) {
+ return other.GetClass()->IsPublic(); // Be conservative, only allow if other is public.
+ } else {
+ return false; // More complicated test not possible on unresolved types, be conservative.
+ }
+ }
+}
+
+inline bool RegType::CanAccessMember(mirror::Class* klass, uint32_t access_flags) const {
+ if ((access_flags & kAccPublic) != 0) {
+ return true;
+ }
+ if (!IsUnresolvedTypes()) {
+ return GetClass()->CanAccessMember(klass, access_flags);
+ } else {
+ return false; // More complicated test not possible on unresolved types, be conservative.
+ }
+}
+
+inline bool RegType::IsConstantBoolean() const {
+ if (!IsConstant()) {
+ return false;
+ } else {
+ const ConstantType* const_val = down_cast<const ConstantType*>(this);
+ return const_val->ConstantValue() >= 0 && const_val->ConstantValue() <= 1;
+ }
+}
+
+inline bool RegType::AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict) {
+ if (lhs.Equals(rhs)) {
+ return true;
+ } else {
+ if (lhs.IsBoolean()) {
+ return rhs.IsBooleanTypes();
+ } else if (lhs.IsByte()) {
+ return rhs.IsByteTypes();
+ } else if (lhs.IsShort()) {
+ return rhs.IsShortTypes();
+ } else if (lhs.IsChar()) {
+ return rhs.IsCharTypes();
+ } else if (lhs.IsInteger()) {
+ return rhs.IsIntegralTypes();
+ } else if (lhs.IsFloat()) {
+ return rhs.IsFloatTypes();
+ } else if (lhs.IsLongLo()) {
+ return rhs.IsLongTypes();
+ } else if (lhs.IsDoubleLo()) {
+ return rhs.IsDoubleTypes();
+ } else {
+ CHECK(lhs.IsReferenceTypes())
+ << "Unexpected register type in IsAssignableFrom: '"
+ << lhs << "' := '" << rhs << "'";
+ if (rhs.IsZero()) {
+ return true; // All reference types can be assigned null.
+ } else if (!rhs.IsReferenceTypes()) {
+ return false; // Expect rhs to be a reference type.
+ } else if (lhs.IsJavaLangObject()) {
+ return true; // All reference types can be assigned to Object.
+ } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
+ // If we're not strict allow assignment to any interface, see comment in ClassJoin.
+ return true;
+ } else if (lhs.IsJavaLangObjectArray()) {
+ return rhs.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
+ } else if (lhs.HasClass() && rhs.HasClass() &&
+ lhs.GetClass()->IsAssignableFrom(rhs.GetClass())) {
+ // We're assignable from the Class point-of-view.
+ return true;
+ } else {
+ // Unresolved types are only assignable for null and equality.
+ return false;
+ }
+ }
+ }
+}
+
+inline bool RegType::IsAssignableFrom(const RegType& src) const {
+ return AssignableFrom(*this, src, false);
+}
+
+inline bool RegType::IsStrictlyAssignableFrom(const RegType& src) const {
+ return AssignableFrom(*this, src, true);
+}
+
+inline const DoubleHiType* DoubleHiType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const DoubleLoType* DoubleLoType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const LongHiType* LongHiType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const LongLoType* LongLoType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const FloatType* FloatType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const CharType* CharType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const ShortType* ShortType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const ByteType* ByteType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+
+inline const IntegerType* IntegerType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const BooleanType* BooleanType::GetInstance() {
+ DCHECK(BooleanType::instance_ != nullptr);
+ return BooleanType::instance_;
+}
+
+inline const ConflictType* ConflictType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+inline const UndefinedType* UndefinedType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
+} // namespace verifier
+} // namespace art
+
+#endif // ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 68c7849a5c..41541b5c86 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#include "reg_type.h"
-
+#include "reg_type-inl.h"
#include "base/casts.h"
#include "class_linker-inl.h"
@@ -33,41 +32,23 @@
namespace art {
namespace verifier {
-UndefinedType* UndefinedType::instance_ = NULL;
-ConflictType* ConflictType::instance_ = NULL;
-BooleanType* BooleanType::instance = NULL;
-ByteType* ByteType::instance_ = NULL;
-ShortType* ShortType::instance_ = NULL;
-CharType* CharType::instance_ = NULL;
-FloatType* FloatType::instance_ = NULL;
-LongLoType* LongLoType::instance_ = NULL;
-LongHiType* LongHiType::instance_ = NULL;
-DoubleLoType* DoubleLoType::instance_ = NULL;
-DoubleHiType* DoubleHiType::instance_ = NULL;
-IntegerType* IntegerType::instance_ = NULL;
-
-int32_t RegType::ConstantValue() const {
- ScopedObjectAccess soa(Thread::Current());
- LOG(FATAL) << "Unexpected call to ConstantValue: " << *this;
- return 0;
-}
-
-int32_t RegType::ConstantValueLo() const {
- ScopedObjectAccess soa(Thread::Current());
- LOG(FATAL) << "Unexpected call to ConstantValueLo: " << *this;
- return 0;
-}
-
-int32_t RegType::ConstantValueHi() const {
- ScopedObjectAccess soa(Thread::Current());
- LOG(FATAL) << "Unexpected call to ConstantValueHi: " << *this;
- return 0;
-}
+const UndefinedType* UndefinedType::instance_ = nullptr;
+const ConflictType* ConflictType::instance_ = nullptr;
+const BooleanType* BooleanType::instance_ = nullptr;
+const ByteType* ByteType::instance_ = nullptr;
+const ShortType* ShortType::instance_ = nullptr;
+const CharType* CharType::instance_ = nullptr;
+const FloatType* FloatType::instance_ = nullptr;
+const LongLoType* LongLoType::instance_ = nullptr;
+const LongHiType* LongHiType::instance_ = nullptr;
+const DoubleLoType* DoubleLoType::instance_ = nullptr;
+const DoubleHiType* DoubleHiType::instance_ = nullptr;
+const IntegerType* IntegerType::instance_ = nullptr;
PrimitiveType::PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: RegType(klass, descriptor, cache_id) {
- CHECK(klass != NULL);
+ CHECK(klass != nullptr);
CHECK(!descriptor.empty());
}
@@ -142,222 +123,160 @@ std::string IntegerType::Dump() const {
return "Integer";
}
-DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new DoubleHiType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-
-DoubleHiType* DoubleHiType::GetInstance() {
- CHECK(instance_ != NULL);
+const DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new DoubleHiType(klass, descriptor, cache_id);
return instance_;
}
void DoubleHiType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
- }
-}
-
-DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new DoubleLoType(klass, descriptor, cache_id);
+ instance_ = nullptr;
}
- return instance_;
}
-DoubleLoType* DoubleLoType::GetInstance() {
- CHECK(instance_ != NULL);
+const DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new DoubleLoType(klass, descriptor, cache_id);
return instance_;
}
void DoubleLoType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new LongLoType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-
-LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new LongHiType(klass, descriptor, cache_id);
- }
+const LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new LongLoType(klass, descriptor, cache_id);
return instance_;
}
-LongHiType* LongHiType::GetInstance() {
- CHECK(instance_ != NULL);
+const LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new LongHiType(klass, descriptor, cache_id);
return instance_;
}
void LongHiType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-LongLoType* LongLoType::GetInstance() {
- CHECK(instance_ != NULL);
- return instance_;
-}
-
void LongLoType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-FloatType* FloatType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new FloatType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-FloatType* FloatType::GetInstance() {
- CHECK(instance_ != NULL);
+const FloatType* FloatType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new FloatType(klass, descriptor, cache_id);
return instance_;
}
void FloatType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-CharType* CharType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new CharType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-
-CharType* CharType::GetInstance() {
- CHECK(instance_ != NULL);
+const CharType* CharType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new CharType(klass, descriptor, cache_id);
return instance_;
}
void CharType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
- }
-}
-
-ShortType* ShortType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new ShortType(klass, descriptor, cache_id);
+ instance_ = nullptr;
}
- return instance_;
}
-ShortType* ShortType::GetInstance() {
- CHECK(instance_ != NULL);
+const ShortType* ShortType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new ShortType(klass, descriptor, cache_id);
return instance_;
}
void ShortType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-ByteType* ByteType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new ByteType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-
-ByteType* ByteType::GetInstance() {
- CHECK(instance_ != NULL);
+const ByteType* ByteType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new ByteType(klass, descriptor, cache_id);
return instance_;
}
void ByteType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new IntegerType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-
-IntegerType* IntegerType::GetInstance() {
- CHECK(instance_ != NULL);
+const IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new IntegerType(klass, descriptor, cache_id);
return instance_;
}
void IntegerType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
- }
-}
-
-ConflictType* ConflictType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new ConflictType(klass, descriptor, cache_id);
+ instance_ = nullptr;
}
- return instance_;
}
-ConflictType* ConflictType::GetInstance() {
- CHECK(instance_ != NULL);
+const ConflictType* ConflictType::CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new ConflictType(klass, descriptor, cache_id);
return instance_;
}
void ConflictType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
-BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+const BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
- if (BooleanType::instance == NULL) {
- instance = new BooleanType(klass, descriptor, cache_id);
- }
- return BooleanType::instance;
-}
-
-BooleanType* BooleanType::GetInstance() {
- CHECK(BooleanType::instance != NULL);
- return BooleanType::instance;
+ CHECK(BooleanType::instance_ == nullptr);
+ instance_ = new BooleanType(klass, descriptor, cache_id);
+ return BooleanType::instance_;
}
void BooleanType::Destroy() {
- if (BooleanType::instance != NULL) {
- delete instance;
- instance = NULL;
+ if (BooleanType::instance_ != nullptr) {
+ delete instance_;
+ instance_ = nullptr;
}
}
@@ -365,23 +284,18 @@ std::string UndefinedType::Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_loc
return "Undefined";
}
-UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id) {
- if (instance_ == NULL) {
- instance_ = new UndefinedType(klass, descriptor, cache_id);
- }
- return instance_;
-}
-
-UndefinedType* UndefinedType::GetInstance() {
- CHECK(instance_ != NULL);
+const UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new UndefinedType(klass, descriptor, cache_id);
return instance_;
}
void UndefinedType::Destroy() {
- if (instance_ != NULL) {
+ if (instance_ != nullptr) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
}
}
@@ -528,18 +442,6 @@ std::string ImpreciseConstHiType::Dump() const {
return result.str();
}
-ConstantType::ConstantType(uint32_t constant, uint16_t cache_id)
- : RegType(NULL, "", cache_id), constant_(constant) {
-}
-
-const RegType& UndefinedType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (incoming_type.IsUndefined()) {
- return *this; // Undefined MERGE Undefined => Undefined
- }
- return reg_types->Conflict();
-}
-
const RegType& RegType::HighHalf(RegTypeCache* cache) const {
DCHECK(IsLowHalf());
if (IsLongLo()) {
@@ -548,7 +450,8 @@ const RegType& RegType::HighHalf(RegTypeCache* cache) const {
return cache->DoubleHi();
} else {
DCHECK(IsImpreciseConstantLo());
- return cache->FromCat2ConstHi(ConstantValue(), false);
+ const ConstantType* const_val = down_cast<const ConstantType*>(this);
+ return cache->FromCat2ConstHi(const_val->ConstantValue(), false);
}
}
@@ -586,24 +489,21 @@ bool UninitializedType::IsNonZeroReferenceTypes() const {
bool UnresolvedType::IsNonZeroReferenceTypes() const {
return true;
}
+
std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const {
std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
- const RegType& _left(reg_type_cache_->GetFromId(refs.first));
- RegType& __left(const_cast<RegType&>(_left));
- UnresolvedMergedType* left = down_cast<UnresolvedMergedType*>(&__left);
-
- RegType& _right(
- const_cast<RegType&>(reg_type_cache_->GetFromId(refs.second)));
- UnresolvedMergedType* right = down_cast<UnresolvedMergedType*>(&_right);
+ const RegType& left = reg_type_cache_->GetFromId(refs.first);
+ const RegType& right = reg_type_cache_->GetFromId(refs.second);
std::set<uint16_t> types;
- if (left->IsUnresolvedMergedReference()) {
- types = left->GetMergedTypes();
+ if (left.IsUnresolvedMergedReference()) {
+ types = down_cast<const UnresolvedMergedType*>(&left)->GetMergedTypes();
} else {
types.insert(refs.first);
}
- if (right->IsUnresolvedMergedReference()) {
- std::set<uint16_t> right_types = right->GetMergedTypes();
+ if (right.IsUnresolvedMergedReference()) {
+ std::set<uint16_t> right_types =
+ down_cast<const UnresolvedMergedType*>(&right)->GetMergedTypes();
types.insert(right_types.begin(), right_types.end());
} else {
types.insert(refs.second);
@@ -619,7 +519,7 @@ std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const {
const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
if (!IsUnresolvedTypes()) {
mirror::Class* super_klass = GetClass()->GetSuperClass();
- if (super_klass != NULL) {
+ if (super_klass != nullptr) {
// A super class of a precise type isn't precise as a precise type indicates the register
// holds exactly that type.
std::string temp;
@@ -638,33 +538,6 @@ const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
}
}
-bool RegType::CanAccess(const RegType& other) const {
- if (Equals(other)) {
- return true; // Trivial accessibility.
- } else {
- bool this_unresolved = IsUnresolvedTypes();
- bool other_unresolved = other.IsUnresolvedTypes();
- if (!this_unresolved && !other_unresolved) {
- return GetClass()->CanAccess(other.GetClass());
- } else if (!other_unresolved) {
- return other.GetClass()->IsPublic(); // Be conservative, only allow if other is public.
- } else {
- return false; // More complicated test not possible on unresolved types, be conservative.
- }
- }
-}
-
-bool RegType::CanAccessMember(mirror::Class* klass, uint32_t access_flags) const {
- if ((access_flags & kAccPublic) != 0) {
- return true;
- }
- if (!IsUnresolvedTypes()) {
- return GetClass()->CanAccessMember(klass, access_flags);
- } else {
- return false; // More complicated test not possible on unresolved types, be conservative.
- }
-}
-
bool RegType::IsObjectArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()) {
// Primitive arrays will always resolve
@@ -704,106 +577,38 @@ bool RegType::IsInstantiableTypes() const {
return IsUnresolvedTypes() || (IsNonZeroReferenceTypes() && GetClass()->IsInstantiable());
}
-ImpreciseConstType::ImpreciseConstType(uint32_t constat, uint16_t cache_id)
- : ConstantType(constat, cache_id) {
-}
-
-static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (lhs.Equals(rhs)) {
- return true;
- } else {
- if (lhs.IsBoolean()) {
- return rhs.IsBooleanTypes();
- } else if (lhs.IsByte()) {
- return rhs.IsByteTypes();
- } else if (lhs.IsShort()) {
- return rhs.IsShortTypes();
- } else if (lhs.IsChar()) {
- return rhs.IsCharTypes();
- } else if (lhs.IsInteger()) {
- return rhs.IsIntegralTypes();
- } else if (lhs.IsFloat()) {
- return rhs.IsFloatTypes();
- } else if (lhs.IsLongLo()) {
- return rhs.IsLongTypes();
- } else if (lhs.IsDoubleLo()) {
- return rhs.IsDoubleTypes();
- } else {
- CHECK(lhs.IsReferenceTypes())
- << "Unexpected register type in IsAssignableFrom: '"
- << lhs << "' := '" << rhs << "'";
- if (rhs.IsZero()) {
- return true; // All reference types can be assigned null.
- } else if (!rhs.IsReferenceTypes()) {
- return false; // Expect rhs to be a reference type.
- } else if (lhs.IsJavaLangObject()) {
- return true; // All reference types can be assigned to Object.
- } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
- // If we're not strict allow assignment to any interface, see comment in ClassJoin.
- return true;
- } else if (lhs.IsJavaLangObjectArray()) {
- return rhs.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
- } else if (lhs.HasClass() && rhs.HasClass() &&
- lhs.GetClass()->IsAssignableFrom(rhs.GetClass())) {
- // We're assignable from the Class point-of-view.
- return true;
- } else {
- // Unresolved types are only assignable for null and equality.
- return false;
- }
- }
- }
-}
-
-bool RegType::IsAssignableFrom(const RegType& src) const {
- return AssignableFrom(*this, src, false);
-}
-
-bool RegType::IsStrictlyAssignableFrom(const RegType& src) const {
- return AssignableFrom(*this, src, true);
-}
-
-int32_t ConstantType::ConstantValueLo() const {
- DCHECK(IsConstantLo());
- return constant_;
-}
-
-int32_t ConstantType::ConstantValueHi() const {
- if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) {
- return constant_;
- } else {
- DCHECK(false);
- return 0;
- }
-}
-
static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
return a.IsConstantTypes() ? b : a;
}
const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
DCHECK(!Equals(incoming_type)); // Trivial equality handled by caller
- if (IsConflict()) {
+ // Perform pointer equality tests for conflict to avoid virtual method dispatch.
+ const ConflictType& conflict = reg_types->Conflict();
+ if (this == &conflict) {
+ DCHECK(IsConflict());
return *this; // Conflict MERGE * => Conflict
- } else if (incoming_type.IsConflict()) {
+ } else if (&incoming_type == &conflict) {
+ DCHECK(incoming_type.IsConflict());
return incoming_type; // * MERGE Conflict => Conflict
} else if (IsUndefined() || incoming_type.IsUndefined()) {
- return reg_types->Conflict(); // Unknown MERGE * => Conflict
+ return conflict; // Unknown MERGE * => Conflict
} else if (IsConstant() && incoming_type.IsConstant()) {
- int32_t val1 = ConstantValue();
- int32_t val2 = incoming_type.ConstantValue();
+ const ConstantType& type1 = *down_cast<const ConstantType*>(this);
+ const ConstantType& type2 = *down_cast<const ConstantType*>(&incoming_type);
+ int32_t val1 = type1.ConstantValue();
+ int32_t val2 = type2.ConstantValue();
if (val1 >= 0 && val2 >= 0) {
// +ve1 MERGE +ve2 => MAX(+ve1, +ve2)
if (val1 >= val2) {
- if (!IsPreciseConstant()) {
+ if (!type1.IsPreciseConstant()) {
return *this;
} else {
return reg_types->FromCat1Const(val1, false);
}
} else {
- if (!incoming_type.IsPreciseConstant()) {
- return incoming_type;
+ if (!type2.IsPreciseConstant()) {
+ return type2;
} else {
return reg_types->FromCat1Const(val2, false);
}
@@ -811,30 +616,30 @@ const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_ty
} else if (val1 < 0 && val2 < 0) {
// -ve1 MERGE -ve2 => MIN(-ve1, -ve2)
if (val1 <= val2) {
- if (!IsPreciseConstant()) {
+ if (!type1.IsPreciseConstant()) {
return *this;
} else {
return reg_types->FromCat1Const(val1, false);
}
} else {
- if (!incoming_type.IsPreciseConstant()) {
- return incoming_type;
+ if (!type2.IsPreciseConstant()) {
+ return type2;
} else {
return reg_types->FromCat1Const(val2, false);
}
}
} else {
// Values are +ve and -ve, choose smallest signed type in which they both fit
- if (IsConstantByte()) {
- if (incoming_type.IsConstantByte()) {
+ if (type1.IsConstantByte()) {
+ if (type2.IsConstantByte()) {
return reg_types->ByteConstant();
- } else if (incoming_type.IsConstantShort()) {
+ } else if (type2.IsConstantShort()) {
return reg_types->ShortConstant();
} else {
return reg_types->IntConstant();
}
- } else if (IsConstantShort()) {
- if (incoming_type.IsConstantShort()) {
+ } else if (type1.IsConstantShort()) {
+ if (type2.IsConstantShort()) {
return reg_types->ShortConstant();
} else {
return reg_types->IntConstant();
@@ -844,12 +649,16 @@ const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_ty
}
}
} else if (IsConstantLo() && incoming_type.IsConstantLo()) {
- int32_t val1 = ConstantValueLo();
- int32_t val2 = incoming_type.ConstantValueLo();
+ const ConstantType& type1 = *down_cast<const ConstantType*>(this);
+ const ConstantType& type2 = *down_cast<const ConstantType*>(&incoming_type);
+ int32_t val1 = type1.ConstantValueLo();
+ int32_t val2 = type2.ConstantValueLo();
return reg_types->FromCat2ConstLo(val1 | val2, false);
} else if (IsConstantHi() && incoming_type.IsConstantHi()) {
- int32_t val1 = ConstantValueHi();
- int32_t val2 = incoming_type.ConstantValueHi();
+ const ConstantType& type1 = *down_cast<const ConstantType*>(this);
+ const ConstantType& type2 = *down_cast<const ConstantType*>(&incoming_type);
+ int32_t val1 = type1.ConstantValueHi();
+ int32_t val2 = type2.ConstantValueHi();
return reg_types->FromCat2ConstHi(val1 | val2, false);
} else if (IsIntegralTypes() && incoming_type.IsIntegralTypes()) {
if (IsBooleanTypes() && incoming_type.IsBooleanTypes()) {
@@ -889,12 +698,12 @@ const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_ty
// Something that is uninitialized hasn't had its constructor called. Mark any merge
// of this type with something that is initialized as conflicting. The cases of a merge
// with itself, 0 or Object are handled above.
- return reg_types->Conflict();
+ return conflict;
} else { // Two reference types, compute Join
mirror::Class* c1 = GetClass();
mirror::Class* c2 = incoming_type.GetClass();
- DCHECK(c1 != NULL && !c1->IsPrimitive());
- DCHECK(c2 != NULL && !c2->IsPrimitive());
+ DCHECK(c1 != nullptr && !c1->IsPrimitive());
+ DCHECK(c2 != nullptr && !c2->IsPrimitive());
mirror::Class* join_class = ClassJoin(c1, c2);
if (c1 == join_class && !IsPreciseReference()) {
return *this;
@@ -906,7 +715,7 @@ const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_ty
}
}
} else {
- return reg_types->Conflict(); // Unexpected types => Conflict
+ return conflict; // Unexpected types => Conflict
}
}
@@ -933,7 +742,7 @@ mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) {
mirror::Class* common_elem = ClassJoin(s_ct, t_ct);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* array_class = class_linker->FindArrayClass(Thread::Current(), &common_elem);
- DCHECK(array_class != NULL);
+ DCHECK(array_class != nullptr);
return array_class;
} else {
size_t s_depth = s->Depth();
@@ -969,7 +778,7 @@ void RegType::CheckInvariants() const {
}
}
-void RegType::VisitRoots(RootCallback* callback, void* arg) {
+void RegType::VisitRoots(RootCallback* callback, void* arg) const {
if (!klass_.IsNull()) {
callback(reinterpret_cast<mirror::Object**>(&klass_), arg, 0, kRootUnknown);
}
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 378b4c97dd..d429dfd411 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -60,7 +60,9 @@ class RegType {
virtual bool IsUninitializedReference() const { return false; }
virtual bool IsUninitializedThisReference() const { return false; }
virtual bool IsUnresolvedAndUninitializedReference() const { return false; }
- virtual bool IsUnresolvedAndUninitializedThisReference() const { return false; }
+ virtual bool IsUnresolvedAndUninitializedThisReference() const {
+ return false;
+ }
virtual bool IsUnresolvedMergedReference() const { return false; }
virtual bool IsUnresolvedSuperClass() const { return false; }
virtual bool IsReference() const { return false; }
@@ -73,90 +75,64 @@ class RegType {
virtual bool IsImpreciseConstant() const { return false; }
virtual bool IsConstantTypes() const { return false; }
bool IsConstant() const {
- return IsPreciseConstant() || IsImpreciseConstant();
+ return IsImpreciseConstant() || IsPreciseConstant();
}
bool IsConstantLo() const {
- return IsPreciseConstantLo() || IsImpreciseConstantLo();
+ return IsImpreciseConstantLo() || IsPreciseConstantLo();
}
bool IsPrecise() const {
- return IsPreciseConstantLo() || IsPreciseConstant() || IsPreciseConstantHi();
- }
- bool IsLongConstant() const {
- return IsConstantLo();
+ return IsPreciseConstantLo() || IsPreciseConstant() ||
+ IsPreciseConstantHi();
}
+ bool IsLongConstant() const { return IsConstantLo(); }
bool IsConstantHi() const {
return (IsPreciseConstantHi() || IsImpreciseConstantHi());
}
- bool IsLongConstantHigh() const {
- return IsConstantHi();
- }
+ bool IsLongConstantHigh() const { return IsConstantHi(); }
virtual bool IsUninitializedTypes() const { return false; }
- bool IsUnresolvedTypes() const {
- return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
- IsUnresolvedAndUninitializedThisReference() ||
- IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
- }
+ virtual bool IsUnresolvedTypes() const { return false; }
bool IsLowHalf() const {
- return (IsLongLo() || IsDoubleLo() || IsPreciseConstantLo() ||
- IsImpreciseConstantLo());
+ return (IsLongLo() || IsDoubleLo() || IsPreciseConstantLo() || IsImpreciseConstantLo());
}
bool IsHighHalf() const {
- return (IsLongHi() || IsDoubleHi() || IsPreciseConstantHi() ||
- IsImpreciseConstantHi());
- }
- bool IsLongOrDoubleTypes() const {
- return IsLowHalf();
+ return (IsLongHi() || IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
}
+ bool IsLongOrDoubleTypes() const { return IsLowHalf(); }
// Check this is the low half, and that type_h is its matching high-half.
inline bool CheckWidePair(const RegType& type_h) const {
if (IsLowHalf()) {
- return ((IsPreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
- (IsPreciseConstantLo() && type_h.IsImpreciseConstantHi()) ||
- (IsImpreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
+ return ((IsImpreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
(IsImpreciseConstantLo() && type_h.IsImpreciseConstantHi()) ||
+ (IsPreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
+ (IsPreciseConstantLo() && type_h.IsImpreciseConstantHi()) ||
(IsDoubleLo() && type_h.IsDoubleHi()) ||
(IsLongLo() && type_h.IsLongHi()));
}
return false;
}
// The high half that corresponds to this low half
- const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const RegType& HighHalf(RegTypeCache* cache) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsConstantBoolean() const {
- return IsConstant() && (ConstantValue() >= 0) && (ConstantValue() <= 1);
- }
- virtual bool IsConstantChar() const {
- return false;
- }
- virtual bool IsConstantByte() const {
- return false;
- }
- virtual bool IsConstantShort() const {
- return false;
- }
- virtual bool IsOne() const {
- return false;
- }
- virtual bool IsZero() const {
- return false;
- }
+ bool IsConstantBoolean() const;
+ virtual bool IsConstantChar() const { return false; }
+ virtual bool IsConstantByte() const { return false; }
+ virtual bool IsConstantShort() const { return false; }
+ virtual bool IsOne() const { return false; }
+ virtual bool IsZero() const { return false; }
bool IsReferenceTypes() const {
return IsNonZeroReferenceTypes() || IsZero();
}
- virtual bool IsNonZeroReferenceTypes() const {
- return false;
- }
+ virtual bool IsNonZeroReferenceTypes() const { return false; }
bool IsCategory1Types() const {
- return IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() || IsShort() ||
- IsBoolean();
+ return IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() ||
+ IsShort() || IsBoolean();
}
bool IsCategory2Types() const {
return IsLowHalf(); // Don't expect explicit testing of high halves
}
- bool IsBooleanTypes() const {
- return IsBoolean() || IsConstantBoolean();
- }
+ bool IsBooleanTypes() const { return IsBoolean() || IsConstantBoolean(); }
bool IsByteTypes() const {
return IsConstantByte() || IsByte() || IsBoolean();
}
@@ -167,48 +143,40 @@ class RegType {
return IsChar() || IsBooleanTypes() || IsConstantChar();
}
bool IsIntegralTypes() const {
- return IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean();
- }
- // Give the constant value encoded, but this shouldn't be called in the general case.
- virtual int32_t ConstantValue() const;
- virtual int32_t ConstantValueLo() const;
- virtual int32_t ConstantValueHi() const;
- bool IsArrayIndexTypes() const {
- return IsIntegralTypes();
+ return IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() ||
+ IsBoolean();
}
+ // Give the constant value encoded, but this shouldn't be called in the
+ // general case.
+ bool IsArrayIndexTypes() const { return IsIntegralTypes(); }
// Float type may be derived from any constant type
- bool IsFloatTypes() const {
- return IsFloat() || IsConstant();
- }
- bool IsLongTypes() const {
- return IsLongLo() || IsLongConstant();
- }
+ bool IsFloatTypes() const { return IsFloat() || IsConstant(); }
+ bool IsLongTypes() const { return IsLongLo() || IsLongConstant(); }
bool IsLongHighTypes() const {
- return (IsLongHi() ||
- IsPreciseConstantHi() ||
- IsImpreciseConstantHi());
- }
- bool IsDoubleTypes() const {
- return IsDoubleLo() || IsLongConstant();
+ return (IsLongHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
}
+ bool IsDoubleTypes() const { return IsDoubleLo() || IsLongConstant(); }
bool IsDoubleHighTypes() const {
return (IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
}
- virtual bool IsLong() const {
- return false;
- }
- virtual bool HasClass() const {
- return false;
+ virtual bool IsLong() const { return false; }
+ bool HasClass() const {
+ bool result = !klass_.IsNull();
+ DCHECK_EQ(result, HasClassVirtual());
+ return result;
}
+ virtual bool HasClassVirtual() const { return false; }
bool IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsObjectArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Primitive::Type GetPrimitiveType() const;
- bool IsJavaLangObjectArray() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsJavaLangObjectArray() const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsInstantiableTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const std::string& GetDescriptor() const {
- DCHECK(HasClass() || (IsUnresolvedTypes() && !IsUnresolvedMergedReference() &&
- !IsUnresolvedSuperClass()));
+ DCHECK(HasClass() ||
+ (IsUnresolvedTypes() && !IsUnresolvedMergedReference() &&
+ !IsUnresolvedSuperClass()));
return descriptor_;
}
mirror::Class* GetClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -217,53 +185,65 @@ class RegType {
DCHECK(HasClass());
return klass_.Read();
}
- uint16_t GetId() const {
- return cache_id_;
- }
+ uint16_t GetId() const { return cache_id_; }
const RegType& GetSuperClass(RegTypeCache* cache) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+ virtual std::string Dump() const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
// Can this type access other?
- bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool CanAccess(const RegType& other) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Can this type access a member with the given properties?
bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Can this type be assigned by src?
- // Note: Object and interface types may always be assigned to one another, see comment on
+ // Note: Object and interface types may always be assigned to one another, see
+ // comment on
// ClassJoin.
- bool IsAssignableFrom(const RegType& src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsAssignableFrom(const RegType& src) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't allow assignment to
+ // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't
+ // allow assignment to
// an interface from an Object.
bool IsStrictlyAssignableFrom(const RegType& src) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Are these RegTypes the same?
- bool Equals(const RegType& other) const {
- return GetId() == other.GetId();
- }
+ bool Equals(const RegType& other) const { return GetId() == other.GetId(); }
- // Compute the merge of this register from one edge (path) with incoming_type from another.
- virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
+ // Compute the merge of this register from one edge (path) with incoming_type
+ // from another.
+ const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
- * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
- * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
- * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+ * A basic Join operation on classes. For a pair of types S and T the Join,
+ *written S v T = J, is
+ * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is
+ *J is the parent of
+ * S and T such that there isn't a parent of both S and T that isn't also the
+ *parent of J (ie J
* is the deepest (lowest upper bound) parent of S and T).
*
- * This operation applies for regular classes and arrays, however, for interface types there
- * needn't be a partial ordering on the types. We could solve the problem of a lack of a partial
- * order by introducing sets of types, however, the only operation permissible on an interface is
- * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
- * types until an invoke-interface call on the interface typed reference at runtime and allow
- * the perversion of Object being assignable to an interface type (note, however, that we don't
- * allow assignment of Object or Interface to any concrete class and are therefore type safe).
+ * This operation applies for regular classes and arrays, however, for
+ *interface types there
+ * needn't be a partial ordering on the types. We could solve the problem of a
+ *lack of a partial
+ * order by introducing sets of types, however, the only operation permissible
+ *on an interface is
+ * invoke-interface. In the tradition of Java verifiers [1] we defer the
+ *verification of interface
+ * types until an invoke-interface call on the interface typed reference at
+ *runtime and allow
+ * the perversion of Object being assignable to an interface type (note,
+ *however, that we don't
+ * allow assignment of Object or Interface to any concrete class and are
+ *therefore type safe).
*
* [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
*/
@@ -272,11 +252,12 @@ class RegType {
virtual ~RegType() {}
- void VisitRoots(RootCallback* callback, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VisitRoots(RootCallback* callback, void* arg) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ RegType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
if (kIsDebugBuild) {
CheckInvariants();
@@ -285,414 +266,402 @@ class RegType {
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
const std::string descriptor_;
- mutable GcRoot<mirror::Class> klass_; // Non-const only due to moving classes.
+ mutable GcRoot<mirror::Class>
+ klass_; // Non-const only due to moving classes.
const uint16_t cache_id_;
friend class RegTypeCache;
private:
+ static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
DISALLOW_COPY_AND_ASSIGN(RegType);
};
// Bottom type.
-class ConflictType : public RegType {
+class ConflictType FINAL : public RegType {
public:
- bool IsConflict() const {
- return true;
- }
+ bool IsConflict() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Get the singleton Conflict instance.
- static ConflictType* GetInstance();
+ static const ConflictType* GetInstance() PURE;
// Create the singleton instance.
- static ConflictType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ static const ConflictType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Destroy the singleton instance.
static void Destroy();
private:
- ConflictType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : RegType(klass, descriptor, cache_id) {
- }
+ ConflictType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {}
- static ConflictType* instance_;
+ static const ConflictType* instance_;
};
-// A variant of the bottom type used to specify an undefined value in the incoming registers.
+// A variant of the bottom type used to specify an undefined value in the
+// incoming registers.
// Merging with UndefinedType yields ConflictType which is the true bottom.
-class UndefinedType : public RegType {
+class UndefinedType FINAL : public RegType {
public:
- bool IsUndefined() const {
- return true;
- }
+ bool IsUndefined() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Get the singleton Undefined instance.
- static UndefinedType* GetInstance();
+ static const UndefinedType* GetInstance() PURE;
// Create the singleton instance.
- static UndefinedType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ static const UndefinedType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Destroy the singleton instance.
static void Destroy();
private:
- UndefinedType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : RegType(klass, descriptor, cache_id) {
- }
-
- virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ UndefinedType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {}
- static UndefinedType* instance_;
+ static const UndefinedType* instance_;
};
class PrimitiveType : public RegType {
public:
- PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ PrimitiveType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
class Cat1Type : public PrimitiveType {
public:
- Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ Cat1Type(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
class IntegerType : public Cat1Type {
public:
- bool IsInteger() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static IntegerType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ bool IsInteger() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static const IntegerType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static IntegerType* GetInstance();
+ static const IntegerType* GetInstance() PURE;
static void Destroy();
+
private:
- IntegerType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {
- }
- static IntegerType* instance_;
+ IntegerType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {}
+ static const IntegerType* instance_;
};
-class BooleanType : public Cat1Type {
+class BooleanType FINAL : public Cat1Type {
public:
- bool IsBoolean() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static BooleanType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ bool IsBoolean() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static const BooleanType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static BooleanType* GetInstance();
+ static const BooleanType* GetInstance() PURE;
static void Destroy();
+
private:
- BooleanType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {
- }
+ BooleanType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {}
- static BooleanType* instance;
+ static const BooleanType* instance_;
};
-class ByteType : public Cat1Type {
+class ByteType FINAL : public Cat1Type {
public:
- bool IsByte() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ByteType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ bool IsByte() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static const ByteType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ByteType* GetInstance();
+ static const ByteType* GetInstance() PURE;
static void Destroy();
+
private:
- ByteType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {
- }
- static ByteType* instance_;
+ ByteType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {}
+ static const ByteType* instance_;
};
-class ShortType : public Cat1Type {
+class ShortType FINAL : public Cat1Type {
public:
- bool IsShort() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ShortType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ bool IsShort() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static const ShortType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ShortType* GetInstance();
+ static const ShortType* GetInstance() PURE;
static void Destroy();
+
private:
- ShortType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {
- }
- static ShortType* instance_;
+ ShortType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {}
+ static const ShortType* instance_;
};
-class CharType : public Cat1Type {
+class CharType FINAL : public Cat1Type {
public:
- bool IsChar() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static CharType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ bool IsChar() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static const CharType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static CharType* GetInstance();
+ static const CharType* GetInstance() PURE;
static void Destroy();
+
private:
- CharType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {
- }
- static CharType* instance_;
+ CharType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {}
+ static const CharType* instance_;
};
-class FloatType : public Cat1Type {
+class FloatType FINAL : public Cat1Type {
public:
- bool IsFloat() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static FloatType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ bool IsFloat() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static const FloatType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static FloatType* GetInstance();
+ static const FloatType* GetInstance() PURE;
static void Destroy();
+
private:
- FloatType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat1Type(klass, descriptor, cache_id) {
- }
- static FloatType* instance_;
+ FloatType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {}
+ static const FloatType* instance_;
};
class Cat2Type : public PrimitiveType {
public:
- Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ Cat2Type(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class LongLoType : public Cat2Type {
+class LongLoType FINAL : public Cat2Type {
public:
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsLongLo() const {
- return true;
- }
- bool IsLong() const {
- return true;
- }
- static LongLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsLongLo() const OVERRIDE { return true; }
+ bool IsLong() const OVERRIDE { return true; }
+ static const LongLoType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static LongLoType* GetInstance();
+ static const LongLoType* GetInstance() PURE;
static void Destroy();
+
private:
- LongLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {
- }
- static LongLoType* instance_;
+ LongLoType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {}
+ static const LongLoType* instance_;
};
-class LongHiType : public Cat2Type {
+class LongHiType FINAL : public Cat2Type {
public:
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsLongHi() const {
- return true;
- }
- static LongHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsLongHi() const OVERRIDE { return true; }
+ static const LongHiType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static LongHiType* GetInstance();
+ static const LongHiType* GetInstance() PURE;
static void Destroy();
+
private:
- LongHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {
- }
- static LongHiType* instance_;
+ LongHiType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {}
+ static const LongHiType* instance_;
};
-class DoubleLoType : public Cat2Type {
+class DoubleLoType FINAL : public Cat2Type {
public:
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsDoubleLo() const {
- return true;
- }
- bool IsDouble() const {
- return true;
- }
- static DoubleLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
- uint16_t cache_id)
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsDoubleLo() const OVERRIDE { return true; }
+ bool IsDouble() const OVERRIDE { return true; }
+ static const DoubleLoType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static DoubleLoType* GetInstance();
+ static const DoubleLoType* GetInstance() PURE;
static void Destroy();
+
private:
- DoubleLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {
- }
- static DoubleLoType* instance_;
+ DoubleLoType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {}
+ static const DoubleLoType* instance_;
};
-class DoubleHiType : public Cat2Type {
+class DoubleHiType FINAL : public Cat2Type {
public:
- std::string Dump() const;
- virtual bool IsDoubleHi() const {
- return true;
- }
- static DoubleHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ virtual bool IsDoubleHi() const OVERRIDE { return true; }
+ static const DoubleHiType* CreateInstance(mirror::Class* klass,
+ const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static DoubleHiType* GetInstance();
+ static const DoubleHiType* GetInstance() PURE;
static void Destroy();
+
private:
- DoubleHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : Cat2Type(klass, descriptor, cache_id) {
- }
- static DoubleHiType* instance_;
+ DoubleHiType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {}
+ static const DoubleHiType* instance_;
};
class ConstantType : public RegType {
public:
- ConstantType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ConstantType(uint32_t constant, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(nullptr, "", cache_id), constant_(constant) {
+ }
- // If this is a 32-bit constant, what is the value? This value may be imprecise in which case
- // the value represents part of the integer range of values that may be held in the register.
+
+ // If this is a 32-bit constant, what is the value? This value may be
+ // imprecise in which case
+ // the value represents part of the integer range of values that may be held
+ // in the register.
int32_t ConstantValue() const {
DCHECK(IsConstantTypes());
return constant_;
}
- int32_t ConstantValueLo() const;
- int32_t ConstantValueHi() const;
- bool IsZero() const {
+ int32_t ConstantValueLo() const {
+ DCHECK(IsConstantLo());
+ return constant_;
+ }
+
+ int32_t ConstantValueHi() const {
+ if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) {
+ return constant_;
+ } else {
+ DCHECK(false);
+ return 0;
+ }
+ }
+
+ bool IsZero() const OVERRIDE {
return IsPreciseConstant() && ConstantValue() == 0;
}
- bool IsOne() const {
+ bool IsOne() const OVERRIDE {
return IsPreciseConstant() && ConstantValue() == 1;
}
- bool IsConstantChar() const {
+ bool IsConstantChar() const OVERRIDE {
return IsConstant() && ConstantValue() >= 0 &&
ConstantValue() <= std::numeric_limits<jchar>::max();
}
- bool IsConstantByte() const {
+ bool IsConstantByte() const OVERRIDE {
return IsConstant() &&
ConstantValue() >= std::numeric_limits<jbyte>::min() &&
ConstantValue() <= std::numeric_limits<jbyte>::max();
}
- bool IsConstantShort() const {
+ bool IsConstantShort() const OVERRIDE {
return IsConstant() &&
ConstantValue() >= std::numeric_limits<jshort>::min() &&
ConstantValue() <= std::numeric_limits<jshort>::max();
}
- virtual bool IsConstantTypes() const { return true; }
+ virtual bool IsConstantTypes() const OVERRIDE { return true; }
private:
const uint32_t constant_;
};
-class PreciseConstType : public ConstantType {
+class PreciseConstType FINAL : public ConstantType {
public:
- PreciseConstType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : ConstantType(constat, cache_id) {
- }
+ PreciseConstType(uint32_t constant, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : ConstantType(constant, cache_id) {}
- bool IsPreciseConstant() const {
- return true;
- }
+ bool IsPreciseConstant() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class PreciseConstLoType : public ConstantType {
+class PreciseConstLoType FINAL : public ConstantType {
public:
- PreciseConstLoType(uint32_t constat, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : ConstantType(constat, cache_id) {
- }
- bool IsPreciseConstantLo() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ PreciseConstLoType(uint32_t constant, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : ConstantType(constant, cache_id) {}
+ bool IsPreciseConstantLo() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class PreciseConstHiType : public ConstantType {
+class PreciseConstHiType FINAL : public ConstantType {
public:
- PreciseConstHiType(uint32_t constat, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : ConstantType(constat, cache_id) {
- }
- bool IsPreciseConstantHi() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ PreciseConstHiType(uint32_t constant, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : ConstantType(constant, cache_id) {}
+ bool IsPreciseConstantHi() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class ImpreciseConstType : public ConstantType {
+class ImpreciseConstType FINAL : public ConstantType {
public:
ImpreciseConstType(uint32_t constat, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsImpreciseConstant() const {
- return true;
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : ConstantType(constat, cache_id) {
}
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool IsImpreciseConstant() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class ImpreciseConstLoType : public ConstantType {
+class ImpreciseConstLoType FINAL : public ConstantType {
public:
- ImpreciseConstLoType(uint32_t constat, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : ConstantType(constat, cache_id) {
- }
- bool IsImpreciseConstantLo() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ImpreciseConstLoType(uint32_t constant, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : ConstantType(constant, cache_id) {}
+ bool IsImpreciseConstantLo() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class ImpreciseConstHiType : public ConstantType {
+class ImpreciseConstHiType FINAL : public ConstantType {
public:
- ImpreciseConstHiType(uint32_t constat, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : ConstantType(constat, cache_id) {
- }
- bool IsImpreciseConstantHi() const {
- return true;
- }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ImpreciseConstHiType(uint32_t constant, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : ConstantType(constant, cache_id) {}
+ bool IsImpreciseConstantHi() const OVERRIDE { return true; }
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-// Common parent of all uninitialized types. Uninitialized types are created by "new" dex
+// Common parent of all uninitialized types. Uninitialized types are created by
+// "new" dex
// instructions and must be passed to a constructor.
class UninitializedType : public RegType {
public:
- UninitializedType(mirror::Class* klass, const std::string& descriptor, uint32_t allocation_pc,
- uint16_t cache_id)
- : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
- }
+ UninitializedType(mirror::Class* klass, const std::string& descriptor,
+ uint32_t allocation_pc, uint16_t cache_id)
+ : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {}
- bool IsUninitializedTypes() const;
- bool IsNonZeroReferenceTypes() const;
+ bool IsUninitializedTypes() const OVERRIDE;
+ bool IsNonZeroReferenceTypes() const OVERRIDE;
uint32_t GetAllocationPc() const {
DCHECK(IsUninitializedTypes());
@@ -704,30 +673,27 @@ class UninitializedType : public RegType {
};
// Similar to ReferenceType but not yet having been passed to a constructor.
-class UninitializedReferenceType : public UninitializedType {
+class UninitializedReferenceType FINAL : public UninitializedType {
public:
- UninitializedReferenceType(mirror::Class* klass, const std::string& descriptor,
+ UninitializedReferenceType(mirror::Class* klass,
+ const std::string& descriptor,
uint32_t allocation_pc, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
- }
+ : UninitializedType(klass, descriptor, allocation_pc, cache_id) {}
- bool IsUninitializedReference() const {
- return true;
- }
+ bool IsUninitializedReference() const OVERRIDE { return true; }
- bool HasClass() const {
- return true;
- }
+ bool HasClassVirtual() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-// Similar to UnresolvedReferenceType but not yet having been passed to a constructor.
-class UnresolvedUninitializedRefType : public UninitializedType {
+// Similar to UnresolvedReferenceType but not yet having been passed to a
+// constructor.
+class UnresolvedUninitializedRefType FINAL : public UninitializedType {
public:
- UnresolvedUninitializedRefType(const std::string& descriptor, uint32_t allocation_pc,
- uint16_t cache_id)
+ UnresolvedUninitializedRefType(const std::string& descriptor,
+ uint32_t allocation_pc, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
if (kIsDebugBuild) {
@@ -735,19 +701,22 @@ class UnresolvedUninitializedRefType : public UninitializedType {
}
}
- bool IsUnresolvedAndUninitializedReference() const {
- return true;
- }
+ bool IsUnresolvedAndUninitializedReference() const OVERRIDE { return true; }
+
+ bool IsUnresolvedTypes() const OVERRIDE { return true; }
+
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-// Similar to UninitializedReferenceType but special case for the this argument of a constructor.
-class UninitializedThisReferenceType : public UninitializedType {
+// Similar to UninitializedReferenceType but special case for the this argument
+// of a constructor.
+class UninitializedThisReferenceType FINAL : public UninitializedType {
public:
- UninitializedThisReferenceType(mirror::Class* klass, const std::string& descriptor,
+ UninitializedThisReferenceType(mirror::Class* klass,
+ const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: UninitializedType(klass, descriptor, 0, cache_id) {
@@ -756,23 +725,20 @@ class UninitializedThisReferenceType : public UninitializedType {
}
}
- virtual bool IsUninitializedThisReference() const {
- return true;
- }
+ virtual bool IsUninitializedThisReference() const OVERRIDE { return true; }
- bool HasClass() const {
- return true;
- }
+ bool HasClassVirtual() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class UnresolvedUninitializedThisRefType : public UninitializedType {
+class UnresolvedUninitializedThisRefType FINAL : public UninitializedType {
public:
- UnresolvedUninitializedThisRefType(const std::string& descriptor, uint16_t cache_id)
+ UnresolvedUninitializedThisRefType(const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: UninitializedType(NULL, descriptor, 0, cache_id) {
if (kIsDebugBuild) {
@@ -780,112 +746,108 @@ class UnresolvedUninitializedThisRefType : public UninitializedType {
}
}
- bool IsUnresolvedAndUninitializedThisReference() const {
- return true;
- }
+ bool IsUnresolvedAndUninitializedThisReference() const OVERRIDE { return true; }
+
+ bool IsUnresolvedTypes() const OVERRIDE { return true; }
+
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-// A type of register holding a reference to an Object of type GetClass or a sub-class.
-class ReferenceType : public RegType {
+// A type of register holding a reference to an Object of type GetClass or a
+// sub-class.
+class ReferenceType FINAL : public RegType {
public:
- ReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : RegType(klass, descriptor, cache_id) {
- }
+ ReferenceType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {}
- bool IsReference() const {
- return true;
- }
+ bool IsReference() const OVERRIDE { return true; }
- bool IsNonZeroReferenceTypes() const {
- return true;
- }
+ bool IsNonZeroReferenceTypes() const OVERRIDE { return true; }
- bool HasClass() const {
- return true;
- }
+ bool HasClassVirtual() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-// A type of register holding a reference to an Object of type GetClass and only an object of that
+// A type of register holding a reference to an Object of type GetClass and only
+// an object of that
// type.
-class PreciseReferenceType : public RegType {
+class PreciseReferenceType FINAL : public RegType {
public:
- PreciseReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ PreciseReferenceType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsPreciseReference() const {
- return true;
- }
+ bool IsPreciseReference() const OVERRIDE { return true; }
- bool IsNonZeroReferenceTypes() const {
- return true;
- }
+ bool IsNonZeroReferenceTypes() const OVERRIDE { return true; }
- bool HasClass() const {
- return true;
- }
+ bool HasClassVirtual() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
// Common parent of unresolved types.
class UnresolvedType : public RegType {
public:
UnresolvedType(const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(NULL, descriptor, cache_id) {}
- bool IsNonZeroReferenceTypes() const;
+ bool IsNonZeroReferenceTypes() const OVERRIDE;
};
-// Similar to ReferenceType except the Class couldn't be loaded. Assignability and other tests made
+// Similar to ReferenceType except the Class couldn't be loaded. Assignability
+// and other tests made
// of this type must be conservative.
-class UnresolvedReferenceType : public UnresolvedType {
+class UnresolvedReferenceType FINAL : public UnresolvedType {
public:
UnresolvedReferenceType(const std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : UnresolvedType(descriptor, cache_id) {
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : UnresolvedType(descriptor, cache_id) {
if (kIsDebugBuild) {
CheckInvariants();
}
}
- bool IsUnresolvedReference() const {
- return true;
- }
+ bool IsUnresolvedReference() const OVERRIDE { return true; }
+
+ bool IsUnresolvedTypes() const OVERRIDE { return true; }
+
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
// Type representing the super-class of an unresolved type.
-class UnresolvedSuperClass : public UnresolvedType {
+class UnresolvedSuperClass FINAL : public UnresolvedType {
public:
- UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache, uint16_t cache_id)
+ UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : UnresolvedType("", cache_id), unresolved_child_id_(child_id),
+ : UnresolvedType("", cache_id),
+ unresolved_child_id_(child_id),
reg_type_cache_(reg_type_cache) {
if (kIsDebugBuild) {
CheckInvariants();
}
}
- bool IsUnresolvedSuperClass() const {
- return true;
- }
+ bool IsUnresolvedSuperClass() const OVERRIDE { return true; }
+
+ bool IsUnresolvedTypes() const OVERRIDE { return true; }
uint16_t GetUnresolvedSuperClassChildId() const {
DCHECK(IsUnresolvedSuperClass());
return static_cast<uint16_t>(unresolved_child_id_ & 0xFFFF);
}
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -894,14 +856,17 @@ class UnresolvedSuperClass : public UnresolvedType {
const RegTypeCache* const reg_type_cache_;
};
-// A merge of two unresolved types. If the types were resolved this may be Conflict or another
+// A merge of two unresolved types. If the types were resolved this may be
+// Conflict or another
// known ReferenceType.
-class UnresolvedMergedType : public UnresolvedType {
+class UnresolvedMergedType FINAL : public UnresolvedType {
public:
- UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache,
- uint16_t cache_id)
+ UnresolvedMergedType(uint16_t left_id, uint16_t right_id,
+ const RegTypeCache* reg_type_cache, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : UnresolvedType("", cache_id), reg_type_cache_(reg_type_cache), merged_types_(left_id, right_id) {
+ : UnresolvedType("", cache_id),
+ reg_type_cache_(reg_type_cache),
+ merged_types_(left_id, right_id) {
if (kIsDebugBuild) {
CheckInvariants();
}
@@ -916,11 +881,11 @@ class UnresolvedMergedType : public UnresolvedType {
// The complete set of merged types.
std::set<uint16_t> GetMergedTypes() const;
- bool IsUnresolvedMergedReference() const {
- return true;
- }
+ bool IsUnresolvedMergedReference() const OVERRIDE { return true; }
+
+ bool IsUnresolvedTypes() const OVERRIDE { return true; }
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index fc9e5c98f7..9024a7dd03 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -17,16 +17,19 @@
#ifndef ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_
#define ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_
+#include "class_linker.h"
+#include "mirror/class-inl.h"
+#include "mirror/string.h"
+#include "mirror/throwable.h"
#include "reg_type.h"
#include "reg_type_cache.h"
-#include "class_linker.h"
namespace art {
namespace verifier {
inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
DCHECK_LT(id, entries_.size());
- RegType* result = entries_[id];
+ const RegType* result = entries_[id];
DCHECK(result != NULL);
return *result;
}
@@ -40,6 +43,81 @@ inline const ConstantType& RegTypeCache::FromCat1Const(int32_t value, bool preci
return FromCat1NonSmallConstant(value, precise);
}
+inline const ImpreciseConstType& RegTypeCache::ByteConstant() {
+ const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false);
+ DCHECK(result.IsImpreciseConstant());
+ return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+inline const ImpreciseConstType& RegTypeCache::CharConstant() {
+ int32_t jchar_max = static_cast<int32_t>(std::numeric_limits<jchar>::max());
+ const ConstantType& result = FromCat1Const(jchar_max, false);
+ DCHECK(result.IsImpreciseConstant());
+ return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+inline const ImpreciseConstType& RegTypeCache::ShortConstant() {
+ const ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::min(), false);
+ DCHECK(result.IsImpreciseConstant());
+ return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+inline const ImpreciseConstType& RegTypeCache::IntConstant() {
+ const ConstantType& result = FromCat1Const(std::numeric_limits<jint>::max(), false);
+ DCHECK(result.IsImpreciseConstant());
+ return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+inline const ImpreciseConstType& RegTypeCache::PosByteConstant() {
+ const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::max(), false);
+ DCHECK(result.IsImpreciseConstant());
+ return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+inline const ImpreciseConstType& RegTypeCache::PosShortConstant() {
+ const ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::max(), false);
+ DCHECK(result.IsImpreciseConstant());
+ return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+inline const PreciseReferenceType& RegTypeCache::JavaLangClass() {
+ const RegType* result = &FromClass("Ljava/lang/Class;", mirror::Class::GetJavaLangClass(), true);
+ DCHECK(result->IsPreciseReference());
+ return *down_cast<const PreciseReferenceType*>(result);
+}
+
+inline const PreciseReferenceType& RegTypeCache::JavaLangString() {
+ // String is final and therefore always precise.
+ const RegType* result = &FromClass("Ljava/lang/String;", mirror::String::GetJavaLangString(),
+ true);
+ DCHECK(result->IsPreciseReference());
+ return *down_cast<const PreciseReferenceType*>(result);
+}
+
+inline const RegType& RegTypeCache::JavaLangThrowable(bool precise) {
+ const RegType* result = &FromClass("Ljava/lang/Throwable;",
+ mirror::Throwable::GetJavaLangThrowable(), precise);
+ if (precise) {
+ DCHECK(result->IsPreciseReference());
+ return *down_cast<const PreciseReferenceType*>(result);
+ } else {
+ DCHECK(result->IsReference());
+ return *down_cast<const ReferenceType*>(result);
+ }
+}
+
+inline const RegType& RegTypeCache::JavaLangObject(bool precise) {
+ const RegType* result = &FromClass("Ljava/lang/Object;",
+ mirror::Class::GetJavaLangClass()->GetSuperClass(), precise);
+ if (precise) {
+ DCHECK(result->IsPreciseReference());
+ return *down_cast<const PreciseReferenceType*>(result);
+ } else {
+ DCHECK(result->IsReference());
+ return *down_cast<const ReferenceType*>(result);
+ }
+}
+
} // namespace verifier
} // namespace art
#endif // ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 92a005b366..121fccb994 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -21,15 +21,16 @@
#include "dex_file-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
+#include "reg_type-inl.h"
namespace art {
namespace verifier {
bool RegTypeCache::primitive_initialized_ = false;
uint16_t RegTypeCache::primitive_count_ = 0;
-PreciseConstType* RegTypeCache::small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1];
+const PreciseConstType* RegTypeCache::small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1];
-static bool MatchingPrecisionForClass(RegType* entry, bool precise)
+static bool MatchingPrecisionForClass(const RegType* entry, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (entry->IsPreciseReference() == precise) {
// We were or weren't looking for a precise reference and we found what we need.
@@ -98,7 +99,7 @@ const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const c
};
const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
- CHECK(RegTypeCache::primitive_initialized_);
+ DCHECK(RegTypeCache::primitive_initialized_);
switch (prim_type) {
case Primitive::kPrimBoolean:
return *BooleanType::GetInstance();
@@ -123,7 +124,7 @@ const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type)
}
bool RegTypeCache::MatchDescriptor(size_t idx, const StringPiece& descriptor, bool precise) {
- RegType* entry = entries_[idx];
+ const RegType* entry = entries_[idx];
if (descriptor != entry->descriptor_) {
return false;
}
@@ -143,11 +144,11 @@ mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassL
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(loader));
- mirror::Class* klass = NULL;
+ mirror::Class* klass = nullptr;
if (can_load_classes_) {
klass = class_linker->FindClass(self, descriptor, class_loader);
} else {
- klass = class_linker->LookupClass(descriptor, loader);
+ klass = class_linker->LookupClass(self, descriptor, loader);
if (klass != nullptr && !klass->IsLoaded()) {
// We found the class but without it being loaded its not safe for use.
klass = nullptr;
@@ -169,7 +170,7 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descr
// Class not found in the cache, will create a new type for that.
// Try resolving class.
mirror::Class* klass = ResolveClass(descriptor, loader);
- if (klass != NULL) {
+ if (klass != nullptr) {
// Class resolved, first look for the class in the list of entries
// Class was not found, must create new type.
// To pass the verification, the type should be imprecise,
@@ -219,7 +220,7 @@ const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* kl
} else {
// Look for the reference in the list of entries to have.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->klass_.Read() == klass && MatchingPrecisionForClass(cur_entry, precise)) {
return *cur_entry;
}
@@ -237,8 +238,8 @@ const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* kl
}
RegTypeCache::RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
- if (kIsDebugBuild && can_load_classes) {
- Thread::Current()->AssertThreadSuspensionIsAllowable();
+ if (kIsDebugBuild) {
+ Thread::Current()->AssertThreadSuspensionIsAllowable(gAborting == 0);
}
entries_.reserve(64);
FillPrimitiveAndSmallConstantTypes();
@@ -251,7 +252,7 @@ RegTypeCache::~RegTypeCache() {
// All entries are from the global pool, nothing to delete.
return;
}
- std::vector<RegType*>::iterator non_primitive_begin = entries_.begin();
+ std::vector<const RegType*>::iterator non_primitive_begin = entries_.begin();
std::advance(non_primitive_begin, kNumPrimitivesAndSmallConstants);
STLDeleteContainerPointers(non_primitive_begin, entries_.end());
}
@@ -271,7 +272,7 @@ void RegTypeCache::ShutDown() {
DoubleLoType::Destroy();
DoubleHiType::Destroy();
for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
- PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant];
+ const PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant];
delete type;
small_precise_constants_[value - kMinSmallConstant] = nullptr;
}
@@ -281,14 +282,14 @@ void RegTypeCache::ShutDown() {
}
template <class Type>
-Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) {
- mirror::Class* klass = NULL;
+const Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) {
+ mirror::Class* klass = nullptr;
// Try loading the class from linker.
if (!descriptor.empty()) {
klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
descriptor.c_str());
}
- Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_);
+ const Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_);
RegTypeCache::primitive_count_++;
return entry;
}
@@ -330,10 +331,10 @@ const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left, const RegT
}
// Check if entry already exists.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedMergedReference()) {
std::set<uint16_t> cur_entry_types =
- (down_cast<UnresolvedMergedType*>(cur_entry))->GetMergedTypes();
+ (down_cast<const UnresolvedMergedType*>(cur_entry))->GetMergedTypes();
if (cur_entry_types == types) {
return *cur_entry;
}
@@ -353,10 +354,10 @@ const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left, const RegT
const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
// Check if entry already exists.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedSuperClass()) {
- UnresolvedSuperClass* tmp_entry =
- down_cast<UnresolvedSuperClass*>(cur_entry);
+ const UnresolvedSuperClass* tmp_entry =
+ down_cast<const UnresolvedSuperClass*>(cur_entry);
uint16_t unresolved_super_child_id =
tmp_entry->GetUnresolvedSuperClassChildId();
if (unresolved_super_child_id == child.GetId()) {
@@ -370,27 +371,28 @@ const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
}
const UninitializedType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
- UninitializedType* entry = NULL;
+ UninitializedType* entry = nullptr;
const std::string& descriptor(type.GetDescriptor());
if (type.IsUnresolvedTypes()) {
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedAndUninitializedReference() &&
- down_cast<UnresolvedUninitializedRefType*>(cur_entry)->GetAllocationPc() == allocation_pc &&
+ down_cast<const UnresolvedUninitializedRefType*>(cur_entry)->GetAllocationPc()
+ == allocation_pc &&
(cur_entry->GetDescriptor() == descriptor)) {
- return *down_cast<UnresolvedUninitializedRefType*>(cur_entry);
+ return *down_cast<const UnresolvedUninitializedRefType*>(cur_entry);
}
}
entry = new UnresolvedUninitializedRefType(descriptor, allocation_pc, entries_.size());
} else {
mirror::Class* klass = type.GetClass();
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUninitializedReference() &&
- down_cast<UninitializedReferenceType*>(cur_entry)
+ down_cast<const UninitializedReferenceType*>(cur_entry)
->GetAllocationPc() == allocation_pc &&
cur_entry->GetClass() == klass) {
- return *down_cast<UninitializedReferenceType*>(cur_entry);
+ return *down_cast<const UninitializedReferenceType*>(cur_entry);
}
}
entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size());
@@ -405,7 +407,7 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
if (uninit_type.IsUnresolvedTypes()) {
const std::string& descriptor(uninit_type.GetDescriptor());
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedReference() &&
cur_entry->GetDescriptor() == descriptor) {
return *cur_entry;
@@ -417,7 +419,7 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
// For uninitialized "this reference" look for reference types that are not precise.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
@@ -427,7 +429,7 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
// We're uninitialized because of allocation, look or create a precise type as allocations
// may only create objects of that type.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
@@ -441,61 +443,24 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
return *entry;
}
-const ImpreciseConstType& RegTypeCache::ByteConstant() {
- const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false);
- DCHECK(result.IsImpreciseConstant());
- return *down_cast<const ImpreciseConstType*>(&result);
-}
-
-const ImpreciseConstType& RegTypeCache::CharConstant() {
- int32_t jchar_max = static_cast<int32_t>(std::numeric_limits<jchar>::max());
- const ConstantType& result = FromCat1Const(jchar_max, false);
- DCHECK(result.IsImpreciseConstant());
- return *down_cast<const ImpreciseConstType*>(&result);
-}
-
-const ImpreciseConstType& RegTypeCache::ShortConstant() {
- const ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::min(), false);
- DCHECK(result.IsImpreciseConstant());
- return *down_cast<const ImpreciseConstType*>(&result);
-}
-
-const ImpreciseConstType& RegTypeCache::IntConstant() {
- const ConstantType& result = FromCat1Const(std::numeric_limits<jint>::max(), false);
- DCHECK(result.IsImpreciseConstant());
- return *down_cast<const ImpreciseConstType*>(&result);
-}
-
-const ImpreciseConstType& RegTypeCache::PosByteConstant() {
- const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::max(), false);
- DCHECK(result.IsImpreciseConstant());
- return *down_cast<const ImpreciseConstType*>(&result);
-}
-
-const ImpreciseConstType& RegTypeCache::PosShortConstant() {
- const ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::max(), false);
- DCHECK(result.IsImpreciseConstant());
- return *down_cast<const ImpreciseConstType*>(&result);
-}
-
const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
UninitializedType* entry;
const std::string& descriptor(type.GetDescriptor());
if (type.IsUnresolvedTypes()) {
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
cur_entry->GetDescriptor() == descriptor) {
- return *down_cast<UninitializedType*>(cur_entry);
+ return *down_cast<const UninitializedType*>(cur_entry);
}
}
entry = new UnresolvedUninitializedThisRefType(descriptor, entries_.size());
} else {
mirror::Class* klass = type.GetClass();
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
- return *down_cast<UninitializedType*>(cur_entry);
+ return *down_cast<const UninitializedType*>(cur_entry);
}
}
entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size());
@@ -506,11 +471,11 @@ const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType&
const ConstantType& RegTypeCache::FromCat1NonSmallConstant(int32_t value, bool precise) {
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->klass_.IsNull() && cur_entry->IsConstant() &&
cur_entry->IsPreciseConstant() == precise &&
- (down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) {
- return *down_cast<ConstantType*>(cur_entry);
+ (down_cast<const ConstantType*>(cur_entry))->ConstantValue() == value) {
+ return *down_cast<const ConstantType*>(cur_entry);
}
}
ConstantType* entry;
@@ -525,10 +490,10 @@ const ConstantType& RegTypeCache::FromCat1NonSmallConstant(int32_t value, bool p
const ConstantType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) {
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsConstantLo() && (cur_entry->IsPrecise() == precise) &&
- (down_cast<ConstantType*>(cur_entry))->ConstantValueLo() == value) {
- return *down_cast<ConstantType*>(cur_entry);
+ (down_cast<const ConstantType*>(cur_entry))->ConstantValueLo() == value) {
+ return *down_cast<const ConstantType*>(cur_entry);
}
}
ConstantType* entry;
@@ -543,10 +508,10 @@ const ConstantType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) {
const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
+ const RegType* cur_entry = entries_[i];
if (cur_entry->IsConstantHi() && (cur_entry->IsPrecise() == precise) &&
- (down_cast<ConstantType*>(cur_entry))->ConstantValueHi() == value) {
- return *down_cast<ConstantType*>(cur_entry);
+ (down_cast<const ConstantType*>(cur_entry))->ConstantValueHi() == value) {
+ return *down_cast<const ConstantType*>(cur_entry);
}
}
ConstantType* entry;
@@ -583,15 +548,15 @@ const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::Clas
void RegTypeCache::Dump(std::ostream& os) {
for (size_t i = 0; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
- if (cur_entry != NULL) {
+ const RegType* cur_entry = entries_[i];
+ if (cur_entry != nullptr) {
os << i << ": " << cur_entry->Dump() << "\n";
}
}
}
void RegTypeCache::VisitRoots(RootCallback* callback, void* arg) {
- for (RegType* entry : entries_) {
+ for (const RegType* entry : entries_) {
entry->VisitRoots(callback, arg);
}
}
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 8baf3ff102..eb17a5258f 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -68,14 +68,6 @@ class RegTypeCache {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const RegType& FromUnresolvedSuperClass(const RegType& child)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const RegType& JavaLangString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // String is final and therefore always precise.
- return From(NULL, "Ljava/lang/String;", true);
- }
- const RegType& JavaLangThrowable(bool precise)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return From(NULL, "Ljava/lang/Throwable;", precise);
- }
const ConstantType& Zero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return FromCat1Const(0, true);
}
@@ -85,48 +77,48 @@ class RegTypeCache {
size_t GetCacheSize() {
return entries_.size();
}
- const RegType& Boolean() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const BooleanType& Boolean() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return *BooleanType::GetInstance();
}
- const RegType& Byte() {
+ const ByteType& Byte() {
return *ByteType::GetInstance();
}
- const RegType& Char() {
+ const CharType& Char() {
return *CharType::GetInstance();
}
- const RegType& Short() {
+ const ShortType& Short() {
return *ShortType::GetInstance();
}
- const RegType& Integer() {
+ const IntegerType& Integer() {
return *IntegerType::GetInstance();
}
- const RegType& Float() {
+ const FloatType& Float() {
return *FloatType::GetInstance();
}
- const RegType& LongLo() {
+ const LongLoType& LongLo() {
return *LongLoType::GetInstance();
}
- const RegType& LongHi() {
+ const LongHiType& LongHi() {
return *LongHiType::GetInstance();
}
- const RegType& DoubleLo() {
+ const DoubleLoType& DoubleLo() {
return *DoubleLoType::GetInstance();
}
- const RegType& DoubleHi() {
+ const DoubleHiType& DoubleHi() {
return *DoubleHiType::GetInstance();
}
- const RegType& Undefined() {
+ const UndefinedType& Undefined() {
return *UndefinedType::GetInstance();
}
- const RegType& Conflict() {
+ const ConflictType& Conflict() {
return *ConflictType::GetInstance();
}
- const RegType& JavaLangClass(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return From(NULL, "Ljava/lang/Class;", precise);
- }
- const RegType& JavaLangObject(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return From(NULL, "Ljava/lang/Object;", precise);
- }
+
+ const PreciseReferenceType& JavaLangClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const PreciseReferenceType& JavaLangString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const RegType& JavaLangThrowable(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const RegType& JavaLangObject(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
const UninitializedType& Uninitialized(const RegType& type, uint32_t allocation_pc)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Create an uninitialized 'this' argument for the given type.
@@ -159,17 +151,14 @@ class RegTypeCache {
void AddEntry(RegType* new_entry);
template <class Type>
- static Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
+ static const Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void CreatePrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // The actual storage for the RegTypes.
- std::vector<RegType*> entries_;
-
// A quick look up for popular small constants.
static constexpr int32_t kMinSmallConstant = -1;
static constexpr int32_t kMaxSmallConstant = 4;
- static PreciseConstType* small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1];
+ static const PreciseConstType* small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1];
static constexpr size_t kNumPrimitivesAndSmallConstants =
12 + (kMaxSmallConstant - kMinSmallConstant + 1);
@@ -180,6 +169,9 @@ class RegTypeCache {
// Number of well known primitives that will be copied into a RegTypeCache upon construction.
static uint16_t primitive_count_;
+ // The actual storage for the RegTypes.
+ std::vector<const RegType*> entries_;
+
// Whether or not we're allowed to load classes.
const bool can_load_classes_;
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index 9dc0df13fb..aad3b5ab99 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -21,6 +21,7 @@
#include "base/casts.h"
#include "common_runtime_test.h"
#include "reg_type_cache-inl.h"
+#include "reg_type-inl.h"
#include "scoped_thread_state_change.h"
#include "thread-inl.h"
@@ -346,7 +347,7 @@ TEST_F(RegTypeReferenceTest, JavalangObjectImprecise) {
RegTypeCache cache(true);
const RegType& imprecise_obj = cache.JavaLangObject(false);
const RegType& precise_obj = cache.JavaLangObject(true);
- const RegType& precise_obj_2 = cache.FromDescriptor(NULL, "Ljava/lang/Object;", true);
+ const RegType& precise_obj_2 = cache.FromDescriptor(nullptr, "Ljava/lang/Object;", true);
EXPECT_TRUE(precise_obj.Equals(precise_obj_2));
EXPECT_FALSE(imprecise_obj.Equals(precise_obj));
@@ -359,11 +360,11 @@ TEST_F(RegTypeReferenceTest, UnresolvedType) {
// a hit second time.
ScopedObjectAccess soa(Thread::Current());
RegTypeCache cache(true);
- const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+ const RegType& ref_type_0 = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes());
- const RegType& ref_type_1 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+ const RegType& ref_type_1 = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.Equals(ref_type_1));
const RegType& unresolved_super_class = cache.FromUnresolvedSuperClass(ref_type_0);
@@ -375,9 +376,9 @@ TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
// Tests creating types uninitialized types from unresolved types.
ScopedObjectAccess soa(Thread::Current());
RegTypeCache cache(true);
- const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+ const RegType& ref_type_0 = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
- const RegType& ref_type = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+ const RegType& ref_type = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.Equals(ref_type));
// Create an uninitialized type of this unresolved type
const RegType& unresolved_unintialised = cache.Uninitialized(ref_type, 1101ull);
@@ -397,8 +398,8 @@ TEST_F(RegTypeReferenceTest, Dump) {
// Tests types for proper Dump messages.
ScopedObjectAccess soa(Thread::Current());
RegTypeCache cache(true);
- const RegType& unresolved_ref = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
- const RegType& unresolved_ref_another = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExistEither;", true);
+ const RegType& unresolved_ref = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
+ const RegType& unresolved_ref_another = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExistEither;", true);
const RegType& resolved_ref = cache.JavaLangString();
const RegType& resolved_unintialiesd = cache.Uninitialized(resolved_ref, 10);
const RegType& unresolved_unintialized = cache.Uninitialized(unresolved_ref, 12);
@@ -424,7 +425,7 @@ TEST_F(RegTypeReferenceTest, JavalangString) {
RegTypeCache cache(true);
const RegType& ref_type = cache.JavaLangString();
const RegType& ref_type_2 = cache.JavaLangString();
- const RegType& ref_type_3 = cache.FromDescriptor(NULL, "Ljava/lang/String;", true);
+ const RegType& ref_type_3 = cache.FromDescriptor(nullptr, "Ljava/lang/String;", true);
EXPECT_TRUE(ref_type.Equals(ref_type_2));
EXPECT_TRUE(ref_type_2.Equals(ref_type_3));
@@ -444,7 +445,7 @@ TEST_F(RegTypeReferenceTest, JavalangObject) {
RegTypeCache cache(true);
const RegType& ref_type = cache.JavaLangObject(true);
const RegType& ref_type_2 = cache.JavaLangObject(true);
- const RegType& ref_type_3 = cache.FromDescriptor(NULL, "Ljava/lang/Object;", true);
+ const RegType& ref_type_3 = cache.FromDescriptor(nullptr, "Ljava/lang/Object;", true);
EXPECT_TRUE(ref_type.Equals(ref_type_2));
EXPECT_TRUE(ref_type_3.Equals(ref_type_2));
@@ -459,9 +460,9 @@ TEST_F(RegTypeReferenceTest, Merging) {
const RegType& Object = cache_new.JavaLangObject(true);
EXPECT_TRUE(string.Merge(Object, &cache_new).IsJavaLangObject());
// Merge two unresolved types.
- const RegType& ref_type_0 = cache_new.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
+ const RegType& ref_type_0 = cache_new.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
- const RegType& ref_type_1 = cache_new.FromDescriptor(NULL, "Ljava/lang/DoesNotExistToo;", true);
+ const RegType& ref_type_1 = cache_new.FromDescriptor(nullptr, "Ljava/lang/DoesNotExistToo;", true);
EXPECT_FALSE(ref_type_0.Equals(ref_type_1));
const RegType& merged = ref_type_1.Merge(ref_type_0, &cache_new);
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 0989cd0c41..219e687699 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -25,10 +25,135 @@
namespace art {
namespace verifier {
-inline const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
+inline const RegType& RegisterLine::GetRegisterType(MethodVerifier* verifier, uint32_t vsrc) const {
// The register index was validated during the static pass, so we don't need to check it here.
DCHECK_LT(vsrc, num_regs_);
- return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
+ return verifier->GetRegTypeCache()->GetFromId(line_[vsrc]);
+}
+
+inline bool RegisterLine::SetRegisterType(MethodVerifier* verifier, uint32_t vdst,
+ const RegType& new_type) {
+ DCHECK_LT(vdst, num_regs_);
+ if (new_type.IsLowHalf() || new_type.IsHighHalf()) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
+ << new_type << "'";
+ return false;
+ } else if (new_type.IsConflict()) { // should only be set during a merge
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
+ return false;
+ } else {
+ line_[vdst] = new_type.GetId();
+ }
+ // Clear the monitor entry bits for this register.
+ ClearAllRegToLockDepths(vdst);
+ return true;
+}
+
+inline bool RegisterLine::SetRegisterTypeWide(MethodVerifier* verifier, uint32_t vdst,
+ const RegType& new_type1,
+ const RegType& new_type2) {
+ DCHECK_LT(vdst + 1, num_regs_);
+ if (!new_type1.CheckWidePair(new_type2)) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Invalid wide pair '"
+ << new_type1 << "' '" << new_type2 << "'";
+ return false;
+ } else {
+ line_[vdst] = new_type1.GetId();
+ line_[vdst + 1] = new_type2.GetId();
+ }
+ // Clear the monitor entry bits for this register.
+ ClearAllRegToLockDepths(vdst);
+ ClearAllRegToLockDepths(vdst + 1);
+ return true;
+}
+
+inline void RegisterLine::SetResultTypeToUnknown(MethodVerifier* verifier) {
+ result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
+ result_[1] = result_[0];
+}
+
+inline void RegisterLine::SetResultRegisterType(MethodVerifier* verifier, const RegType& new_type) {
+ DCHECK(!new_type.IsLowHalf());
+ DCHECK(!new_type.IsHighHalf());
+ result_[0] = new_type.GetId();
+ result_[1] = verifier->GetRegTypeCache()->Undefined().GetId();
+}
+
+inline void RegisterLine::SetResultRegisterTypeWide(const RegType& new_type1,
+ const RegType& new_type2) {
+ DCHECK(new_type1.CheckWidePair(new_type2));
+ result_[0] = new_type1.GetId();
+ result_[1] = new_type2.GetId();
+}
+
+inline void RegisterLine::CopyRegister1(MethodVerifier* verifier, uint32_t vdst, uint32_t vsrc,
+ TypeCategory cat) {
+ DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
+ const RegType& type = GetRegisterType(verifier, vsrc);
+ if (!SetRegisterType(verifier, vdst, type)) {
+ return;
+ }
+ if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
+ (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
+ << " cat=" << static_cast<int>(cat);
+ } else if (cat == kTypeCategoryRef) {
+ CopyRegToLockDepth(vdst, vsrc);
+ }
+}
+
+inline void RegisterLine::CopyRegister2(MethodVerifier* verifier, uint32_t vdst, uint32_t vsrc) {
+ const RegType& type_l = GetRegisterType(verifier, vsrc);
+ const RegType& type_h = GetRegisterType(verifier, vsrc + 1);
+
+ if (!type_l.CheckWidePair(type_h)) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy2 v" << vdst << "<-v" << vsrc
+ << " type=" << type_l << "/" << type_h;
+ } else {
+ SetRegisterTypeWide(verifier, vdst, type_l, type_h);
+ }
+}
+
+inline bool RegisterLine::VerifyRegisterType(MethodVerifier* verifier, uint32_t vsrc,
+ const RegType& check_type) {
+ // Verify the src register type against the check type refining the type of the register
+ const RegType& src_type = GetRegisterType(verifier, vsrc);
+ if (UNLIKELY(!check_type.IsAssignableFrom(src_type))) {
+ enum VerifyError fail_type;
+ if (!check_type.IsNonZeroReferenceTypes() || !src_type.IsNonZeroReferenceTypes()) {
+ // Hard fail if one of the types is primitive, since they are concretely known.
+ fail_type = VERIFY_ERROR_BAD_CLASS_HARD;
+ } else if (check_type.IsUnresolvedTypes() || src_type.IsUnresolvedTypes()) {
+ fail_type = VERIFY_ERROR_NO_CLASS;
+ } else {
+ fail_type = VERIFY_ERROR_BAD_CLASS_SOFT;
+ }
+ verifier->Fail(fail_type) << "register v" << vsrc << " has type "
+ << src_type << " but expected " << check_type;
+ return false;
+ }
+ if (check_type.IsLowHalf()) {
+ const RegType& src_type_h = GetRegisterType(verifier, vsrc + 1);
+ if (UNLIKELY(!src_type.CheckWidePair(src_type_h))) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
+ << src_type << "/" << src_type_h;
+ return false;
+ }
+ }
+ // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
+ // precise than the subtype in vsrc so leave it for reference types. For primitive types
+ // if they are a defined type then they are as precise as we can get, however, for constant
+ // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
+ return true;
+}
+
+inline bool RegisterLine::VerifyMonitorStackEmpty(MethodVerifier* verifier) const {
+ if (MonitorStackDepth() != 0) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected empty monitor stack";
+ return false;
+ } else {
+ return true;
+ }
}
} // namespace verifier
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 556056ce04..3139204ba5 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -20,15 +20,16 @@
#include "dex_instruction-inl.h"
#include "method_verifier.h"
#include "register_line-inl.h"
+#include "reg_type-inl.h"
namespace art {
namespace verifier {
-bool RegisterLine::CheckConstructorReturn() const {
+bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const {
for (size_t i = 0; i < num_regs_; i++) {
- if (GetRegisterType(i).IsUninitializedThisReference() ||
- GetRegisterType(i).IsUnresolvedAndUninitializedThisReference()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT)
+ if (GetRegisterType(verifier, i).IsUninitializedThisReference() ||
+ GetRegisterType(verifier, i).IsUnresolvedAndUninitializedThisReference()) {
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT)
<< "Constructor returning without calling superclass constructor";
return false;
}
@@ -36,122 +37,38 @@ bool RegisterLine::CheckConstructorReturn() const {
return true;
}
-bool RegisterLine::SetRegisterType(uint32_t vdst, const RegType& new_type) {
- DCHECK_LT(vdst, num_regs_);
- if (new_type.IsLowHalf() || new_type.IsHighHalf()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
- << new_type << "'";
- return false;
- } else if (new_type.IsConflict()) { // should only be set during a merge
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
- return false;
- } else {
- line_[vdst] = new_type.GetId();
- }
- // Clear the monitor entry bits for this register.
- ClearAllRegToLockDepths(vdst);
- return true;
-}
-
-bool RegisterLine::SetRegisterTypeWide(uint32_t vdst, const RegType& new_type1,
- const RegType& new_type2) {
- DCHECK_LT(vdst + 1, num_regs_);
- if (!new_type1.CheckWidePair(new_type2)) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Invalid wide pair '"
- << new_type1 << "' '" << new_type2 << "'";
- return false;
- } else {
- line_[vdst] = new_type1.GetId();
- line_[vdst + 1] = new_type2.GetId();
- }
- // Clear the monitor entry bits for this register.
- ClearAllRegToLockDepths(vdst);
- ClearAllRegToLockDepths(vdst + 1);
- return true;
-}
-
-void RegisterLine::SetResultTypeToUnknown() {
- result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
- result_[1] = result_[0];
-}
-
-void RegisterLine::SetResultRegisterType(const RegType& new_type) {
- DCHECK(!new_type.IsLowHalf());
- DCHECK(!new_type.IsHighHalf());
- result_[0] = new_type.GetId();
- result_[1] = verifier_->GetRegTypeCache()->Undefined().GetId();
-}
-
-void RegisterLine::SetResultRegisterTypeWide(const RegType& new_type1,
- const RegType& new_type2) {
- DCHECK(new_type1.CheckWidePair(new_type2));
- result_[0] = new_type1.GetId();
- result_[1] = new_type2.GetId();
-}
-
-const RegType& RegisterLine::GetInvocationThis(const Instruction* inst, bool is_range) {
+const RegType& RegisterLine::GetInvocationThis(MethodVerifier* verifier, const Instruction* inst,
+ bool is_range) {
const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
if (args_count < 1) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
- return verifier_->GetRegTypeCache()->Conflict();
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
+ return verifier->GetRegTypeCache()->Conflict();
}
/* Get the element type of the array held in vsrc */
const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
- const RegType& this_type = GetRegisterType(this_reg);
+ const RegType& this_type = GetRegisterType(verifier, this_reg);
if (!this_type.IsReferenceTypes()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "tried to get class from non-reference register v"
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "tried to get class from non-reference register v"
<< this_reg << " (type=" << this_type << ")";
- return verifier_->GetRegTypeCache()->Conflict();
+ return verifier->GetRegTypeCache()->Conflict();
}
return this_type;
}
-bool RegisterLine::VerifyRegisterType(uint32_t vsrc,
- const RegType& check_type) {
- // Verify the src register type against the check type refining the type of the register
- const RegType& src_type = GetRegisterType(vsrc);
- if (!(check_type.IsAssignableFrom(src_type))) {
- enum VerifyError fail_type;
- if (!check_type.IsNonZeroReferenceTypes() || !src_type.IsNonZeroReferenceTypes()) {
- // Hard fail if one of the types is primitive, since they are concretely known.
- fail_type = VERIFY_ERROR_BAD_CLASS_HARD;
- } else if (check_type.IsUnresolvedTypes() || src_type.IsUnresolvedTypes()) {
- fail_type = VERIFY_ERROR_NO_CLASS;
- } else {
- fail_type = VERIFY_ERROR_BAD_CLASS_SOFT;
- }
- verifier_->Fail(fail_type) << "register v" << vsrc << " has type "
- << src_type << " but expected " << check_type;
- return false;
- }
- if (check_type.IsLowHalf()) {
- const RegType& src_type_h = GetRegisterType(vsrc + 1);
- if (!src_type.CheckWidePair(src_type_h)) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
- << src_type << "/" << src_type_h;
- return false;
- }
- }
- // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
- // precise than the subtype in vsrc so leave it for reference types. For primitive types
- // if they are a defined type then they are as precise as we can get, however, for constant
- // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
- return true;
-}
-
-bool RegisterLine::VerifyRegisterTypeWide(uint32_t vsrc, const RegType& check_type1,
+bool RegisterLine::VerifyRegisterTypeWide(MethodVerifier* verifier, uint32_t vsrc,
+ const RegType& check_type1,
const RegType& check_type2) {
DCHECK(check_type1.CheckWidePair(check_type2));
// Verify the src register type against the check type refining the type of the register
- const RegType& src_type = GetRegisterType(vsrc);
+ const RegType& src_type = GetRegisterType(verifier, vsrc);
if (!check_type1.IsAssignableFrom(src_type)) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type
<< " but expected " << check_type1;
return false;
}
- const RegType& src_type_h = GetRegisterType(vsrc + 1);
+ const RegType& src_type_h = GetRegisterType(verifier, vsrc + 1);
if (!src_type.CheckWidePair(src_type_h)) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
<< src_type << "/" << src_type_h;
return false;
}
@@ -162,12 +79,12 @@ bool RegisterLine::VerifyRegisterTypeWide(uint32_t vsrc, const RegType& check_ty
return true;
}
-void RegisterLine::MarkRefsAsInitialized(const RegType& uninit_type) {
+void RegisterLine::MarkRefsAsInitialized(MethodVerifier* verifier, const RegType& uninit_type) {
DCHECK(uninit_type.IsUninitializedTypes());
- const RegType& init_type = verifier_->GetRegTypeCache()->FromUninitialized(uninit_type);
+ const RegType& init_type = verifier->GetRegTypeCache()->FromUninitialized(uninit_type);
size_t changed = 0;
for (uint32_t i = 0; i < num_regs_; i++) {
- if (GetRegisterType(i).Equals(uninit_type)) {
+ if (GetRegisterType(verifier, i).Equals(uninit_type)) {
line_[i] = init_type.GetId();
changed++;
}
@@ -175,15 +92,15 @@ void RegisterLine::MarkRefsAsInitialized(const RegType& uninit_type) {
DCHECK_GT(changed, 0u);
}
-void RegisterLine::MarkAllRegistersAsConflicts() {
- uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
+void RegisterLine::MarkAllRegistersAsConflicts(MethodVerifier* verifier) {
+ uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
for (uint32_t i = 0; i < num_regs_; i++) {
line_[i] = conflict_type_id;
}
}
-void RegisterLine::MarkAllRegistersAsConflictsExcept(uint32_t vsrc) {
- uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
+void RegisterLine::MarkAllRegistersAsConflictsExcept(MethodVerifier* verifier, uint32_t vsrc) {
+ uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
for (uint32_t i = 0; i < num_regs_; i++) {
if (i != vsrc) {
line_[i] = conflict_type_id;
@@ -191,8 +108,8 @@ void RegisterLine::MarkAllRegistersAsConflictsExcept(uint32_t vsrc) {
}
}
-void RegisterLine::MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc) {
- uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
+void RegisterLine::MarkAllRegistersAsConflictsExceptWide(MethodVerifier* verifier, uint32_t vsrc) {
+ uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
for (uint32_t i = 0; i < num_regs_; i++) {
if ((i != vsrc) && (i != (vsrc + 1))) {
line_[i] = conflict_type_id;
@@ -200,11 +117,11 @@ void RegisterLine::MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc) {
}
}
-std::string RegisterLine::Dump() const {
+std::string RegisterLine::Dump(MethodVerifier* verifier) const {
std::string result;
for (size_t i = 0; i < num_regs_; i++) {
result += StringPrintf("%zd:[", i);
- result += GetRegisterType(i).Dump();
+ result += GetRegisterType(verifier, i).Dump();
result += "],";
}
for (const auto& monitor : monitors_) {
@@ -213,52 +130,25 @@ std::string RegisterLine::Dump() const {
return result;
}
-void RegisterLine::MarkUninitRefsAsInvalid(const RegType& uninit_type) {
+void RegisterLine::MarkUninitRefsAsInvalid(MethodVerifier* verifier, const RegType& uninit_type) {
for (size_t i = 0; i < num_regs_; i++) {
- if (GetRegisterType(i).Equals(uninit_type)) {
- line_[i] = verifier_->GetRegTypeCache()->Conflict().GetId();
+ if (GetRegisterType(verifier, i).Equals(uninit_type)) {
+ line_[i] = verifier->GetRegTypeCache()->Conflict().GetId();
ClearAllRegToLockDepths(i);
}
}
}
-void RegisterLine::CopyRegister1(uint32_t vdst, uint32_t vsrc, TypeCategory cat) {
- DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
- const RegType& type = GetRegisterType(vsrc);
- if (!SetRegisterType(vdst, type)) {
- return;
- }
- if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
- (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
- << " cat=" << static_cast<int>(cat);
- } else if (cat == kTypeCategoryRef) {
- CopyRegToLockDepth(vdst, vsrc);
- }
-}
-
-void RegisterLine::CopyRegister2(uint32_t vdst, uint32_t vsrc) {
- const RegType& type_l = GetRegisterType(vsrc);
- const RegType& type_h = GetRegisterType(vsrc + 1);
-
- if (!type_l.CheckWidePair(type_h)) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy2 v" << vdst << "<-v" << vsrc
- << " type=" << type_l << "/" << type_h;
- } else {
- SetRegisterTypeWide(vdst, type_l, type_h);
- }
-}
-
-void RegisterLine::CopyResultRegister1(uint32_t vdst, bool is_reference) {
- const RegType& type = verifier_->GetRegTypeCache()->GetFromId(result_[0]);
+void RegisterLine::CopyResultRegister1(MethodVerifier* verifier, uint32_t vdst, bool is_reference) {
+ const RegType& type = verifier->GetRegTypeCache()->GetFromId(result_[0]);
if ((!is_reference && !type.IsCategory1Types()) ||
(is_reference && !type.IsReferenceTypes())) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "copyRes1 v" << vdst << "<- result0" << " type=" << type;
} else {
- DCHECK(verifier_->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined());
- SetRegisterType(vdst, type);
- result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
+ DCHECK(verifier->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined());
+ SetRegisterType(verifier, vdst, type);
+ result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
}
}
@@ -266,178 +156,179 @@ void RegisterLine::CopyResultRegister1(uint32_t vdst, bool is_reference) {
* Implement "move-result-wide". Copy the category-2 value from the result
* register to another register, and reset the result register.
*/
-void RegisterLine::CopyResultRegister2(uint32_t vdst) {
- const RegType& type_l = verifier_->GetRegTypeCache()->GetFromId(result_[0]);
- const RegType& type_h = verifier_->GetRegTypeCache()->GetFromId(result_[1]);
+void RegisterLine::CopyResultRegister2(MethodVerifier* verifier, uint32_t vdst) {
+ const RegType& type_l = verifier->GetRegTypeCache()->GetFromId(result_[0]);
+ const RegType& type_h = verifier->GetRegTypeCache()->GetFromId(result_[1]);
if (!type_l.IsCategory2Types()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "copyRes2 v" << vdst << "<- result0" << " type=" << type_l;
} else {
DCHECK(type_l.CheckWidePair(type_h)); // Set should never allow this case
- SetRegisterTypeWide(vdst, type_l, type_h); // also sets the high
- result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
- result_[1] = verifier_->GetRegTypeCache()->Undefined().GetId();
+ SetRegisterTypeWide(verifier, vdst, type_l, type_h); // also sets the high
+ result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
+ result_[1] = verifier->GetRegTypeCache()->Undefined().GetId();
}
}
-void RegisterLine::CheckUnaryOp(const Instruction* inst,
- const RegType& dst_type,
- const RegType& src_type) {
- if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
- SetRegisterType(inst->VRegA_12x(), dst_type);
+void RegisterLine::CheckUnaryOp(MethodVerifier* verifier, const Instruction* inst,
+ const RegType& dst_type, const RegType& src_type) {
+ if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) {
+ SetRegisterType(verifier, inst->VRegA_12x(), dst_type);
}
}
-void RegisterLine::CheckUnaryOpWide(const Instruction* inst,
+void RegisterLine::CheckUnaryOpWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1, const RegType& src_type2) {
- if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
- SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
+ if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) {
+ SetRegisterTypeWide(verifier, inst->VRegA_12x(), dst_type1, dst_type2);
}
}
-void RegisterLine::CheckUnaryOpToWide(const Instruction* inst,
+void RegisterLine::CheckUnaryOpToWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type) {
- if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
- SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
+ if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) {
+ SetRegisterTypeWide(verifier, inst->VRegA_12x(), dst_type1, dst_type2);
}
}
-void RegisterLine::CheckUnaryOpFromWide(const Instruction* inst,
+void RegisterLine::CheckUnaryOpFromWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2) {
- if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
- SetRegisterType(inst->VRegA_12x(), dst_type);
+ if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) {
+ SetRegisterType(verifier, inst->VRegA_12x(), dst_type);
}
}
-void RegisterLine::CheckBinaryOp(const Instruction* inst,
+void RegisterLine::CheckBinaryOp(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2,
bool check_boolean_op) {
const uint32_t vregB = inst->VRegB_23x();
const uint32_t vregC = inst->VRegC_23x();
- if (VerifyRegisterType(vregB, src_type1) &&
- VerifyRegisterType(vregC, src_type2)) {
+ if (VerifyRegisterType(verifier, vregB, src_type1) &&
+ VerifyRegisterType(verifier, vregC, src_type2)) {
if (check_boolean_op) {
DCHECK(dst_type.IsInteger());
- if (GetRegisterType(vregB).IsBooleanTypes() &&
- GetRegisterType(vregC).IsBooleanTypes()) {
- SetRegisterType(inst->VRegA_23x(), verifier_->GetRegTypeCache()->Boolean());
+ if (GetRegisterType(verifier, vregB).IsBooleanTypes() &&
+ GetRegisterType(verifier, vregC).IsBooleanTypes()) {
+ SetRegisterType(verifier, inst->VRegA_23x(), verifier->GetRegTypeCache()->Boolean());
return;
}
}
- SetRegisterType(inst->VRegA_23x(), dst_type);
+ SetRegisterType(verifier, inst->VRegA_23x(), dst_type);
}
}
-void RegisterLine::CheckBinaryOpWide(const Instruction* inst,
+void RegisterLine::CheckBinaryOpWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2) {
- if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_type1_1, src_type1_2) &&
- VerifyRegisterTypeWide(inst->VRegC_23x(), src_type2_1, src_type2_2)) {
- SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2);
+ if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), src_type1_1, src_type1_2) &&
+ VerifyRegisterTypeWide(verifier, inst->VRegC_23x(), src_type2_1, src_type2_2)) {
+ SetRegisterTypeWide(verifier, inst->VRegA_23x(), dst_type1, dst_type2);
}
}
-void RegisterLine::CheckBinaryOpWideShift(const Instruction* inst,
+void RegisterLine::CheckBinaryOpWideShift(MethodVerifier* verifier, const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type) {
- if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_type, long_hi_type) &&
- VerifyRegisterType(inst->VRegC_23x(), int_type)) {
- SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type);
+ if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), long_lo_type, long_hi_type) &&
+ VerifyRegisterType(verifier, inst->VRegC_23x(), int_type)) {
+ SetRegisterTypeWide(verifier, inst->VRegA_23x(), long_lo_type, long_hi_type);
}
}
-void RegisterLine::CheckBinaryOp2addr(const Instruction* inst,
+void RegisterLine::CheckBinaryOp2addr(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type, const RegType& src_type1,
const RegType& src_type2, bool check_boolean_op) {
const uint32_t vregA = inst->VRegA_12x();
const uint32_t vregB = inst->VRegB_12x();
- if (VerifyRegisterType(vregA, src_type1) &&
- VerifyRegisterType(vregB, src_type2)) {
+ if (VerifyRegisterType(verifier, vregA, src_type1) &&
+ VerifyRegisterType(verifier, vregB, src_type2)) {
if (check_boolean_op) {
DCHECK(dst_type.IsInteger());
- if (GetRegisterType(vregA).IsBooleanTypes() &&
- GetRegisterType(vregB).IsBooleanTypes()) {
- SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
+ if (GetRegisterType(verifier, vregA).IsBooleanTypes() &&
+ GetRegisterType(verifier, vregB).IsBooleanTypes()) {
+ SetRegisterType(verifier, vregA, verifier->GetRegTypeCache()->Boolean());
return;
}
}
- SetRegisterType(vregA, dst_type);
+ SetRegisterType(verifier, vregA, dst_type);
}
}
-void RegisterLine::CheckBinaryOp2addrWide(const Instruction* inst,
+void RegisterLine::CheckBinaryOp2addrWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2) {
const uint32_t vregA = inst->VRegA_12x();
const uint32_t vregB = inst->VRegB_12x();
- if (VerifyRegisterTypeWide(vregA, src_type1_1, src_type1_2) &&
- VerifyRegisterTypeWide(vregB, src_type2_1, src_type2_2)) {
- SetRegisterTypeWide(vregA, dst_type1, dst_type2);
+ if (VerifyRegisterTypeWide(verifier, vregA, src_type1_1, src_type1_2) &&
+ VerifyRegisterTypeWide(verifier, vregB, src_type2_1, src_type2_2)) {
+ SetRegisterTypeWide(verifier, vregA, dst_type1, dst_type2);
}
}
-void RegisterLine::CheckBinaryOp2addrWideShift(const Instruction* inst,
+void RegisterLine::CheckBinaryOp2addrWideShift(MethodVerifier* verifier, const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type) {
const uint32_t vregA = inst->VRegA_12x();
const uint32_t vregB = inst->VRegB_12x();
- if (VerifyRegisterTypeWide(vregA, long_lo_type, long_hi_type) &&
- VerifyRegisterType(vregB, int_type)) {
- SetRegisterTypeWide(vregA, long_lo_type, long_hi_type);
+ if (VerifyRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type) &&
+ VerifyRegisterType(verifier, vregB, int_type)) {
+ SetRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type);
}
}
-void RegisterLine::CheckLiteralOp(const Instruction* inst,
+void RegisterLine::CheckLiteralOp(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type, const RegType& src_type,
bool check_boolean_op, bool is_lit16) {
const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b();
const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b();
- if (VerifyRegisterType(vregB, src_type)) {
+ if (VerifyRegisterType(verifier, vregB, src_type)) {
if (check_boolean_op) {
DCHECK(dst_type.IsInteger());
/* check vB with the call, then check the constant manually */
const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
- if (GetRegisterType(vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
- SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
+ if (GetRegisterType(verifier, vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
+ SetRegisterType(verifier, vregA, verifier->GetRegTypeCache()->Boolean());
return;
}
}
- SetRegisterType(vregA, dst_type);
+ SetRegisterType(verifier, vregA, dst_type);
}
}
-void RegisterLine::PushMonitor(uint32_t reg_idx, int32_t insn_idx) {
- const RegType& reg_type = GetRegisterType(reg_idx);
+void RegisterLine::PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx) {
+ const RegType& reg_type = GetRegisterType(verifier, reg_idx);
if (!reg_type.IsReferenceTypes()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter on non-object (" << reg_type << ")";
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter on non-object ("
+ << reg_type << ")";
} else if (monitors_.size() >= 32) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter stack overflow: " << monitors_.size();
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter stack overflow: "
+ << monitors_.size();
} else {
SetRegToLockDepth(reg_idx, monitors_.size());
monitors_.push_back(insn_idx);
}
}
-void RegisterLine::PopMonitor(uint32_t reg_idx) {
- const RegType& reg_type = GetRegisterType(reg_idx);
+void RegisterLine::PopMonitor(MethodVerifier* verifier, uint32_t reg_idx) {
+ const RegType& reg_type = GetRegisterType(verifier, reg_idx);
if (!reg_type.IsReferenceTypes()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit on non-object (" << reg_type << ")";
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit on non-object (" << reg_type << ")";
} else if (monitors_.empty()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit stack underflow";
+ verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit stack underflow";
} else {
monitors_.pop_back();
if (!IsSetLockDepth(reg_idx, monitors_.size())) {
// Bug 3215458: Locks and unlocks are on objects, if that object is a literal then before
// format "036" the constant collector may create unlocks on the same object but referenced
// via different registers.
- ((verifier_->DexFileVersion() >= 36) ? verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT)
- : verifier_->LogVerifyInfo())
+ ((verifier->DexFileVersion() >= 36) ? verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT)
+ : verifier->LogVerifyInfo())
<< "monitor-exit not unlocking the top of the monitor stack";
} else {
// Record the register was unlocked
@@ -446,41 +337,34 @@ void RegisterLine::PopMonitor(uint32_t reg_idx) {
}
}
-bool RegisterLine::VerifyMonitorStackEmpty() const {
- if (MonitorStackDepth() != 0) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected empty monitor stack";
- return false;
- } else {
- return true;
- }
-}
-
-bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
+bool RegisterLine::MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line) {
bool changed = false;
DCHECK(incoming_line != nullptr);
for (size_t idx = 0; idx < num_regs_; idx++) {
if (line_[idx] != incoming_line->line_[idx]) {
- const RegType& incoming_reg_type = incoming_line->GetRegisterType(idx);
- const RegType& cur_type = GetRegisterType(idx);
- const RegType& new_type = cur_type.Merge(incoming_reg_type, verifier_->GetRegTypeCache());
+ const RegType& incoming_reg_type = incoming_line->GetRegisterType(verifier, idx);
+ const RegType& cur_type = GetRegisterType(verifier, idx);
+ const RegType& new_type = cur_type.Merge(incoming_reg_type, verifier->GetRegTypeCache());
changed = changed || !cur_type.Equals(new_type);
line_[idx] = new_type.GetId();
}
}
- if (monitors_.size() != incoming_line->monitors_.size()) {
- LOG(WARNING) << "mismatched stack depths (depth=" << MonitorStackDepth()
- << ", incoming depth=" << incoming_line->MonitorStackDepth() << ")";
- } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
- for (uint32_t idx = 0; idx < num_regs_; idx++) {
- size_t depths = reg_to_lock_depths_.count(idx);
- size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
- if (depths != incoming_depths) {
- if (depths == 0 || incoming_depths == 0) {
- reg_to_lock_depths_.erase(idx);
- } else {
- LOG(WARNING) << "mismatched stack depths for register v" << idx
- << ": " << depths << " != " << incoming_depths;
- break;
+ if (monitors_.size() > 0 || incoming_line->monitors_.size() > 0) {
+ if (monitors_.size() != incoming_line->monitors_.size()) {
+ LOG(WARNING) << "mismatched stack depths (depth=" << MonitorStackDepth()
+ << ", incoming depth=" << incoming_line->MonitorStackDepth() << ")";
+ } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
+ for (uint32_t idx = 0; idx < num_regs_; idx++) {
+ size_t depths = reg_to_lock_depths_.count(idx);
+ size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
+ if (depths != incoming_depths) {
+ if (depths == 0 || incoming_depths == 0) {
+ reg_to_lock_depths_.erase(idx);
+ } else {
+ LOG(WARNING) << "mismatched stack depths for register v" << idx
+ << ": " << depths << " != " << incoming_depths;
+ break;
+ }
}
}
}
@@ -488,12 +372,13 @@ bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
return changed;
}
-void RegisterLine::WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes) {
+void RegisterLine::WriteReferenceBitMap(MethodVerifier* verifier,
+ std::vector<uint8_t>* data, size_t max_bytes) {
for (size_t i = 0; i < num_regs_; i += 8) {
uint8_t val = 0;
for (size_t j = 0; j < 8 && (i + j) < num_regs_; j++) {
// Note: we write 1 for a Reference but not for Null
- if (GetRegisterType(i + j).IsNonZeroReferenceTypes()) {
+ if (GetRegisterType(verifier, i + j).IsNonZeroReferenceTypes()) {
val |= 1 << j;
}
}
@@ -502,15 +387,9 @@ void RegisterLine::WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_b
continue;
}
DCHECK_LT(i / 8, max_bytes) << "val=" << static_cast<uint32_t>(val);
- data.push_back(val);
+ data->push_back(val);
}
}
-std::ostream& operator<<(std::ostream& os, const RegisterLine& rhs)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- os << rhs.Dump();
- return os;
-}
-
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index a9d0dbb073..c7fd369472 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -57,50 +57,54 @@ class RegisterLine {
}
// Implement category-1 "move" instructions. Copy a 32-bit value from "vsrc" to "vdst".
- void CopyRegister1(uint32_t vdst, uint32_t vsrc, TypeCategory cat)
+ void CopyRegister1(MethodVerifier* verifier, uint32_t vdst, uint32_t vsrc, TypeCategory cat)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Implement category-2 "move" instructions. Copy a 64-bit value from "vsrc" to "vdst". This
// copies both halves of the register.
- void CopyRegister2(uint32_t vdst, uint32_t vsrc)
+ void CopyRegister2(MethodVerifier* verifier, uint32_t vdst, uint32_t vsrc)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Implement "move-result". Copy the category-1 value from the result register to another
// register, and reset the result register.
- void CopyResultRegister1(uint32_t vdst, bool is_reference)
+ void CopyResultRegister1(MethodVerifier* verifier, uint32_t vdst, bool is_reference)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Implement "move-result-wide". Copy the category-2 value from the result register to another
// register, and reset the result register.
- void CopyResultRegister2(uint32_t vdst)
+ void CopyResultRegister2(MethodVerifier* verifier, uint32_t vdst)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Set the invisible result register to unknown
- void SetResultTypeToUnknown() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetResultTypeToUnknown(MethodVerifier* verifier) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Set the type of register N, verifying that the register is valid. If "newType" is the "Lo"
// part of a 64-bit value, register N+1 will be set to "newType+1".
// The register index was validated during the static pass, so we don't need to check it here.
- bool SetRegisterType(uint32_t vdst, const RegType& new_type)
+ ALWAYS_INLINE bool SetRegisterType(MethodVerifier* verifier, uint32_t vdst,
+ const RegType& new_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool SetRegisterTypeWide(uint32_t vdst, const RegType& new_type1, const RegType& new_type2)
+ bool SetRegisterTypeWide(MethodVerifier* verifier, uint32_t vdst, const RegType& new_type1,
+ const RegType& new_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/* Set the type of the "result" register. */
- void SetResultRegisterType(const RegType& new_type)
+ void SetResultRegisterType(MethodVerifier* verifier, const RegType& new_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetResultRegisterTypeWide(const RegType& new_type1, const RegType& new_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Get the type of register vsrc.
- const RegType& GetRegisterType(uint32_t vsrc) const;
+ const RegType& GetRegisterType(MethodVerifier* verifier, uint32_t vsrc) const;
- bool VerifyRegisterType(uint32_t vsrc, const RegType& check_type)
+ ALWAYS_INLINE bool VerifyRegisterType(MethodVerifier* verifier, uint32_t vsrc,
+ const RegType& check_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool VerifyRegisterTypeWide(uint32_t vsrc, const RegType& check_type1, const RegType& check_type2)
+ bool VerifyRegisterTypeWide(MethodVerifier* verifier, uint32_t vsrc, const RegType& check_type1,
+ const RegType& check_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void CopyFromLine(const RegisterLine* src) {
@@ -110,7 +114,7 @@ class RegisterLine {
reg_to_lock_depths_ = src->reg_to_lock_depths_;
}
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump(MethodVerifier* verifier) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void FillWithGarbage() {
memset(&line_, 0xf1, num_regs_ * sizeof(uint16_t));
@@ -126,7 +130,7 @@ class RegisterLine {
* to prevent them from being used (otherwise, MarkRefsAsInitialized would mark the old ones and
* the new ones at the same time).
*/
- void MarkUninitRefsAsInvalid(const RegType& uninit_type)
+ void MarkUninitRefsAsInvalid(MethodVerifier* verifier, const RegType& uninit_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
@@ -134,15 +138,15 @@ class RegisterLine {
* reference type. This is called when an appropriate constructor is invoked -- all copies of
* the reference must be marked as initialized.
*/
- void MarkRefsAsInitialized(const RegType& uninit_type)
+ void MarkRefsAsInitialized(MethodVerifier* verifier, const RegType& uninit_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* Update all registers to be Conflict except vsrc.
*/
- void MarkAllRegistersAsConflicts();
- void MarkAllRegistersAsConflictsExcept(uint32_t vsrc);
- void MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc);
+ void MarkAllRegistersAsConflicts(MethodVerifier* verifier);
+ void MarkAllRegistersAsConflictsExcept(MethodVerifier* verifier, uint32_t vsrc);
+ void MarkAllRegistersAsConflictsExceptWide(MethodVerifier* verifier, uint32_t vsrc);
/*
* Check constraints on constructor return. Specifically, make sure that the "this" argument got
@@ -151,7 +155,7 @@ class RegisterLine {
* of the list in slot 0. If we see a register with an uninitialized slot 0 reference, we know it
* somehow didn't get initialized.
*/
- bool CheckConstructorReturn() const;
+ bool CheckConstructorReturn(MethodVerifier* verifier) const;
// Compare two register lines. Returns 0 if they match.
// Using this for a sort is unwise, since the value can change based on machine endianness.
@@ -173,28 +177,29 @@ class RegisterLine {
* The argument count is in vA, and the first argument is in vC, for both "simple" and "range"
* versions. We just need to make sure vA is >= 1 and then return vC.
*/
- const RegType& GetInvocationThis(const Instruction* inst, bool is_range)
+ const RegType& GetInvocationThis(MethodVerifier* verifier, const Instruction* inst,
+ bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* Verify types for a simple two-register instruction (e.g. "neg-int").
* "dst_type" is stored into vA, and "src_type" is verified against vB.
*/
- void CheckUnaryOp(const Instruction* inst, const RegType& dst_type,
+ void CheckUnaryOp(MethodVerifier* verifier, const Instruction* inst, const RegType& dst_type,
const RegType& src_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckUnaryOpWide(const Instruction* inst,
+ void CheckUnaryOpWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1, const RegType& src_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckUnaryOpToWide(const Instruction* inst,
+ void CheckUnaryOpToWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckUnaryOpFromWide(const Instruction* inst,
+ void CheckUnaryOpFromWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -204,18 +209,18 @@ class RegisterLine {
* "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
* against vB/vC.
*/
- void CheckBinaryOp(const Instruction* inst,
+ void CheckBinaryOp(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type, const RegType& src_type1, const RegType& src_type2,
bool check_boolean_op)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOpWide(const Instruction* inst,
+ void CheckBinaryOpWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOpWideShift(const Instruction* inst,
+ void CheckBinaryOpWideShift(MethodVerifier* verifier, const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -224,19 +229,19 @@ class RegisterLine {
* Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
* are verified against vA/vB, then "dst_type" is stored into vA.
*/
- void CheckBinaryOp2addr(const Instruction* inst,
+ void CheckBinaryOp2addr(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2,
bool check_boolean_op)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOp2addrWide(const Instruction* inst,
+ void CheckBinaryOp2addrWide(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOp2addrWideShift(const Instruction* inst,
+ void CheckBinaryOp2addrWideShift(MethodVerifier* verifier, const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -247,16 +252,18 @@ class RegisterLine {
*
* If "check_boolean_op" is set, we use the constant value in vC.
*/
- void CheckLiteralOp(const Instruction* inst,
+ void CheckLiteralOp(MethodVerifier* verifier, const Instruction* inst,
const RegType& dst_type, const RegType& src_type,
bool check_boolean_op, bool is_lit16)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Verify/push monitor onto the monitor stack, locking the value in reg_idx at location insn_idx.
- void PushMonitor(uint32_t reg_idx, int32_t insn_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Verify/pop monitor from monitor stack ensuring that we believe the monitor is locked
- void PopMonitor(uint32_t reg_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void PopMonitor(MethodVerifier* verifier, uint32_t reg_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Stack of currently held monitors and where they were locked
size_t MonitorStackDepth() const {
@@ -265,23 +272,23 @@ class RegisterLine {
// We expect no monitors to be held at certain points, such a method returns. Verify the stack
// is empty, failing and returning false if not.
- bool VerifyMonitorStackEmpty() const;
+ bool VerifyMonitorStackEmpty(MethodVerifier* verifier) const;
- bool MergeRegisters(const RegisterLine* incoming_line)
+ bool MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- size_t GetMaxNonZeroReferenceReg(size_t max_ref_reg) {
+ size_t GetMaxNonZeroReferenceReg(MethodVerifier* verifier, size_t max_ref_reg) {
size_t i = static_cast<int>(max_ref_reg) < 0 ? 0 : max_ref_reg;
for (; i < num_regs_; i++) {
- if (GetRegisterType(i).IsNonZeroReferenceTypes()) {
+ if (GetRegisterType(verifier, i).IsNonZeroReferenceTypes()) {
max_ref_reg = i;
}
}
return max_ref_reg;
}
- // Write a bit at each register location that holds a reference
- void WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes);
+ // Write a bit at each register location that holds a reference.
+ void WriteReferenceBitMap(MethodVerifier* verifier, std::vector<uint8_t>* data, size_t max_bytes);
size_t GetMonitorEnterCount() {
return monitors_.size();
@@ -337,19 +344,17 @@ class RegisterLine {
}
RegisterLine(size_t num_regs, MethodVerifier* verifier)
- : verifier_(verifier), num_regs_(num_regs) {
+ : num_regs_(num_regs) {
memset(&line_, 0, num_regs_ * sizeof(uint16_t));
- SetResultTypeToUnknown();
+ SetResultTypeToUnknown(verifier);
}
// Storage for the result register's type, valid after an invocation
uint16_t result_[2];
- // Back link to the verifier
- MethodVerifier* verifier_;
-
// Length of reg_types_
const uint32_t num_regs_;
+
// A stack of monitor enter locations
std::vector<uint32_t, TrackingAllocator<uint32_t, kAllocatorTagVerifier>> monitors_;
// A map from register to a bit vector of indices into the monitors_ stack. As we pop the monitor
@@ -360,7 +365,6 @@ class RegisterLine {
// An array of RegType Ids associated with each dex register.
uint16_t line_[0];
};
-std::ostream& operator<<(std::ostream& os, const RegisterLine& rhs);
} // namespace verifier
} // namespace art