diff options
36 files changed, 278 insertions, 280 deletions
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc index 92b123013d..540bd0ce45 100644 --- a/compiler/dex/quick_compiler_callbacks.cc +++ b/compiler/dex/quick_compiler_callbacks.cc @@ -38,7 +38,7 @@ ClassStatus QuickCompilerCallbacks::GetPreviousClassState(ClassReference ref) { // If we don't have class unloading enabled in the compiler, we will never see class that were // previously verified. Return false to avoid overhead from the lookup in the compiler driver. if (!does_class_unloading_) { - return ClassStatus::kStatusNotReady; + return ClassStatus::kNotReady; } DCHECK(compiler_driver_ != nullptr); // In the case of the quicken filter: avoiding verification of quickened instructions, which the diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 68f963e3ab..0652ea13a8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1808,7 +1808,7 @@ static void PopulateVerifiedMethods(const DexFile& dex_file, static void LoadAndUpdateStatus(const DexFile& dex_file, const DexFile::ClassDef& class_def, - mirror::Class::Status status, + ClassStatus status, Handle<mirror::ClassLoader> class_loader, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -1867,16 +1867,16 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // Just update the compiled_classes_ map. The compiler doesn't need to resolve // the type. ClassReference ref(dex_file, i); - mirror::Class::Status existing = mirror::Class::kStatusNotReady; + ClassStatus existing = ClassStatus::kNotReady; DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation(); ClassStateTable::InsertResult result = - compiled_classes_.Insert(ref, existing, mirror::Class::kStatusVerified); + compiled_classes_.Insert(ref, existing, ClassStatus::kVerified); CHECK_EQ(result, ClassStateTable::kInsertResultSuccess); } else { // Update the class status, so later compilation stages know they don't need to verify // the class. LoadAndUpdateStatus( - *dex_file, class_def, mirror::Class::kStatusVerified, class_loader, soa.Self()); + *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self()); // Create `VerifiedMethod`s for each methods, the compiler expects one for // quickening or compiling. // Note that this means: @@ -1890,7 +1890,7 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // this class again. LoadAndUpdateStatus(*dex_file, class_def, - mirror::Class::kStatusRetryVerificationAtRuntime, + ClassStatus::kRetryVerificationAtRuntime, class_loader, soa.Self()); } @@ -2104,10 +2104,10 @@ class SetVerifiedClassVisitor : public CompilationVisitor { // Only do this if the class is resolved. If even resolution fails, quickening will go very, // very wrong. if (klass->IsResolved() && !klass->IsErroneousResolved()) { - if (klass->GetStatus() < mirror::Class::kStatusVerified) { + if (klass->GetStatus() < ClassStatus::kVerified) { ObjectLock<mirror::Class> lock(soa.Self(), klass); // Set class status to verified. - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self()); + mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self()); // Mark methods as pre-verified. If we don't do this, the interpreter will run with // access checks. klass->SetSkipAccessChecksFlagOnAllMethods( @@ -2184,7 +2184,7 @@ class InitializeClassVisitor : public CompilationVisitor { const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage(); const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage(); - mirror::Class::Status old_status = klass->GetStatus(); + ClassStatus old_status = klass->GetStatus(); // Don't initialize classes in boot space when compiling app image if (is_app_image && klass->IsBootStrapClassLoaded()) { // Also return early and don't store the class status in the recorded class status. @@ -2309,7 +2309,7 @@ class InitializeClassVisitor : public CompilationVisitor { // would do so they can be skipped at runtime. if (!klass->IsInitialized() && manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) { - old_status = mirror::Class::kStatusSuperclassValidated; + old_status = ClassStatus::kSuperclassValidated; } else { soa.Self()->ClearException(); } @@ -2772,36 +2772,36 @@ void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref, DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod(); } -bool CompilerDriver::GetCompiledClass(const ClassReference& ref, - mirror::Class::Status* status) const { +bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const { DCHECK(status != nullptr); // The table doesn't know if something wasn't inserted. For this case it will return - // kStatusNotReady. To handle this, just assume anything we didn't try to verify is not compiled. + // ClassStatus::kNotReady. To handle this, just assume anything we didn't try to verify + // is not compiled. if (!compiled_classes_.Get(ref, status) || - *status < mirror::Class::kStatusRetryVerificationAtRuntime) { + *status < ClassStatus::kRetryVerificationAtRuntime) { return false; } return true; } -mirror::Class::Status CompilerDriver::GetClassStatus(const ClassReference& ref) const { - mirror::Class::Status status = ClassStatus::kStatusNotReady; +ClassStatus CompilerDriver::GetClassStatus(const ClassReference& ref) const { + ClassStatus status = ClassStatus::kNotReady; if (!GetCompiledClass(ref, &status)) { classpath_classes_.Get(ref, &status); } return status; } -void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class::Status status) { +void CompilerDriver::RecordClassStatus(const ClassReference& ref, ClassStatus status) { switch (status) { - case mirror::Class::kStatusErrorResolved: - case mirror::Class::kStatusErrorUnresolved: - case mirror::Class::kStatusNotReady: - case mirror::Class::kStatusResolved: - case mirror::Class::kStatusRetryVerificationAtRuntime: - case mirror::Class::kStatusVerified: - case mirror::Class::kStatusSuperclassValidated: - case mirror::Class::kStatusInitialized: + case ClassStatus::kErrorResolved: + case ClassStatus::kErrorUnresolved: + case ClassStatus::kNotReady: + case ClassStatus::kResolved: + case ClassStatus::kRetryVerificationAtRuntime: + case ClassStatus::kVerified: + case ClassStatus::kSuperclassValidated: + case ClassStatus::kInitialized: break; // Expected states. default: LOG(FATAL) << "Unexpected class status for class " @@ -2813,7 +2813,7 @@ void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class: ClassStateTable::InsertResult result; ClassStateTable* table = &compiled_classes_; do { - mirror::Class::Status existing = mirror::Class::kStatusNotReady; + ClassStatus existing = ClassStatus::kNotReady; if (!table->Get(ref, &existing)) { // A classpath class. if (kIsDebugBuild) { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index e001726c95..bcea8530e4 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -31,13 +31,13 @@ #include "base/mutex.h" #include "base/timing_logger.h" #include "class_reference.h" +#include "class_status.h" #include "compiler.h" #include "dex_file.h" #include "dex_file_types.h" #include "driver/compiled_method_storage.h" #include "jit/profile_compilation_info.h" #include "method_reference.h" -#include "mirror/class.h" // For mirror::Class::Status. #include "os.h" #include "safe_map.h" #include "thread_pool.h" @@ -47,6 +47,7 @@ namespace art { namespace mirror { +class Class; class DexCache; } // namespace mirror @@ -55,18 +56,21 @@ class MethodVerifier; class VerifierDepsTest; } // namespace verifier +class ArtField; class BitVector; class CompiledMethod; class CompilerOptions; class DexCompilationUnit; +template<class T> class Handle; struct InlineIGetIPutData; class InstructionSetFeatures; class InternTable; enum InvokeType : uint32_t; +class MemberOffset; +template<class MirrorType> class ObjPtr; class ParallelCompilationManager; class ScopedObjectAccess; template <class Allocator> class SrcMap; -template<class T> class Handle; class TimingLogger; class VdexFile; class VerificationResults; @@ -152,8 +156,8 @@ class CompilerDriver { std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const; std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const; - mirror::Class::Status GetClassStatus(const ClassReference& ref) const; - bool GetCompiledClass(const ClassReference& ref, mirror::Class::Status* status) const; + ClassStatus GetClassStatus(const ClassReference& ref) const; + bool GetCompiledClass(const ClassReference& ref, ClassStatus* status) const; CompiledMethod* GetCompiledMethod(MethodReference ref) const; size_t GetNonRelativeLinkerPatchCount() const; @@ -321,7 +325,7 @@ class CompilerDriver { // according to the profile file. bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const; - void RecordClassStatus(const ClassReference& ref, mirror::Class::Status status); + void RecordClassStatus(const ClassReference& ref, ClassStatus status); // Checks if the specified method has been verified without failures. Returns // false if the method is not in the verification results (GetVerificationResults). @@ -476,7 +480,7 @@ class CompilerDriver { GUARDED_BY(requires_constructor_barrier_lock_); // All class references that this compiler has compiled. Indexed by class defs. - using ClassStateTable = AtomicDexRefMap<ClassReference, mirror::Class::Status>; + using ClassStateTable = AtomicDexRefMap<ClassReference, ClassStatus>; ClassStateTable compiled_classes_; // All class references that are in the classpath. Indexed by class defs. ClassStateTable classpath_classes_; diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 278358b250..2698574084 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -16,11 +16,13 @@ #include "driver/compiler_driver.h" +#include <limits> #include <stdint.h> #include <stdio.h> #include <memory> #include "art_method-inl.h" +#include "base/casts.h" #include "class_linker-inl.h" #include "common_compiler_test.h" #include "compiler_callbacks.h" @@ -344,11 +346,11 @@ class CompilerDriverVerifyTest : public CompilerDriverTest { ASSERT_NE(klass, nullptr); EXPECT_TRUE(klass->IsVerified()); - mirror::Class::Status status; + ClassStatus status; bool found = compiler_driver_->GetCompiledClass( ClassReference(&klass->GetDexFile(), klass->GetDexTypeIndex().index_), &status); ASSERT_TRUE(found); - EXPECT_EQ(status, mirror::Class::kStatusVerified); + EXPECT_EQ(status, ClassStatus::kVerified); } }; @@ -367,8 +369,8 @@ TEST_F(CompilerDriverVerifyTest, VerifyCompilation) { CheckVerifiedClass(class_loader, "LSecond;"); } -// Test that a class of status kStatusRetryVerificationAtRuntime is indeed recorded that way in the -// driver. +// Test that a class of status ClassStatus::kRetryVerificationAtRuntime is indeed +// recorded that way in the driver. TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) { Thread* const self = Thread::Current(); jobject class_loader; @@ -386,17 +388,19 @@ TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) { callbacks_->SetDoesClassUnloading(true, compiler_driver_.get()); ClassReference ref(dex_file, 0u); // Test that the status is read from the compiler driver as expected. - for (size_t i = mirror::Class::kStatusRetryVerificationAtRuntime; - i < mirror::Class::kStatusMax; - ++i) { - const mirror::Class::Status expected_status = static_cast<mirror::Class::Status>(i); + static_assert(enum_cast<size_t>(ClassStatus::kLast) < std::numeric_limits<size_t>::max(), + "Make sure incrementing the class status does not overflow."); + for (size_t i = enum_cast<size_t>(ClassStatus::kRetryVerificationAtRuntime); + i <= enum_cast<size_t>(ClassStatus::kLast); + ++i) { + const ClassStatus expected_status = enum_cast<ClassStatus>(i); // Skip unsupported status that are not supposed to be ever recorded. - if (expected_status == mirror::Class::kStatusVerifyingAtRuntime || - expected_status == mirror::Class::kStatusInitializing) { + if (expected_status == ClassStatus::kVerifyingAtRuntime || + expected_status == ClassStatus::kInitializing) { continue; } compiler_driver_->RecordClassStatus(ref, expected_status); - mirror::Class::Status status = {}; + ClassStatus status = {}; ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status)); EXPECT_EQ(status, expected_status); } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index f9dcb5d6ef..13886b32b3 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2103,9 +2103,8 @@ void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCod // TODO(vixl): Let the MacroAssembler handle MemOperand. __ Add(temp, class_reg, status_offset); __ Ldarb(temp, HeapOperand(temp)); - __ Cmp(temp, mirror::Class::kStatusInitialized); - __ B(ne, slow_path->GetEntryLabel()); - // Use Bne instead of Blt because ARM64 doesn't have Ldarsb. + __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized)); + __ B(lo, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); } diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index c6e1b042a7..7f8353312f 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -7173,12 +7173,12 @@ void InstructionCodeGeneratorARMVIXL::GenerateClassInitializationCheck( LoadClassSlowPathARMVIXL* slow_path, vixl32::Register class_reg) { UseScratchRegisterScope temps(GetVIXLAssembler()); vixl32::Register temp = temps.Acquire(); - GetAssembler()->LoadFromOffset(kLoadSignedByte, + GetAssembler()->LoadFromOffset(kLoadUnsignedByte, temp, class_reg, mirror::Class::StatusOffset().Int32Value()); - __ Cmp(temp, mirror::Class::kStatusInitialized); - __ B(lt, slow_path->GetEntryLabel()); + __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized)); + __ B(lo, slow_path->GetEntryLabel()); // Even if the initialized flag is set, we may be in a situation where caches are not synced // properly. Therefore, we do a memory fence. __ Dmb(ISH); diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index c4772ad79f..ebe252a9c8 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1915,9 +1915,9 @@ void CodeGeneratorMIPS::GenerateInvokeRuntime(int32_t entry_point_offset, bool d void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg) { - __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value()); - __ LoadConst32(AT, mirror::Class::kStatusInitialized); - __ Blt(TMP, AT, slow_path->GetEntryLabel()); + __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value()); + __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized)); + __ Bltu(TMP, AT, slow_path->GetEntryLabel()); // Even if the initialized flag is set, we need to ensure consistent memory ordering. __ Sync(0); __ Bind(slow_path->GetExitLabel()); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index c8891eddfc..3ea7b827bb 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -1761,9 +1761,9 @@ void CodeGeneratorMIPS64::GenerateInvokeRuntime(int32_t entry_point_offset) { void InstructionCodeGeneratorMIPS64::GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path, GpuRegister class_reg) { - __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value()); - __ LoadConst32(AT, mirror::Class::kStatusInitialized); - __ Bltc(TMP, AT, slow_path->GetEntryLabel()); + __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value()); + __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized)); + __ Bltuc(TMP, AT, slow_path->GetEntryLabel()); // Even if the initialized flag is set, we need to ensure consistent memory ordering. __ Sync(0); __ Bind(slow_path->GetExitLabel()); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index ba222fe532..68532386e1 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -6220,8 +6220,8 @@ void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) { void InstructionCodeGeneratorX86::GenerateClassInitializationCheck( SlowPathCode* slow_path, Register class_reg) { __ cmpb(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), - Immediate(mirror::Class::kStatusInitialized)); - __ j(kLess, slow_path->GetEntryLabel()); + Immediate(enum_cast<>(ClassStatus::kInitialized))); + __ j(kBelow, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); // No need for memory fence, thanks to the X86 memory model. } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index caad7885bd..1f8d822507 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5426,8 +5426,8 @@ void ParallelMoveResolverX86_64::RestoreScratch(int reg) { void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck( SlowPathCode* slow_path, CpuRegister class_reg) { __ cmpb(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), - Immediate(mirror::Class::kStatusInitialized)); - __ j(kLess, slow_path->GetEntryLabel()); + Immediate(enum_cast<>(ClassStatus::kInitialized))); + __ j(kBelow, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); // No need for memory fence, thanks to the x86-64 memory model. } diff --git a/compiler/trampolines/trampoline_compiler.h b/compiler/trampolines/trampoline_compiler.h index 1a10e4c799..64c1eb5022 100644 --- a/compiler/trampolines/trampoline_compiler.h +++ b/compiler/trampolines/trampoline_compiler.h @@ -21,6 +21,7 @@ #include <vector> #include "driver/compiler_driver.h" +#include "offsets.h" namespace art { diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index ee1d7c69bc..d77842afe1 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -237,9 +237,9 @@ class VerifierDepsTest : public CommonCompilerTest { CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); } else if (unverified_classes.find(class_def.class_idx_) == unverified_classes.end()) { - ASSERT_EQ(cls->GetStatus(), mirror::Class::kStatusVerified); + ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerified); } else { - ASSERT_LT(cls->GetStatus(), mirror::Class::kStatusVerified); + ASSERT_LT(cls->GetStatus(), ClassStatus::kVerified); } } } diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 738bbf8e9d..363cb8b7fa 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -585,7 +585,7 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) { if (dirty_image_objects_ != nullptr && dirty_image_objects_->find(klass->PrettyDescriptor()) != dirty_image_objects_->end()) { bin = Bin::kKnownDirty; - } else if (klass->GetStatus() == Class::kStatusInitialized) { + } else if (klass->GetStatus() == ClassStatus::kInitialized) { bin = Bin::kClassInitialized; // If the class's static fields are all final, put it into a separate bin @@ -650,7 +650,7 @@ bool ImageWriter::WillMethodBeDirty(ArtMethod* m) const { } mirror::Class* declaring_class = m->GetDeclaringClass(); // Initialized is highly unlikely to dirty since there's no entry points to mutate. - return declaring_class == nullptr || declaring_class->GetStatus() != Class::kStatusInitialized; + return declaring_class == nullptr || declaring_class->GetStatus() != ClassStatus::kInitialized; } bool ImageWriter::IsImageBinSlotAssigned(mirror::Object* object) const { diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h index 3aceceb80c..a7c14395dd 100644 --- a/dex2oat/linker/image_writer.h +++ b/dex2oat/linker/image_writer.h @@ -62,6 +62,7 @@ class ClassLoader; } // namespace mirror class ClassLoaderVisitor; +class ImTable; class ImtConflictTable; static constexpr int kInvalidFd = -1; diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index d261679ac1..016a1140c2 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -188,8 +188,8 @@ class OatWriter::OatClassHeader { OatClassHeader(uint32_t offset, uint32_t num_non_null_compiled_methods, uint32_t num_methods, - mirror::Class::Status status) - : status_(status), + ClassStatus status) + : status_(enum_cast<uint16_t>(status)), offset_(offset) { // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use // kOatClassAllCompiled unless there is at least one compiled method. This means in an @@ -210,8 +210,8 @@ class OatWriter::OatClassHeader { } // Data to write. - static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits"); - int16_t status_; + static_assert(enum_cast<>(ClassStatus::kLast) < (1 << 16), "class status won't fit in 16bits"); + uint16_t status_; static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits"); uint16_t type_; @@ -931,17 +931,17 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { bool EndClass() OVERRIDE { ClassReference class_ref(dex_file_, class_def_index_); - mirror::Class::Status status; + ClassStatus status; bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status); if (!found) { VerificationResults* results = writer_->compiler_driver_->GetVerificationResults(); if (results != nullptr && results->IsClassRejected(class_ref)) { // The oat class status is used only for verification of resolved classes, - // so use kStatusErrorResolved whether the class was resolved or unresolved + // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved // during compile-time verification. - status = mirror::Class::kStatusErrorResolved; + status = ClassStatus::kErrorResolved; } else { - status = mirror::Class::kStatusNotReady; + status = ClassStatus::kNotReady; } } diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index e9958b129a..44c2f89076 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -455,7 +455,7 @@ TEST_F(OatTest, WriteRead) { ScopedNullHandle<mirror::ClassLoader>()); const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i); - CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class.GetStatus()) << descriptor; + CHECK_EQ(ClassStatus::kNotReady, oat_class.GetStatus()) << descriptor; CHECK_EQ(kCompile ? OatClassType::kOatClassAllCompiled : OatClassType::kOatClassNoneCompiled, oat_class.GetType()) << descriptor; diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc index a62cbec1be..93e02eff69 100644 --- a/runtime/aot_class_linker.cc +++ b/runtime/aot_class_linker.cc @@ -44,7 +44,7 @@ bool AotClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, // Don't initialize klass if it's superclass is not initialized, because superclass might abort // the transaction and rolled back after klass's change is commited. if (strict_mode_ && !klass->IsInterface() && klass->HasSuperClass()) { - if (klass->GetSuperClass()->GetStatus() == mirror::Class::kStatusInitializing) { + if (klass->GetSuperClass()->GetStatus() == ClassStatus::kInitializing) { runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve " + klass->PrettyTypeOf() + " because it's superclass is not initialized."); return false; @@ -79,11 +79,11 @@ verifier::FailureKind AotClassLinker::PerformClassVerification(Thread* self, ClassStatus old_status = callbacks->GetPreviousClassState( ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex())); // Was it verified? Report no failure. - if (old_status >= ClassStatus::kStatusVerified) { + if (old_status >= ClassStatus::kVerified) { return verifier::FailureKind::kNoFailure; } // Does it need to be verified at runtime? Report soft failure. - if (old_status >= ClassStatus::kStatusRetryVerificationAtRuntime) { + if (old_status >= ClassStatus::kRetryVerificationAtRuntime) { // Error messages from here are only reported through -verbose:class. It is not worth it to // create a message. return verifier::FailureKind::kSoftFailure; diff --git a/runtime/base/casts.h b/runtime/base/casts.h index ac1a10c24f..3c6b2be355 100644 --- a/runtime/base/casts.h +++ b/runtime/base/casts.h @@ -26,6 +26,8 @@ #include <android-base/logging.h> +#include "stl_util_identity.h" + namespace art { // Use implicit_cast as a safe version of static_cast or const_cast @@ -97,7 +99,7 @@ inline Dest bit_cast(const Source& source) { // A version of static_cast that DCHECKs that the value can be precisely represented // when converting to Dest. template <typename Dest, typename Source> -inline Dest dchecked_integral_cast(const Source source) { +constexpr Dest dchecked_integral_cast(Source source) { DCHECK( // Check that the value is within the lower limit of Dest. (static_cast<intmax_t>(std::numeric_limits<Dest>::min()) <= @@ -113,6 +115,33 @@ inline Dest dchecked_integral_cast(const Source source) { return static_cast<Dest>(source); } +// A version of dchecked_integral_cast casting between an integral type and an enum type. +// When casting to an enum type, the cast does not check if the value corresponds to an enumerator. +// When casting from an enum type, the target type can be omitted and the enum's underlying type +// shall be used. + +template <typename Dest, typename Source> +constexpr +typename std::enable_if<!std::is_enum<Source>::value, Dest>::type +enum_cast(Source value) { + return static_cast<Dest>( + dchecked_integral_cast<typename std::underlying_type<Dest>::type>(value)); +} + +template <typename Dest = void, typename Source> +constexpr +typename std::enable_if<std::is_enum<Source>::value, + typename std::conditional<std::is_same<Dest, void>::value, + std::underlying_type<Source>, + Identity<Dest>>::type>::type::type +enum_cast(Source value) { + using return_type = typename std::conditional<std::is_same<Dest, void>::value, + std::underlying_type<Source>, + Identity<Dest>>::type::type; + return dchecked_integral_cast<return_type>( + static_cast<typename std::underlying_type<Source>::type>(value)); +} + // A version of reinterpret_cast<>() between pointers and int64_t/uint64_t // that goes through uintptr_t to avoid treating the pointer as "signed." diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 727dd14d6a..7c0c68a4f2 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -445,7 +445,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b CHECK(java_lang_Object != nullptr); // backfill Object as the super class of Class. java_lang_Class->SetSuperClass(java_lang_Object.Get()); - mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self); + mirror::Class::SetStatus(java_lang_Object, ClassStatus::kLoaded, self); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been @@ -494,14 +494,14 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); mirror::String::SetClass(java_lang_String.Get()); - mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self); + mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self); // Setup java.lang.ref.Reference. Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_)))); mirror::Reference::SetClass(java_lang_ref_Reference.Get()); java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize()); - mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self); + mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kResolved, self); // Create storage for root classes, save away our work so far (requires descriptors). class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>( @@ -554,7 +554,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get()); java_lang_DexCache->SetDexCacheClass(); java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize()); - mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self); + mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kResolved, self); // Setup dalvik.system.ClassExt @@ -562,7 +562,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_)))); SetClassRoot(kDalvikSystemClassExt, dalvik_system_ClassExt.Get()); mirror::ClassExt::SetClass(dalvik_system_ClassExt.Get()); - mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusResolved, self); + mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kResolved, self); // Set up array classes for string, field, method Handle<mirror::Class> object_array_string(hs.NewHandle( @@ -610,15 +610,15 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b } // Object, String, ClassExt and DexCache need to be rerun through FindSystemClass to finish init - mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self); + mirror::Class::SetStatus(java_lang_Object, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;"); CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize()); - mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self); + mirror::Class::SetStatus(java_lang_String, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_String, "Ljava/lang/String;"); - mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self); + mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;"); CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize()); - mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusNotReady, self); + mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kNotReady, self); CheckSystemClass(self, dalvik_system_ClassExt, "Ldalvik/system/ClassExt;"); CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize()); @@ -772,7 +772,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // java.lang.ref classes need to be specially flagged, but otherwise are normal classes // finish initializing Reference class - mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self); + mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_ref_Reference, "Ljava/lang/ref/Reference;"); CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize()); CHECK_EQ(java_lang_ref_Reference->GetClassSize(), @@ -2309,7 +2309,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, // Check for circular dependencies between classes, the lock is required for SetStatus. if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) { ThrowClassCircularityError(h_class.Get()); - mirror::Class::SetStatus(h_class, mirror::Class::kStatusErrorUnresolved, self); + mirror::Class::SetStatus(h_class, ClassStatus::kErrorUnresolved, self); return nullptr; } } @@ -2771,7 +2771,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, // An exception occured during load, set status to erroneous while holding klass' lock in case // notification is necessary. if (!klass->IsErroneous()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); } return nullptr; } @@ -2781,7 +2781,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, if (!LoadSuperAndInterfaces(klass, *new_dex_file)) { // Loading failed. if (!klass->IsErroneous()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); } return nullptr; } @@ -2800,7 +2800,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) { // Linking failed. if (!klass->IsErroneous()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); } return nullptr; } @@ -3087,7 +3087,7 @@ void ClassLinker::SetupClass(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader) { CHECK(klass != nullptr); CHECK(klass->GetDexCache() != nullptr); - CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus()); + CHECK_EQ(ClassStatus::kNotReady, klass->GetStatus()); const char* descriptor = dex_file.GetClassDescriptor(dex_class_def); CHECK(descriptor != nullptr); @@ -3097,7 +3097,7 @@ void ClassLinker::SetupClass(const DexFile& dex_file, klass->SetAccessFlags(access_flags); klass->SetClassLoader(class_loader); DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); - mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr); + mirror::Class::SetStatus(klass, ClassStatus::kIdx, nullptr); klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def)); klass->SetDexTypeIndex(dex_class_def.class_idx_); @@ -3623,7 +3623,7 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primi h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract); h_class->SetPrimitiveType(type); h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable()); - mirror::Class::SetStatus(h_class, mirror::Class::kStatusInitialized, self); + mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self); const char* descriptor = Primitive::Descriptor(type); ObjPtr<mirror::Class> existing = InsertClass(descriptor, h_class.Get(), @@ -3738,11 +3738,11 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto } else { new_class->SetClassFlags(mirror::kClassFlagObjectArray); } - mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self); + mirror::Class::SetStatus(new_class, ClassStatus::kLoaded, self); new_class->PopulateEmbeddedVTable(image_pointer_size_); ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_); new_class->SetImt(object_imt, image_pointer_size_); - mirror::Class::SetStatus(new_class, mirror::Class::kStatusInitialized, self); + mirror::Class::SetStatus(new_class, ClassStatus::kInitialized, self); // don't need to set new_class->SetObjectSize(..) // because Object::SizeOf delegates to Array::SizeOf @@ -4000,7 +4000,7 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, } // Need to grab the lock to change status. ObjectLock<mirror::Class> super_lock(self, klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); return false; } @@ -4022,9 +4022,9 @@ verifier::FailureKind ClassLinker::VerifyClass( ObjectLock<mirror::Class> lock(self, klass); // Is somebody verifying this now? - mirror::Class::Status old_status = klass->GetStatus(); - while (old_status == mirror::Class::kStatusVerifying || - old_status == mirror::Class::kStatusVerifyingAtRuntime) { + ClassStatus old_status = klass->GetStatus(); + while (old_status == ClassStatus::kVerifying || + old_status == ClassStatus::kVerifyingAtRuntime) { lock.WaitIgnoringInterrupts(); // WaitIgnoringInterrupts can still receive an interrupt and return early, in this // case we may see the same status again. b/62912904. This is why the check is @@ -4055,18 +4055,18 @@ verifier::FailureKind ClassLinker::VerifyClass( return verifier::FailureKind::kSoftFailure; } - if (klass->GetStatus() == mirror::Class::kStatusResolved) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self); + if (klass->GetStatus() == ClassStatus::kResolved) { + mirror::Class::SetStatus(klass, ClassStatus::kVerifying, self); } else { - CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime) + CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime) << klass->PrettyClass(); CHECK(!Runtime::Current()->IsAotCompiler()); - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self); + mirror::Class::SetStatus(klass, ClassStatus::kVerifyingAtRuntime, self); } // Skip verification if disabled. if (!Runtime::Current()->IsVerificationEnabled()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); + mirror::Class::SetStatus(klass, ClassStatus::kVerified, self); EnsureSkipAccessChecksMethods(klass, image_pointer_size_); return verifier::FailureKind::kNoFailure; } @@ -4128,7 +4128,7 @@ verifier::FailureKind ClassLinker::VerifyClass( // Try to use verification information from the oat file, otherwise do runtime verification. const DexFile& dex_file = *klass->GetDexCache()->GetDexFile(); - mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady); + ClassStatus oat_file_class_status(ClassStatus::kNotReady); bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status); VLOG(class_linker) << "Class preverified status for class " @@ -4165,10 +4165,10 @@ verifier::FailureKind ClassLinker::VerifyClass( // Even though there were no verifier failures we need to respect whether the super-class and // super-default-interfaces were verified or requiring runtime reverification. if (supertype == nullptr || supertype->IsVerified()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); + mirror::Class::SetStatus(klass, ClassStatus::kVerified, self); } else { - CHECK_EQ(supertype->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime); - mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self); + CHECK_EQ(supertype->GetStatus(), ClassStatus::kRetryVerificationAtRuntime); + mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self); // Pretend a soft failure occurred so that we don't consider the class verified below. verifier_failure = verifier::FailureKind::kSoftFailure; } @@ -4178,9 +4178,9 @@ verifier::FailureKind ClassLinker::VerifyClass( // failures at runtime will be handled by slow paths in the generated // code. Set status accordingly. if (Runtime::Current()->IsAotCompiler()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self); + mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self); } else { - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); + mirror::Class::SetStatus(klass, ClassStatus::kVerified, self); // As this is a fake verified status, make sure the methods are _not_ marked // kAccSkipAccessChecks later. klass->SetVerificationAttempted(); @@ -4192,7 +4192,7 @@ verifier::FailureKind ClassLinker::VerifyClass( << " because: " << error_msg; self->AssertNoPendingException(); ThrowVerifyError(klass.Get(), "%s", error_msg.c_str()); - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); } if (preverified || verifier_failure == verifier::FailureKind::kNoFailure) { // Class is verified so we don't need to do any access check on its methods. @@ -4234,7 +4234,7 @@ verifier::FailureKind ClassLinker::PerformClassVerification(Thread* self, bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, ObjPtr<mirror::Class> klass, - mirror::Class::Status& oat_file_class_status) { + ClassStatus& oat_file_class_status) { // If we're compiling, we can only verify the class using the oat file if // we are not compiling the image or if the class we're verifying is not part of // the app. In other words, we will only check for preverification of bootclasspath @@ -4260,15 +4260,15 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, uint16_t class_def_index = klass->GetDexClassDefIndex(); oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus(); - if (oat_file_class_status >= mirror::Class::kStatusVerified) { + if (oat_file_class_status >= ClassStatus::kVerified) { return true; } // If we only verified a subset of the classes at compile time, we can end up with classes that // were resolved by the verifier. - if (oat_file_class_status == mirror::Class::kStatusResolved) { + if (oat_file_class_status == ClassStatus::kResolved) { return false; } - if (oat_file_class_status == mirror::Class::kStatusRetryVerificationAtRuntime) { + if (oat_file_class_status == ClassStatus::kRetryVerificationAtRuntime) { // Compile time verification failed with a soft error. Compile time verification can fail // because we have incomplete type information. Consider the following: // class ... { @@ -4293,7 +4293,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, // in the class. These errors are unrecoverable. return false; } - if (oat_file_class_status == mirror::Class::kStatusNotReady) { + if (oat_file_class_status == ClassStatus::kNotReady) { // Status is uninitialized if we couldn't determine the status at compile time, for example, // not loading the class. // TODO: when the verifier doesn't rely on Class-es failing to resolve/load the type hierarchy @@ -4366,7 +4366,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache()); // Object has an empty iftable, copy it for that reason. temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable()); - mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusIdx, self); + mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self); std::string descriptor(GetDescriptorForProxy(temp_klass.Get())); const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str()); @@ -4434,7 +4434,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& // The super class is java.lang.reflect.Proxy temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy)); // Now effectively in the loaded state. - mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusLoaded, self); + mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self); self->AssertNoPendingException(); // At this point the class is loaded. Publish a ClassLoad event. @@ -4450,7 +4450,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& Handle<mirror::ObjectArray<mirror::Class>> h_interfaces( hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces))); if (!LinkClass(self, descriptor.c_str(), temp_klass, h_interfaces, &klass)) { - mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusErrorUnresolved, self); + mirror::Class::SetStatus(temp_klass, ClassStatus::kErrorUnresolved, self); return nullptr; } } @@ -4471,7 +4471,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& { // Lock on klass is released. Lock new class object. ObjectLock<mirror::Class> initialization_lock(self, klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self); + mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self); } // sanity checks @@ -4687,7 +4687,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, VlogClassInitializationFailure(klass); } else { CHECK(Runtime::Current()->IsAotCompiler()); - CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime); + CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime); } return false; } else { @@ -4703,12 +4703,12 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, } } - // If the class is kStatusInitializing, either this thread is + // If the class is ClassStatus::kInitializing, either this thread is // initializing higher up the stack or another thread has beat us // to initializing and we need to wait. Either way, this // invocation of InitializeClass will not be responsible for // running <clinit> and will return. - if (klass->GetStatus() == mirror::Class::kStatusInitializing) { + if (klass->GetStatus() == ClassStatus::kInitializing) { // Could have got an exception during verification. if (self->IsExceptionPending()) { VlogClassInitializationFailure(klass); @@ -4733,20 +4733,20 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler()) ? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class) : OatFile::OatClass::Invalid(); - if (oat_class.GetStatus() < mirror::Class::kStatusSuperclassValidated && + if (oat_class.GetStatus() < ClassStatus::kSuperclassValidated && !ValidateSuperClassDescriptors(klass)) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); return false; } self->AllowThreadSuspension(); - CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << klass->PrettyClass() + CHECK_EQ(klass->GetStatus(), ClassStatus::kVerified) << klass->PrettyClass() << " self.tid=" << self->GetTid() << " clinit.tid=" << klass->GetClinitThreadId(); // From here out other threads may observe that we're initializing and so changes of state // require the a notification. klass->SetClinitThreadId(self->GetTid()); - mirror::Class::SetStatus(klass, mirror::Class::kStatusInitializing, self); + mirror::Class::SetStatus(klass, ClassStatus::kInitializing, self); t0 = NanoTime(); } @@ -4773,7 +4773,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, << (self->GetException() != nullptr ? self->GetException()->Dump() : ""); ObjectLock<mirror::Class> lock(self, klass); // Initialization failed because the super-class is erroneous. - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); return false; } } @@ -4804,7 +4804,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, if (!iface_initialized) { ObjectLock<mirror::Class> lock(self, klass); // Initialization failed because one of our interfaces with default methods is erroneous. - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); return false; } } @@ -4876,7 +4876,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, if (self->IsExceptionPending()) { WrapExceptionInInitializer(klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); success = false; } else if (Runtime::Current()->IsTransactionAborted()) { // The exception thrown when the transaction aborted has been caught and cleared @@ -4885,7 +4885,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, << mirror::Class::PrettyDescriptor(klass.Get()) << " without exception while transaction was aborted: re-throw it now."; Runtime::Current()->ThrowTransactionAbortError(self); - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); success = false; } else { RuntimeStats* global_stats = Runtime::Current()->GetStats(); @@ -4895,7 +4895,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, global_stats->class_init_time_ns += (t1 - t0); thread_stats->class_init_time_ns += (t1 - t0); // Set the class as initialized except if failed to initialize static fields. - mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self); + mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self); if (VLOG_IS_ON(class_linker)) { std::string temp; LOG(INFO) << "Initialized class " << klass->GetDescriptor(&temp) << " from " << @@ -4969,14 +4969,14 @@ bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, // we were not using WaitIgnoringInterrupts), bail out. if (self->IsExceptionPending()) { WrapExceptionInInitializer(klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self); return false; } // Spurious wakeup? Go back to waiting. - if (klass->GetStatus() == mirror::Class::kStatusInitializing) { + if (klass->GetStatus() == ClassStatus::kInitializing) { continue; } - if (klass->GetStatus() == mirror::Class::kStatusVerified && + if (klass->GetStatus() == ClassStatus::kVerified && Runtime::Current()->IsAotCompiler()) { // Compile time initialization failed. return false; @@ -5309,7 +5309,7 @@ bool ClassLinker::LinkClass(Thread* self, Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, MutableHandle<mirror::Class>* h_new_class_out) { - CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); + CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus()); if (!LinkSuperClass(klass)) { return false; @@ -5329,7 +5329,7 @@ bool ClassLinker::LinkClass(Thread* self, return false; } CreateReferenceInstanceOffsets(klass); - CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); + CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus()); ImTable* imt = nullptr; if (klass->ShouldHaveImt()) { @@ -5382,7 +5382,7 @@ bool ClassLinker::LinkClass(Thread* self, // This will notify waiters on klass that saw the not yet resolved // class in the class_table_ during EnsureResolved. - mirror::Class::SetStatus(klass, mirror::Class::kStatusResolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kResolved, self); h_new_class_out->Assign(klass.Get()); } else { CHECK(!klass->IsResolved()); @@ -5398,7 +5398,7 @@ bool ClassLinker::LinkClass(Thread* self, klass->SetIFieldsPtrUnchecked(nullptr); if (UNLIKELY(h_new_class == nullptr)) { self->AssertPendingOOMException(); - mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); + mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); return false; } @@ -5432,12 +5432,12 @@ bool ClassLinker::LinkClass(Thread* self, // This will notify waiters on temp class that saw the not yet resolved class in the // class_table_ during EnsureResolved. - mirror::Class::SetStatus(klass, mirror::Class::kStatusRetired, self); + mirror::Class::SetStatus(klass, ClassStatus::kRetired, self); - CHECK_EQ(h_new_class->GetStatus(), mirror::Class::kStatusResolving); + CHECK_EQ(h_new_class->GetStatus(), ClassStatus::kResolving); // This will notify waiters on new_class that saw the not yet resolved // class in the class_table_ during EnsureResolved. - mirror::Class::SetStatus(h_new_class, mirror::Class::kStatusResolved, self); + mirror::Class::SetStatus(h_new_class, ClassStatus::kResolved, self); // Return the new class. h_new_class_out->Assign(h_new_class.Get()); } @@ -5445,7 +5445,7 @@ bool ClassLinker::LinkClass(Thread* self, } bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) { - CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus()); + CHECK_EQ(ClassStatus::kIdx, klass->GetStatus()); const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex()); dex::TypeIndex super_class_idx = class_def.superclass_idx_; if (super_class_idx.IsValid()) { @@ -5498,7 +5498,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF } } // Mark the class as loaded. - mirror::Class::SetStatus(klass, mirror::Class::kStatusLoaded, nullptr); + mirror::Class::SetStatus(klass, ClassStatus::kLoaded, nullptr); return true; } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 10562f0890..b4e293772b 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -478,7 +478,7 @@ class ClassLinker { REQUIRES(!Locks::dex_lock_); bool VerifyClassUsingOatFile(const DexFile& dex_file, ObjPtr<mirror::Class> klass, - mirror::Class::Status& oat_file_class_status) + ClassStatus& oat_file_class_status) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass) diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 3dca2f960b..c386883474 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -86,7 +86,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_TRUE(primitive->GetSuperClass() == nullptr); EXPECT_FALSE(primitive->HasSuperClass()); EXPECT_TRUE(primitive->GetClassLoader() == nullptr); - EXPECT_EQ(mirror::Class::kStatusInitialized, primitive->GetStatus()); + EXPECT_EQ(ClassStatus::kInitialized, primitive->GetStatus()); EXPECT_FALSE(primitive->IsErroneous()); EXPECT_TRUE(primitive->IsLoaded()); EXPECT_TRUE(primitive->IsResolved()); @@ -125,7 +125,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_TRUE(JavaLangObject->GetSuperClass() == nullptr); EXPECT_FALSE(JavaLangObject->HasSuperClass()); EXPECT_TRUE(JavaLangObject->GetClassLoader() == nullptr); - EXPECT_EQ(mirror::Class::kStatusInitialized, JavaLangObject->GetStatus()); + EXPECT_EQ(ClassStatus::kInitialized, JavaLangObject->GetStatus()); EXPECT_FALSE(JavaLangObject->IsErroneous()); EXPECT_TRUE(JavaLangObject->IsLoaded()); EXPECT_TRUE(JavaLangObject->IsResolved()); @@ -200,7 +200,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_TRUE(array->HasSuperClass()); ASSERT_TRUE(array->GetComponentType() != nullptr); ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U); - EXPECT_EQ(mirror::Class::kStatusInitialized, array->GetStatus()); + EXPECT_EQ(ClassStatus::kInitialized, array->GetStatus()); EXPECT_FALSE(array->IsErroneous()); EXPECT_TRUE(array->IsLoaded()); EXPECT_TRUE(array->IsResolved()); @@ -919,7 +919,7 @@ TEST_F(ClassLinkerTest, FindClass) { EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject); EXPECT_TRUE(MyClass->HasSuperClass()); EXPECT_EQ(class_loader.Get(), MyClass->GetClassLoader()); - EXPECT_EQ(mirror::Class::kStatusResolved, MyClass->GetStatus()); + EXPECT_EQ(ClassStatus::kResolved, MyClass->GetStatus()); EXPECT_FALSE(MyClass->IsErroneous()); EXPECT_TRUE(MyClass->IsLoaded()); EXPECT_TRUE(MyClass->IsResolved()); diff --git a/runtime/class_status.h b/runtime/class_status.h index 7f2ef6a09d..ada286338b 100644 --- a/runtime/class_status.h +++ b/runtime/class_status.h @@ -24,70 +24,70 @@ namespace art { // Class Status // -// kStatusRetired: Class that's temporarily used till class linking time +// kRetired: Class that's temporarily used till class linking time // has its (vtable) size figured out and has been cloned to one with the // right size which will be the one used later. The old one is retired and // will be gc'ed once all refs to the class point to the newly // cloned version. // -// kStatusErrorUnresolved, kStatusErrorResolved: Class is erroneous. We need +// kErrorUnresolved, kErrorResolved: Class is erroneous. We need // to distinguish between classes that have been resolved and classes that // have not. This is important because the const-class instruction needs to // return a previously resolved class even if its subsequent initialization // failed. We also need this to decide whether to wrap a previous // initialization failure in ClassDefNotFound error or not. // -// kStatusNotReady: If a Class cannot be found in the class table by +// kNotReady: If a Class cannot be found in the class table by // FindClass, it allocates an new one with AllocClass in the -// kStatusNotReady and calls LoadClass. Note if it does find a -// class, it may not be kStatusResolved and it will try to push it -// forward toward kStatusResolved. +// kNotReady and calls LoadClass. Note if it does find a +// class, it may not be kResolved and it will try to push it +// forward toward kResolved. // -// kStatusIdx: LoadClass populates with Class with information from -// the DexFile, moving the status to kStatusIdx, indicating that the +// kIdx: LoadClass populates with Class with information from +// the DexFile, moving the status to kIdx, indicating that the // Class value in super_class_ has not been populated. The new Class // can then be inserted into the classes table. // -// kStatusLoaded: After taking a lock on Class, the ClassLinker will -// attempt to move a kStatusIdx class forward to kStatusLoaded by +// kLoaded: After taking a lock on Class, the ClassLinker will +// attempt to move a kIdx class forward to kLoaded by // using ResolveClass to initialize the super_class_ and ensuring the // interfaces are resolved. // -// kStatusResolving: Class is just cloned with the right size from +// kResolving: Class is just cloned with the right size from // temporary class that's acting as a placeholder for linking. The old // class will be retired. New class is set to this status first before // moving on to being resolved. // -// kStatusResolved: Still holding the lock on Class, the ClassLinker +// kResolved: Still holding the lock on Class, the ClassLinker // shows linking is complete and fields of the Class populated by making -// it kStatusResolved. Java allows circularities of the form where a super +// it kResolved. Java allows circularities of the form where a super // class has a field that is of the type of the sub class. We need to be able // to fully resolve super classes while resolving types for fields. // -// kStatusRetryVerificationAtRuntime: The verifier sets a class to +// kRetryVerificationAtRuntime: The verifier sets a class to // this state if it encounters a soft failure at compile time. This // often happens when there are unresolved classes in other dex // files, and this status marks a class as needing to be verified // again at runtime. // // TODO: Explain the other states -enum ClassStatus : int8_t { - kStatusRetired = -3, // Retired, should not be used. Use the newly cloned one instead. - kStatusErrorResolved = -2, - kStatusErrorUnresolved = -1, - kStatusNotReady = 0, - kStatusIdx = 1, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_. - kStatusLoaded = 2, // DEX idx values resolved. - kStatusResolving = 3, // Just cloned from temporary class object. - kStatusResolved = 4, // Part of linking. - kStatusVerifying = 5, // In the process of being verified. - kStatusRetryVerificationAtRuntime = 6, // Compile time verification failed, retry at runtime. - kStatusVerifyingAtRuntime = 7, // Retrying verification at runtime. - kStatusVerified = 8, // Logically part of linking; done pre-init. - kStatusSuperclassValidated = 9, // Superclass validation part of init done. - kStatusInitializing = 10, // Class init in progress. - kStatusInitialized = 11, // Ready to go. - kStatusMax = 12, +enum class ClassStatus : uint8_t { + kNotReady = 0, // Zero-initialized Class object starts in this state. + kRetired = 1, // Retired, should not be used. Use the newly cloned one instead. + kErrorResolved = 2, + kErrorUnresolved = 3, + kIdx = 4, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_. + kLoaded = 5, // DEX idx values resolved. + kResolving = 6, // Just cloned from temporary class object. + kResolved = 7, // Part of linking. + kVerifying = 8, // In the process of being verified. + kRetryVerificationAtRuntime = 9, // Compile time verification failed, retry at runtime. + kVerifyingAtRuntime = 10, // Retrying verification at runtime. + kVerified = 11, // Logically part of linking; done pre-init. + kSuperclassValidated = 12, // Superclass validation part of init done. + kInitializing = 13, // Class init in progress. + kInitialized = 14, // Ready to go. + kLast = kInitialized }; std::ostream& operator<<(std::ostream& os, const ClassStatus& rhs); diff --git a/runtime/class_table.cc b/runtime/class_table.cc index c45bbe5334..e313ec5dd7 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -79,7 +79,7 @@ mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* kl mirror::Class* const existing = existing_it->Read(); CHECK_NE(existing, klass) << descriptor; CHECK(!existing->IsResolved()) << descriptor; - CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor; + CHECK_EQ(klass->GetStatus(), ClassStatus::kResolving) << descriptor; CHECK(!klass->IsTemp()) << descriptor; VerifyObject(klass); // Update the element in the hash set with the new class. This is safe to do since the descriptor diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h index 9041df94b9..4560bca922 100644 --- a/runtime/compiler_callbacks.h +++ b/runtime/compiler_callbacks.h @@ -55,7 +55,7 @@ class CompilerCallbacks { // Return the class status of a previous stage of the compilation. This can be used, for example, // when class unloading is enabled during multidex compilation. virtual ClassStatus GetPreviousClassState(ClassReference ref ATTRIBUTE_UNUSED) { - return ClassStatus::kStatusNotReady; + return ClassStatus::kNotReady; } virtual void SetDoesClassUnloading(bool does_class_unloading ATTRIBUTE_UNUSED, diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h index e1582120dc..46630dbeef 100644 --- a/runtime/generated/asm_support_gen.h +++ b/runtime/generated/asm_support_gen.h @@ -54,8 +54,6 @@ DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET), DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_CLASS_OFFSET), (static_cast<int32_t>(art::mirror::Object::ClassOffset().Int32Value()))) #define MIRROR_OBJECT_LOCK_WORD_OFFSET 4 DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_LOCK_WORD_OFFSET), (static_cast<int32_t>(art::mirror::Object::MonitorOffset().Int32Value()))) -#define MIRROR_CLASS_STATUS_INITIALIZED 0xb -DEFINE_CHECK_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED), (static_cast<uint32_t>((art::mirror::Class::kStatusInitialized)))) #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000 DEFINE_CHECK_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), (static_cast<uint32_t>((art::kAccClassIsFinalizable)))) #define ACCESS_FLAGS_CLASS_IS_INTERFACE 0x200 diff --git a/runtime/image.cc b/runtime/image.cc index 8f35d8474c..b9d955c08c 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '1', '\0' }; // @FastNative access flags. +const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '2', '\0' }; // 4-bit ClassStatus. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h index 3d52ead0f4..263b7746db 100644 --- a/runtime/mirror/class-refvisitor-inl.h +++ b/runtime/mirror/class-refvisitor-inl.h @@ -32,12 +32,12 @@ template <bool kVisitNativeRoots, inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) { VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor); // Right after a class is allocated, but not yet loaded - // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it + // (ClassStatus::kNotReady, see ClassLinker::LoadClass()), GC may find it // and scan it. IsTemp() may call Class::GetAccessFlags() but may // fail in the DCHECK in Class::GetAccessFlags() because the class - // status is kStatusNotReady. To avoid it, rely on IsResolved() + // status is ClassStatus::kNotReady. To avoid it, rely on IsResolved() // only. This is fine because a temp class never goes into the - // kStatusResolved state. + // ClassStatus::kResolved state. if (IsResolved<kVerifyFlags>()) { // Temp classes don't ever populate imt/vtable or static fields and they are not even // allocated with the right size for those. Also, unresolved classes don't have fields diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 10daebbf5b..6bee3cf950 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -54,23 +54,6 @@ using android::base::StringPrintf; GcRoot<Class> Class::java_lang_Class_; -constexpr Class::Status Class::kStatusRetired; -constexpr Class::Status Class::kStatusErrorResolved; -constexpr Class::Status Class::kStatusErrorUnresolved; -constexpr Class::Status Class::kStatusNotReady; -constexpr Class::Status Class::kStatusIdx; -constexpr Class::Status Class::kStatusLoaded; -constexpr Class::Status Class::kStatusResolving; -constexpr Class::Status Class::kStatusResolved; -constexpr Class::Status Class::kStatusVerifying; -constexpr Class::Status Class::kStatusRetryVerificationAtRuntime; -constexpr Class::Status Class::kStatusVerifyingAtRuntime; -constexpr Class::Status Class::kStatusVerified; -constexpr Class::Status Class::kStatusSuperclassValidated; -constexpr Class::Status Class::kStatusInitializing; -constexpr Class::Status Class::kStatusInitialized; -constexpr Class::Status Class::kStatusMax; - void Class::SetClassClass(ObjPtr<Class> java_lang_Class) { CHECK(java_lang_Class_.IsNull()) << java_lang_Class_.Read() @@ -131,19 +114,19 @@ ClassExt* Class::EnsureExtDataPresent(Thread* self) { } } -void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) { - Status old_status = h_this->GetStatus(); +void Class::SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self) { + ClassStatus old_status = h_this->GetStatus(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); bool class_linker_initialized = class_linker != nullptr && class_linker->IsInitialized(); if (LIKELY(class_linker_initialized)) { if (UNLIKELY(new_status <= old_status && - new_status != kStatusErrorUnresolved && - new_status != kStatusErrorResolved && - new_status != kStatusRetired)) { + new_status != ClassStatus::kErrorUnresolved && + new_status != ClassStatus::kErrorResolved && + new_status != ClassStatus::kRetired)) { LOG(FATAL) << "Unexpected change back of class status for " << h_this->PrettyClass() << " " << old_status << " -> " << new_status; } - if (new_status >= kStatusResolved || old_status >= kStatusResolved) { + if (new_status >= ClassStatus::kResolved || old_status >= ClassStatus::kResolved) { // When classes are being resolved the resolution code should hold the lock. CHECK_EQ(h_this->GetLockOwnerThreadId(), self->GetThreadId()) << "Attempt to change status of class while not holding its lock: " @@ -155,7 +138,7 @@ void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) { << "Attempt to set as erroneous an already erroneous class " << h_this->PrettyClass() << " old_status: " << old_status << " new_status: " << new_status; - CHECK_EQ(new_status == kStatusErrorResolved, old_status >= kStatusResolved); + CHECK_EQ(new_status == ClassStatus::kErrorResolved, old_status >= ClassStatus::kResolved); if (VLOG_IS_ON(class_linker)) { LOG(ERROR) << "Setting " << h_this->PrettyDescriptor() << " to erroneous."; if (self->IsExceptionPending()) { @@ -181,7 +164,7 @@ void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) { // Setting the object size alloc fast path needs to be after the status write so that if the // alloc path sees a valid object size, we would know that it's initialized as long as it has a // load-acquire/fake dependency. - if (new_status == kStatusInitialized && !h_this->IsVariableSize()) { + if (new_status == ClassStatus::kInitialized && !h_this->IsVariableSize()) { DCHECK_EQ(h_this->GetObjectSizeAllocFastPath(), std::numeric_limits<uint32_t>::max()); // Finalizable objects must always go slow path. if (!h_this->IsFinalizable()) { @@ -199,13 +182,13 @@ void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) { if (h_this->IsTemp()) { // Class is a temporary one, ensure that waiters for resolution get notified of retirement // so that they can grab the new version of the class from the class linker's table. - CHECK_LT(new_status, kStatusResolved) << h_this->PrettyDescriptor(); - if (new_status == kStatusRetired || new_status == kStatusErrorUnresolved) { + CHECK_LT(new_status, ClassStatus::kResolved) << h_this->PrettyDescriptor(); + if (new_status == ClassStatus::kRetired || new_status == ClassStatus::kErrorUnresolved) { h_this->NotifyAll(self); } } else { - CHECK_NE(new_status, kStatusRetired); - if (old_status >= kStatusResolved || new_status >= kStatusResolved) { + CHECK_NE(new_status, ClassStatus::kRetired); + if (old_status >= ClassStatus::kResolved || new_status >= ClassStatus::kResolved) { h_this->NotifyAll(self); } } @@ -1154,7 +1137,7 @@ class CopyClassVisitor { StackHandleScope<1> hs(self_); Handle<mirror::Class> h_new_class_obj(hs.NewHandle(obj->AsClass())); Object::CopyObject(h_new_class_obj.Get(), orig_->Get(), copy_bytes_); - Class::SetStatus(h_new_class_obj, Class::kStatusResolving, self_); + Class::SetStatus(h_new_class_obj, ClassStatus::kResolving, self_); h_new_class_obj->PopulateEmbeddedVTable(pointer_size_); h_new_class_obj->SetImt(imt_, pointer_size_); h_new_class_obj->SetClassSize(new_length_); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index c545a9b7d5..95fc35dd35 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_MIRROR_CLASS_H_ #include "base/bit_utils.h" +#include "base/casts.h" #include "base/enums.h" #include "base/iteration_range.h" #include "class_flags.h" @@ -77,38 +78,16 @@ class MANAGED Class FINAL : public Object { static constexpr uint32_t kPrimitiveTypeSizeShiftShift = 16; static constexpr uint32_t kPrimitiveTypeMask = (1u << kPrimitiveTypeSizeShiftShift) - 1; - // Make ClassStatus available as Class::Status. - using Status = ClassStatus; - - // Required for a minimal change. Fix up and remove in a future change. - static constexpr Status kStatusRetired = Status::kStatusRetired; - static constexpr Status kStatusErrorResolved = Status::kStatusErrorResolved; - static constexpr Status kStatusErrorUnresolved = Status::kStatusErrorUnresolved; - static constexpr Status kStatusNotReady = Status::kStatusNotReady; - static constexpr Status kStatusIdx = Status::kStatusIdx; - static constexpr Status kStatusLoaded = Status::kStatusLoaded; - static constexpr Status kStatusResolving = Status::kStatusResolving; - static constexpr Status kStatusResolved = Status::kStatusResolved; - static constexpr Status kStatusVerifying = Status::kStatusVerifying; - static constexpr Status kStatusRetryVerificationAtRuntime = - Status::kStatusRetryVerificationAtRuntime; - static constexpr Status kStatusVerifyingAtRuntime = Status::kStatusVerifyingAtRuntime; - static constexpr Status kStatusVerified = Status::kStatusVerified; - static constexpr Status kStatusSuperclassValidated = Status::kStatusSuperclassValidated; - static constexpr Status kStatusInitializing = Status::kStatusInitializing; - static constexpr Status kStatusInitialized = Status::kStatusInitialized; - static constexpr Status kStatusMax = Status::kStatusMax; - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - Status GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) { + ClassStatus GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) { // Avoid including "subtype_check_bits_and_status.h" to get the field. // The ClassStatus is always in the least-significant bits of status_. - return static_cast<Status>(static_cast<uint8_t>( - static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff)); + return enum_cast<ClassStatus>( + static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff); } // This is static because 'this' may be moved by GC. - static void SetStatus(Handle<Class> h_this, Status new_status, Thread* self) + static void SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); static MemberOffset StatusOffset() { @@ -118,24 +97,24 @@ class MANAGED Class FINAL : public Object { // Returns true if the class has been retired. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsRetired() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() == kStatusRetired; + return GetStatus<kVerifyFlags>() == ClassStatus::kRetired; } // Returns true if the class has failed to link. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsErroneousUnresolved() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() == kStatusErrorUnresolved; + return GetStatus<kVerifyFlags>() == ClassStatus::kErrorUnresolved; } // Returns true if the class has failed to initialize. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsErroneousResolved() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() == kStatusErrorResolved; + return GetStatus<kVerifyFlags>() == ClassStatus::kErrorResolved; } // Returns true if the class status indicets that the class has failed to link or initialize. - static bool IsErroneous(Status status) { - return status == kStatusErrorUnresolved || status == kStatusErrorResolved; + static bool IsErroneous(ClassStatus status) { + return status == ClassStatus::kErrorUnresolved || status == ClassStatus::kErrorResolved; } // Returns true if the class has failed to link or initialize. @@ -147,44 +126,44 @@ class MANAGED Class FINAL : public Object { // Returns true if the class has been loaded. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsIdxLoaded() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() >= kStatusIdx; + return GetStatus<kVerifyFlags>() >= ClassStatus::kIdx; } // Returns true if the class has been loaded. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsLoaded() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() >= kStatusLoaded; + return GetStatus<kVerifyFlags>() >= ClassStatus::kLoaded; } // Returns true if the class has been linked. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsResolved() REQUIRES_SHARED(Locks::mutator_lock_) { - Status status = GetStatus<kVerifyFlags>(); - return status >= kStatusResolved || status == kStatusErrorResolved; + ClassStatus status = GetStatus<kVerifyFlags>(); + return status >= ClassStatus::kResolved || status == ClassStatus::kErrorResolved; } // Returns true if the class should be verified at runtime. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool ShouldVerifyAtRuntime() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() == kStatusRetryVerificationAtRuntime; + return GetStatus<kVerifyFlags>() == ClassStatus::kRetryVerificationAtRuntime; } // Returns true if the class has been verified. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsVerified() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() >= kStatusVerified; + return GetStatus<kVerifyFlags>() >= ClassStatus::kVerified; } // Returns true if the class is initializing. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsInitializing() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() >= kStatusInitializing; + return GetStatus<kVerifyFlags>() >= ClassStatus::kInitializing; } // Returns true if the class is initialized. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsInitialized() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetStatus<kVerifyFlags>() == kStatusInitialized; + return GetStatus<kVerifyFlags>() == ClassStatus::kInitialized; } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -333,8 +312,10 @@ class MANAGED Class FINAL : public Object { // Returns true if this class is the placeholder and should retire and // be replaced with a class with the right size for embedded imt/vtable. bool IsTemp() REQUIRES_SHARED(Locks::mutator_lock_) { - Status s = GetStatus(); - return s < Status::kStatusResolving && s != kStatusErrorResolved && ShouldHaveEmbeddedVTable(); + ClassStatus s = GetStatus(); + return s < ClassStatus::kResolving && + s != ClassStatus::kErrorResolved && + ShouldHaveEmbeddedVTable(); } String* GetName() REQUIRES_SHARED(Locks::mutator_lock_); // Returns the cached name. diff --git a/runtime/oat.h b/runtime/oat.h index 9d2118064d..7d1bf85a6c 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: .bss index mapping change. - static constexpr uint8_t kOatVersion[] = { '1', '3', '5', '\0' }; + // Last oat version changed reason: 4-bit ClassStatus. + static constexpr uint8_t kOatVersion[] = { '1', '3', '6', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index f437db281d..7a3014e210 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1654,9 +1654,8 @@ OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) con const uint8_t* status_pointer = oat_class_pointer; CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation(); - mirror::Class::Status status = - static_cast<mirror::Class::Status>(*reinterpret_cast<const int16_t*>(status_pointer)); - CHECK_LT(status, mirror::Class::kStatusMax); + ClassStatus status = enum_cast<ClassStatus>(*reinterpret_cast<const int16_t*>(status_pointer)); + CHECK_LE(status, ClassStatus::kLast); const uint8_t* type_pointer = status_pointer + sizeof(uint16_t); CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation(); @@ -1737,7 +1736,7 @@ void OatDexFile::MadviseDexFile(const DexFile& dex_file, MadviseState state) { } OatFile::OatClass::OatClass(const OatFile* oat_file, - mirror::Class::Status status, + ClassStatus status, OatClassType type, uint32_t bitmap_size, const uint32_t* bitmap_pointer, diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 1fb17a46f8..2ed1c825c6 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -24,11 +24,12 @@ #include "base/array_ref.h" #include "base/mutex.h" #include "base/stringpiece.h" +#include "class_status.h" #include "compiler_filter.h" #include "dex_file.h" #include "dex_file_layout.h" #include "index_bss_mapping.h" -#include "mirror/class.h" +#include "mirror/object.h" #include "oat.h" #include "os.h" #include "type_lookup_table.h" @@ -196,7 +197,7 @@ class OatFile { class OatClass FINAL { public: - mirror::Class::Status GetStatus() const { + ClassStatus GetStatus() const { return status_; } @@ -224,7 +225,7 @@ class OatFile { // See FindOatClass(). static OatClass Invalid() { return OatClass(/* oat_file */ nullptr, - mirror::Class::kStatusErrorUnresolved, + ClassStatus::kErrorUnresolved, kOatClassNoneCompiled, /* bitmap_size */ 0, /* bitmap_pointer */ nullptr, @@ -233,7 +234,7 @@ class OatFile { private: OatClass(const OatFile* oat_file, - mirror::Class::Status status, + ClassStatus status, OatClassType type, uint32_t bitmap_size, const uint32_t* bitmap_pointer, @@ -241,7 +242,7 @@ class OatFile { const OatFile* const oat_file_; - const mirror::Class::Status status_; + const ClassStatus status_; const OatClassType type_; diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc index 304017eadb..0bad548ed8 100644 --- a/runtime/transaction_test.cc +++ b/runtime/transaction_test.cc @@ -66,7 +66,7 @@ class TransactionTest : public CommonRuntimeTest { class_linker_->VerifyClass(soa.Self(), h_klass); ASSERT_TRUE(h_klass->IsVerified()); - mirror::Class::Status old_status = h_klass->GetStatus(); + ClassStatus old_status = h_klass->GetStatus(); LockWord old_lock_word = h_klass->GetLockWord(false); Runtime::Current()->EnterTransactionMode(); diff --git a/test/008-exceptions/src/Main.java b/test/008-exceptions/src/Main.java index 89fe016856..008576acc3 100644 --- a/test/008-exceptions/src/Main.java +++ b/test/008-exceptions/src/Main.java @@ -158,8 +158,8 @@ public class Main { t.printStackTrace(System.out); } try { - // Before splitting mirror::Class::kStatusError into - // kStatusErrorUnresolved and kStatusErrorResolved, + // Before splitting ClassStatus::kError into + // ClassStatus::kErrorUnresolved and ClassStatus::kErrorResolved, // this would trigger a // CHECK(super_class->IsResolved()) // failure in @@ -188,8 +188,8 @@ public class Main { } catch (Throwable t) { t.printStackTrace(System.out); } - // Before splitting mirror::Class::kStatusError into - // kStatusErrorUnresolved and kStatusErrorResolved, + // Before splitting ClassStatus::kError into + // ClassStatus::kErrorUnresolved and ClassStatus::kErrorResolved, // the exception from wrapper 1 would have been // wrapped in NoClassDefFoundError but the exception // from wrapper 2 would have been unwrapped. diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc index e1af02edfd..96ef2665cb 100644 --- a/test/626-const-class-linking/clear_dex_cache_types.cc +++ b/test/626-const-class-linking/clear_dex_cache_types.cc @@ -36,10 +36,10 @@ extern "C" JNIEXPORT void JNICALL Java_Main_nativeSkipVerification(JNIEnv*, jcla ScopedObjectAccess soa(Thread::Current()); StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> klass = hs.NewHandle(soa.Decode<mirror::Class>(cls)); - mirror::Class::Status status = klass->GetStatus(); - if (status == mirror::Class::kStatusResolved) { + ClassStatus status = klass->GetStatus(); + if (status == ClassStatus::kResolved) { ObjectLock<mirror::Class> lock(soa.Self(), klass); - klass->SetStatus(klass, mirror::Class::kStatusVerified, soa.Self()); + klass->SetStatus(klass, ClassStatus::kVerified, soa.Self()); } else { LOG(ERROR) << klass->PrettyClass() << " has unexpected status: " << status; } diff --git a/tools/cpp-define-generator/constant_class.def b/tools/cpp-define-generator/constant_class.def index f46cd339b0..4f1d875e5a 100644 --- a/tools/cpp-define-generator/constant_class.def +++ b/tools/cpp-define-generator/constant_class.def @@ -15,7 +15,6 @@ */ #if defined(DEFINE_INCLUDE_DEPENDENCIES) -#include "mirror/class.h" // kStatusInitialized #include "modifiers.h" // kAccClassIsFinalizable #include "base/bit_utils.h" // MostSignificantBit #endif @@ -23,7 +22,6 @@ #define DEFINE_FLAG_OFFSET(type_name, field_name, expr) \ DEFINE_EXPR(type_name ## _ ## field_name, uint32_t, (expr)) -DEFINE_FLAG_OFFSET(MIRROR_CLASS, STATUS_INITIALIZED, art::mirror::Class::kStatusInitialized) DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_FINALIZABLE, art::kAccClassIsFinalizable) DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_INTERFACE, art::kAccInterface) // TODO: We should really have a BitPosition which also checks it's a power of 2. |