diff options
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 12 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime_test.cc | 43 | ||||
| -rw-r--r-- | runtime/runtime.cc | 14 | ||||
| -rw-r--r-- | runtime/runtime.h | 8 | ||||
| -rw-r--r-- | runtime/transaction_test.cc | 59 |
5 files changed, 61 insertions, 75 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index cf04e41d5c..7970b4ca5d 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2331,10 +2331,8 @@ class InitializeClassVisitor : public CompilationVisitor { // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity // checks in Thread::AssertThreadSuspensionIsAllowable. Runtime* const runtime = Runtime::Current(); - Transaction transaction; - // Run the class initializer in transaction mode. - runtime->EnterTransactionMode(&transaction); + runtime->EnterTransactionMode(); bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true, true); // TODO we detach transaction from runtime to indicate we quit the transactional @@ -2343,7 +2341,11 @@ class InitializeClassVisitor : public CompilationVisitor { { ScopedAssertNoThreadSuspension ants("Transaction end"); - runtime->ExitTransactionMode(); + + if (success) { + runtime->ExitTransactionMode(); + DCHECK(!runtime->IsActiveTransaction()); + } if (!success) { CHECK(soa.Self()->IsExceptionPending()); @@ -2357,7 +2359,7 @@ class InitializeClassVisitor : public CompilationVisitor { *file_log << exception->Dump() << "\n"; } soa.Self()->ClearException(); - transaction.Rollback(); + runtime->RollbackAndExitTransactionMode(); CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored"; } else if (is_boot_image) { // For boot image, we want to put the updated status in the oat class since we can't diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 3461a6503a..87fa8beb01 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -780,44 +780,40 @@ TEST_F(UnstartedRuntimeTest, ToLowerUpper) { { JValue result; tmp->SetVReg(0, static_cast<int32_t>(i)); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); UnstartedCharacterToLowerCase(self, tmp, &result, 0); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(self->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); } { JValue result; tmp->SetVReg(0, static_cast<int32_t>(i)); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); UnstartedCharacterToUpperCase(self, tmp, &result, 0); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(self->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); } } for (uint64_t i = 256; i <= std::numeric_limits<uint32_t>::max(); i <<= 1) { { JValue result; tmp->SetVReg(0, static_cast<int32_t>(i)); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); UnstartedCharacterToLowerCase(self, tmp, &result, 0); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(self->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); } { JValue result; tmp->SetVReg(0, static_cast<int32_t>(i)); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); UnstartedCharacterToUpperCase(self, tmp, &result, 0); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(self->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); } } @@ -996,12 +992,11 @@ TEST_F(UnstartedRuntimeTest, ThreadLocalGet) { ShadowFrame* caller_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, caller_method, 0); shadow_frame->SetLink(caller_frame); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); UnstartedThreadLocalGet(self, shadow_frame, &result, 0); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(self->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); self->ClearException(); ShadowFrame::DeleteDeoptimizedFrame(caller_frame); @@ -1066,12 +1061,11 @@ TEST_F(UnstartedRuntimeTest, ThreadCurrentThread) { PrepareForAborts(); { - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); UnstartedThreadCurrentThread(self, shadow_frame, &result, 0); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(self->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); self->ClearException(); } @@ -1138,28 +1132,27 @@ class UnstartedClassForNameTest : public UnstartedRuntimeTest { mirror::String* name_string = mirror::String::AllocFromModifiedUtf8(self, name); CHECK(name_string != nullptr); - Transaction transaction; if (in_transaction) { - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); } CHECK(!self->IsExceptionPending()); runner(self, shadow_frame, name_string, &result); - if (in_transaction) { - Runtime::Current()->ExitTransactionMode(); - } - if (should_succeed) { CHECK(!self->IsExceptionPending()) << name << " " << self->GetException()->Dump(); CHECK(result.GetL() != nullptr) << name; } else { CHECK(self->IsExceptionPending()) << name; if (in_transaction) { - ASSERT_TRUE(transaction.IsAborted()); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); } self->ClearException(); } + + if (in_transaction) { + Runtime::Current()->ExitTransactionMode(); + } } ShadowFrame::DeleteDeoptimizedFrame(shadow_frame); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index ebee5ea187..01b87b932b 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -2065,19 +2065,25 @@ void Runtime::RegisterAppInfo(const std::vector<std::string>& code_paths, } // Transaction support. -void Runtime::EnterTransactionMode(Transaction* transaction) { +void Runtime::EnterTransactionMode() { DCHECK(IsAotCompiler()); - DCHECK(transaction != nullptr); DCHECK(!IsActiveTransaction()); - preinitialization_transaction_ = transaction; + preinitialization_transaction_ = std::make_unique<Transaction>(); } void Runtime::ExitTransactionMode() { DCHECK(IsAotCompiler()); - DCHECK(IsActiveTransaction()); preinitialization_transaction_ = nullptr; } +void Runtime::RollbackAndExitTransactionMode() { + DCHECK(IsAotCompiler()); + DCHECK(IsActiveTransaction()); + std::unique_ptr<Transaction> rollback_transaction_= std::move(preinitialization_transaction_); + ExitTransactionMode(); + rollback_transaction_->Rollback(); +} + bool Runtime::IsTransactionAborted() const { if (!IsActiveTransaction()) { return false; diff --git a/runtime/runtime.h b/runtime/runtime.h index af9d215454..0200dc03bd 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -24,6 +24,7 @@ #include <set> #include <string> #include <utility> +#include <memory> #include <vector> #include "arch/instruction_set.h" @@ -457,8 +458,11 @@ class Runtime { bool IsActiveTransaction() const { return preinitialization_transaction_ != nullptr; } - void EnterTransactionMode(Transaction* transaction); + void EnterTransactionMode(); void ExitTransactionMode(); + // Transaction rollback and exit transaction are always done together, it's convenience to + // do them in one function. + void RollbackAndExitTransactionMode() REQUIRES_SHARED(Locks::mutator_lock_); bool IsTransactionAborted() const; void AbortTransactionAndThrowAbortError(Thread* self, const std::string& abort_message) @@ -842,7 +846,7 @@ class Runtime { bool dump_gc_performance_on_shutdown_; // Transaction used for pre-initializing classes at compilation time. - Transaction* preinitialization_transaction_; + std::unique_ptr<Transaction> preinitialization_transaction_; // If kNone, verification is disabled. kEnable by default. verifier::VerifyMode verify_; diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc index 920629276a..e52dd08540 100644 --- a/runtime/transaction_test.cc +++ b/runtime/transaction_test.cc @@ -69,14 +69,12 @@ class TransactionTest : public CommonRuntimeTest { mirror::Class::Status old_status = h_klass->GetStatus(); LockWord old_lock_word = h_klass->GetLockWord(false); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); bool success = class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true); - Runtime::Current()->ExitTransactionMode(); + ASSERT_TRUE(Runtime::Current()->IsTransactionAborted()); ASSERT_FALSE(success); ASSERT_TRUE(h_klass->IsErroneous()); ASSERT_TRUE(soa.Self()->IsExceptionPending()); - ASSERT_TRUE(transaction.IsAborted()); // Check class's monitor get back to its original state without rolling back changes. LockWord new_lock_word = h_klass->GetLockWord(false); @@ -84,7 +82,7 @@ class TransactionTest : public CommonRuntimeTest { // Check class status is rolled back properly. soa.Self()->ClearException(); - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); ASSERT_EQ(old_status, h_klass->GetStatus()); } }; @@ -97,15 +95,12 @@ TEST_F(TransactionTest, Object_class) { hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"))); ASSERT_TRUE(h_klass != nullptr); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); Handle<mirror::Object> h_obj(hs.NewHandle(h_klass->AllocObject(soa.Self()))); ASSERT_TRUE(h_obj != nullptr); ASSERT_EQ(h_obj->GetClass(), h_klass.Get()); - Runtime::Current()->ExitTransactionMode(); - // Rolling back transaction's changes must not clear the Object::class field. - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); EXPECT_EQ(h_obj->GetClass(), h_klass.Get()); } @@ -124,15 +119,13 @@ TEST_F(TransactionTest, Object_monitor) { h_obj->MonitorEnter(soa.Self()); LockWord old_lock_word = h_obj->GetLockWord(false); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); // Unlock object's monitor inside the transaction. h_obj->MonitorExit(soa.Self()); LockWord new_lock_word = h_obj->GetLockWord(false); - Runtime::Current()->ExitTransactionMode(); - // Rolling back transaction's changes must not change monitor's state. - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); + LockWord aborted_lock_word = h_obj->GetLockWord(false); EXPECT_FALSE(LockWord::Equal<false>(old_lock_word, new_lock_word)); EXPECT_TRUE(LockWord::Equal<false>(aborted_lock_word, new_lock_word)); @@ -148,8 +141,7 @@ TEST_F(TransactionTest, Array_length) { constexpr int32_t kArraySize = 2; - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); // Allocate an array during transaction. Handle<mirror::Array> h_obj( @@ -159,10 +151,9 @@ TEST_F(TransactionTest, Array_length) { Runtime::Current()->GetHeap()->GetCurrentAllocator()))); ASSERT_TRUE(h_obj != nullptr); ASSERT_EQ(h_obj->GetClass(), h_klass.Get()); - Runtime::Current()->ExitTransactionMode(); + Runtime::Current()->RollbackAndExitTransactionMode(); // Rolling back transaction's changes must not reset array's length. - transaction.Rollback(); EXPECT_EQ(h_obj->GetLength(), kArraySize); } @@ -238,8 +229,7 @@ TEST_F(TransactionTest, StaticFieldsTest) { ASSERT_EQ(h_obj->GetClass(), h_klass.Get()); // Modify fields inside transaction then rollback changes. - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); booleanField->SetBoolean<true>(h_klass.Get(), true); byteField->SetByte<true>(h_klass.Get(), 1); charField->SetChar<true>(h_klass.Get(), 1u); @@ -249,8 +239,7 @@ TEST_F(TransactionTest, StaticFieldsTest) { floatField->SetFloat<true>(h_klass.Get(), 1.0); doubleField->SetDouble<true>(h_klass.Get(), 1.0); objectField->SetObject<true>(h_klass.Get(), h_obj.Get()); - Runtime::Current()->ExitTransactionMode(); - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); // Check values have properly been restored to their original (default) value. EXPECT_EQ(booleanField->GetBoolean(h_klass.Get()), false); @@ -340,8 +329,7 @@ TEST_F(TransactionTest, InstanceFieldsTest) { ASSERT_EQ(h_obj->GetClass(), h_klass.Get()); // Modify fields inside transaction then rollback changes. - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); booleanField->SetBoolean<true>(h_instance.Get(), true); byteField->SetByte<true>(h_instance.Get(), 1); charField->SetChar<true>(h_instance.Get(), 1u); @@ -351,8 +339,7 @@ TEST_F(TransactionTest, InstanceFieldsTest) { floatField->SetFloat<true>(h_instance.Get(), 1.0); doubleField->SetDouble<true>(h_instance.Get(), 1.0); objectField->SetObject<true>(h_instance.Get(), h_obj.Get()); - Runtime::Current()->ExitTransactionMode(); - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); // Check values have properly been restored to their original (default) value. EXPECT_EQ(booleanField->GetBoolean(h_instance.Get()), false); @@ -457,8 +444,7 @@ TEST_F(TransactionTest, StaticArrayFieldsTest) { ASSERT_EQ(h_obj->GetClass(), h_klass.Get()); // Modify fields inside transaction then rollback changes. - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); booleanArray->SetWithoutChecks<true>(0, true); byteArray->SetWithoutChecks<true>(0, 1); charArray->SetWithoutChecks<true>(0, 1u); @@ -468,8 +454,7 @@ TEST_F(TransactionTest, StaticArrayFieldsTest) { floatArray->SetWithoutChecks<true>(0, 1.0); doubleArray->SetWithoutChecks<true>(0, 1.0); objectArray->SetWithoutChecks<true>(0, h_obj.Get()); - Runtime::Current()->ExitTransactionMode(); - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); // Check values have properly been restored to their original (default) value. EXPECT_EQ(booleanArray->GetWithoutChecks(0), false); @@ -511,8 +496,7 @@ TEST_F(TransactionTest, ResolveString) { EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache.Get()) == nullptr); EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr); // Do the transaction, then roll back. - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); bool success = class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true); ASSERT_TRUE(success); ASSERT_TRUE(h_klass->IsInitialized()); @@ -523,8 +507,7 @@ TEST_F(TransactionTest, ResolveString) { EXPECT_STREQ(s->ToModifiedUtf8().c_str(), kResolvedString); EXPECT_EQ(s, h_dex_cache->GetResolvedString(string_idx)); } - Runtime::Current()->ExitTransactionMode(); - transaction.Rollback(); + Runtime::Current()->RollbackAndExitTransactionMode(); // Check that the string did not stay resolved. EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache.Get()) == nullptr); EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr); @@ -547,8 +530,7 @@ TEST_F(TransactionTest, EmptyClass) { class_linker_->VerifyClass(soa.Self(), h_klass); ASSERT_TRUE(h_klass->IsVerified()); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); bool success = class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(success); @@ -571,8 +553,7 @@ TEST_F(TransactionTest, StaticFieldClass) { class_linker_->VerifyClass(soa.Self(), h_klass); ASSERT_TRUE(h_klass->IsVerified()); - Transaction transaction; - Runtime::Current()->EnterTransactionMode(&transaction); + Runtime::Current()->EnterTransactionMode(); bool success = class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true); Runtime::Current()->ExitTransactionMode(); ASSERT_TRUE(success); |