Add strict flag in transaction

Add a flag named strict_ indicating whether we are compiling app images,
which need more strict constraints to control <clinit>s' behavours.

When the transaction is marked as strict mode, behaviour changes
including nested transactions, field access validation, memory
consumption limit and time out for <clinit> at compile time.

Test: make test-art-host -j64

Change-Id: I7cc0eea161803ad0d7763725d4deaeee21858054
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index ed36e11..a932e38 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2332,7 +2332,7 @@
             // checks in Thread::AssertThreadSuspensionIsAllowable.
             Runtime* const runtime = Runtime::Current();
             // Run the class initializer in transaction mode.
-            runtime->EnterTransactionMode(klass.Get());
+            runtime->EnterTransactionMode(is_app_image, klass.Get());
             bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true,
                                                                          true);
             // TODO we detach transaction from runtime to indicate we quit the transactional
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6fbf64b..5018eae 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2068,9 +2068,9 @@
   preinitialization_transaction_ = std::make_unique<Transaction>();
 }
 
-void Runtime::EnterTransactionMode(mirror::Class* root) {
+void Runtime::EnterTransactionMode(bool strict, mirror::Class* root) {
   DCHECK(IsAotCompiler());
-  preinitialization_transaction_ = std::make_unique<Transaction>(root);
+  preinitialization_transaction_ = std::make_unique<Transaction>(strict, root);
 }
 
 void Runtime::ExitTransactionMode() {
@@ -2095,6 +2095,10 @@
   }
 }
 
+bool Runtime::IsActiveStrictTransactionMode() const {
+  return IsActiveTransaction() && preinitialization_transaction_->IsStrict();
+}
+
 void Runtime::AbortTransactionAndThrowAbortError(Thread* self, const std::string& abort_message) {
   DCHECK(IsAotCompiler());
   DCHECK(IsActiveTransaction());
@@ -2418,5 +2422,4 @@
     GetClassLinker()->VisitClasses(&visitor);
   }
 }
-
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 7e4b896..7ee73e8 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -458,12 +458,13 @@
     return preinitialization_transaction_ != nullptr;
   }
   void EnterTransactionMode();
-  void EnterTransactionMode(mirror::Class* root);
+  void EnterTransactionMode(bool strict, mirror::Class* root);
   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;
+  bool IsActiveStrictTransactionMode() const;
 
   void AbortTransactionAndThrowAbortError(Thread* self, const std::string& abort_message)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index 9e62aa6..b4e35cd 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -34,11 +34,14 @@
 static constexpr bool kEnableTransactionStats = false;
 
 Transaction::Transaction()
-  : log_lock_("transaction log lock", kTransactionLogLock), aborted_(false) {
+  : log_lock_("transaction log lock", kTransactionLogLock),
+    aborted_(false),
+    strict_(false) {
   CHECK(Runtime::Current()->IsAotCompiler());
 }
 
-Transaction::Transaction(mirror::Class* root) : Transaction() {
+Transaction::Transaction(bool strict, mirror::Class* root) : Transaction() {
+  strict_ = strict;
   root_ = root;
 }
 
@@ -101,6 +104,11 @@
   return aborted_;
 }
 
+bool Transaction::IsStrict() {
+  MutexLock mu(Thread::Current(), log_lock_);
+  return strict_;
+}
+
 const std::string& Transaction::GetAbortMessage() {
   MutexLock mu(Thread::Current(), log_lock_);
   return abort_message_;
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 22518f6..fb0d1ec 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -45,7 +45,7 @@
   static constexpr const char* kAbortExceptionSignature = "Ldalvik/system/TransactionAbortError;";
 
   Transaction();
-  explicit Transaction(mirror::Class* root);
+  explicit Transaction(bool strict, mirror::Class* root);
   ~Transaction();
 
   void Abort(const std::string& abort_message)
@@ -56,6 +56,11 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
   bool IsAborted() REQUIRES(!log_lock_);
 
+  // If the transaction is in strict mode, then all access of static fields will be constrained,
+  // one class's clinit will not be allowed to read or modify another class's static fields, unless
+  // the transaction is aborted.
+  bool IsStrict() REQUIRES(!log_lock_);
+
   // Record object field changes.
   void RecordWriteFieldBoolean(mirror::Object* obj,
                                MemberOffset field_offset,
@@ -289,6 +294,7 @@
   std::list<InternStringLog> intern_string_logs_ GUARDED_BY(log_lock_);
   std::list<ResolveStringLog> resolve_string_logs_ GUARDED_BY(log_lock_);
   bool aborted_ GUARDED_BY(log_lock_);
+  bool strict_ GUARDED_BY(log_lock_);
   std::string abort_message_ GUARDED_BY(log_lock_);
   mirror::Class* root_ GUARDED_BY(log_lock_);