Update Transaction for boot image extension.

And clean up transaction-related code to keep test code
out of the production binaries.

Test: Add TransactionTest#Constraints to transaction_test.
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: aosp_taimen-userdebug boots.
Change-Id: Iefe5f1cfde95f564069249148f9e7d71564d7a10
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 9953743..e017b17 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -109,7 +109,7 @@
   if (is_static) {
     obj = f->GetDeclaringClass();
     if (transaction_active) {
-      if (Runtime::Current()->GetTransaction()->ReadConstraint(obj.Ptr(), f)) {
+      if (Runtime::Current()->GetTransaction()->ReadConstraint(self, obj, f)) {
         Runtime::Current()->AbortTransactionAndThrowAbortError(self, "Can't read static fields of "
             + obj->PrettyTypeOf() + " since it does not belong to clinit's class.");
         return false;
@@ -321,14 +321,6 @@
   ObjPtr<mirror::Object> obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
-    if (transaction_active) {
-      if (Runtime::Current()->GetTransaction()->WriteConstraint(obj.Ptr(), f)) {
-        Runtime::Current()->AbortTransactionAndThrowAbortError(
-            self, "Can't set fields of " + obj->PrettyTypeOf());
-        return false;
-      }
-    }
-
   } else {
     obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
     if (UNLIKELY(obj == nullptr)) {
@@ -336,6 +328,22 @@
       return false;
     }
   }
+  if (transaction_active) {
+    Runtime* runtime = Runtime::Current();
+    if (runtime->GetTransaction()->WriteConstraint(self, obj, f)) {
+      if (is_static) {
+        runtime->AbortTransactionAndThrowAbortError(
+            self, "Can't set fields of " + obj->PrettyTypeOf());
+      } else {
+        // This can happen only when compiling a boot image extension.
+        DCHECK(!runtime->GetTransaction()->IsStrict());
+        DCHECK(runtime->GetHeap()->ObjectIsInBootImageSpace(obj));
+        runtime->AbortTransactionAndThrowAbortError(
+            self, "Can't set fields of boot image objects");
+      }
+      return false;
+    }
+  }
 
   uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   JValue value = GetFieldValue<field_type>(shadow_frame, vregA);
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 495039c..4429f63 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -785,19 +785,19 @@
     {
       JValue result;
       tmp->SetVReg(0, static_cast<int32_t>(i));
-      Runtime::Current()->EnterTransactionMode();
+      EnterTransactionMode();
       UnstartedCharacterToLowerCase(self, tmp.get(), &result, 0);
-      ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
-      Runtime::Current()->ExitTransactionMode();
+      ASSERT_TRUE(IsTransactionAborted());
+      ExitTransactionMode();
       ASSERT_TRUE(self->IsExceptionPending());
     }
     {
       JValue result;
       tmp->SetVReg(0, static_cast<int32_t>(i));
-      Runtime::Current()->EnterTransactionMode();
+      EnterTransactionMode();
       UnstartedCharacterToUpperCase(self, tmp.get(), &result, 0);
-      ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
-      Runtime::Current()->ExitTransactionMode();
+      ASSERT_TRUE(IsTransactionAborted());
+      ExitTransactionMode();
       ASSERT_TRUE(self->IsExceptionPending());
     }
   }
@@ -805,19 +805,19 @@
     {
       JValue result;
       tmp->SetVReg(0, static_cast<int32_t>(i));
-      Runtime::Current()->EnterTransactionMode();
+      EnterTransactionMode();
       UnstartedCharacterToLowerCase(self, tmp.get(), &result, 0);
-      ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
-      Runtime::Current()->ExitTransactionMode();
+      ASSERT_TRUE(IsTransactionAborted());
+      ExitTransactionMode();
       ASSERT_TRUE(self->IsExceptionPending());
     }
     {
       JValue result;
       tmp->SetVReg(0, static_cast<int32_t>(i));
-      Runtime::Current()->EnterTransactionMode();
+      EnterTransactionMode();
       UnstartedCharacterToUpperCase(self, tmp.get(), &result, 0);
-      ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
-      Runtime::Current()->ExitTransactionMode();
+      ASSERT_TRUE(IsTransactionAborted());
+      ExitTransactionMode();
       ASSERT_TRUE(self->IsExceptionPending());
     }
   }
@@ -980,10 +980,10 @@
     UniqueDeoptShadowFramePtr caller_frame = CreateShadowFrame(10, nullptr, caller_method, 0);
     shadow_frame->SetLink(caller_frame.get());
 
-    Runtime::Current()->EnterTransactionMode();
+    EnterTransactionMode();
     UnstartedThreadLocalGet(self, shadow_frame.get(), &result, 0);
-    ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
-    Runtime::Current()->ExitTransactionMode();
+    ASSERT_TRUE(IsTransactionAborted());
+    ExitTransactionMode();
     ASSERT_TRUE(self->IsExceptionPending());
     self->ClearException();
 
@@ -1050,10 +1050,10 @@
   PrepareForAborts();
 
   {
-    Runtime::Current()->EnterTransactionMode();
+    EnterTransactionMode();
     UnstartedThreadCurrentThread(self, shadow_frame.get(), &result, 0);
-    ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
-    Runtime::Current()->ExitTransactionMode();
+    ASSERT_TRUE(IsTransactionAborted());
+    ExitTransactionMode();
     ASSERT_TRUE(self->IsExceptionPending());
     self->ClearException();
   }
@@ -1120,7 +1120,7 @@
       CHECK(name_string != nullptr);
 
       if (in_transaction) {
-        Runtime::Current()->EnterTransactionMode();
+        EnterTransactionMode();
       }
       CHECK(!self->IsExceptionPending());
 
@@ -1132,13 +1132,13 @@
       } else {
         CHECK(self->IsExceptionPending()) << name;
         if (in_transaction) {
-          ASSERT_TRUE(Runtime::Current()->IsTransactionAborted());
+          ASSERT_TRUE(IsTransactionAborted());
         }
         self->ClearException();
       }
 
       if (in_transaction) {
-        Runtime::Current()->ExitTransactionMode();
+        ExitTransactionMode();
       }
     }
   }