Introduce -Xint flag for ART.

Change-Id: I0f7d8c0b0f33e77ca2d3fbf05b7a16fedb86a545
diff --git a/src/object.cc b/src/object.cc
index aaaa245..4eb5066 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -657,33 +657,41 @@
   // Pass everything as arguments.
   AbstractMethod::InvokeStub* stub = GetInvokeStub();
 
-
   if (UNLIKELY(!Runtime::Current()->IsStarted())){
-    LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started.";
+    LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started";
     if (result != NULL) {
       result->SetJ(0);
     }
   } else {
-    if (GetCode() != NULL && stub != NULL) {
-      bool log = false;
-      if (log) {
-        LOG(INFO) << StringPrintf("invoking %s code=%p stub=%p",
+    bool interpret = self->ReadFlag(kEnterInterpreter);
+    const bool kLogInvocationStartAndReturn = false;
+    if (!interpret && GetCode() != NULL && stub != NULL) {
+      if (kLogInvocationStartAndReturn) {
+        LOG(INFO) << StringPrintf("Invoking '%s' code=%p stub=%p",
                                   PrettyMethod(this).c_str(), GetCode(), stub);
       }
       (*stub)(this, receiver, self, args, result);
-      if (log) {
-        LOG(INFO) << StringPrintf("returned %s code=%p stub=%p",
+      if (kLogInvocationStartAndReturn) {
+        LOG(INFO) << StringPrintf("Returned '%s' code=%p stub=%p",
                                   PrettyMethod(this).c_str(), GetCode(), stub);
       }
     } else {
-      LOG(INFO) << "Not invoking " << PrettyMethod(this)
-          << " code=" << reinterpret_cast<const void*>(GetCode())
-          << " stub=" << reinterpret_cast<void*>(stub);
       const bool kInterpretMethodsWithNoCode = false;
-      if (kInterpretMethodsWithNoCode) {
+      if (interpret || kInterpretMethodsWithNoCode) {
+        if (kLogInvocationStartAndReturn) {
+          LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
+        }
         art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args, result);
-      } else if (result != NULL) {
+        if (kLogInvocationStartAndReturn) {
+          LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
+        }
+      } else {
+        LOG(INFO) << "Not invoking '" << PrettyMethod(this)
+              << "' code=" << reinterpret_cast<const void*>(GetCode())
+              << " stub=" << reinterpret_cast<void*>(stub);
+        if (result != NULL) {
           result->SetJ(0);
+        }
       }
     }
   }
diff --git a/src/runtime.cc b/src/runtime.cc
index 4cc3b4f..ec2f569 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -364,6 +364,7 @@
 
   parsed->is_compiler_ = false;
   parsed->is_zygote_ = false;
+  parsed->interpreter_only_ = false;
   parsed->is_concurrent_gc_enabled_ = true;
 
   parsed->jni_globals_max_ = 0;
@@ -508,6 +509,8 @@
       parsed->is_compiler_ = true;
     } else if (option == "-Xzygote") {
       parsed->is_zygote_ = true;
+    } else if (option == "-Xint") {
+      parsed->interpreter_only_ = true;
     } else if (StartsWith(option, "-Xgc:")) {
       std::vector<std::string> gc_options;
       Split(option.substr(strlen("-Xgc:")), ',', gc_options);
@@ -756,6 +759,7 @@
 
   is_compiler_ = options->is_compiler_;
   is_zygote_ = options->is_zygote_;
+  interpreter_only_ = options->interpreter_only_;
   is_concurrent_gc_enabled_ = options->is_concurrent_gc_enabled_;
 
   vfprintf_ = options->hook_vfprintf_;
diff --git a/src/runtime.h b/src/runtime.h
index d2238ae..79c0592 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -76,6 +76,7 @@
     std::string jni_trace_;
     bool is_compiler_;
     bool is_zygote_;
+    bool interpreter_only_;
     bool is_concurrent_gc_enabled_;
     size_t heap_initial_size_;
     size_t heap_maximum_size_;
@@ -112,6 +113,10 @@
     return is_zygote_;
   }
 
+  bool InterpreterOnly() const {
+    return interpreter_only_;
+  }
+
   bool IsConcurrentGcEnabled() const {
     return is_concurrent_gc_enabled_;
   }
@@ -377,6 +382,7 @@
 
   bool is_compiler_;
   bool is_zygote_;
+  bool interpreter_only_;
   bool is_concurrent_gc_enabled_;
 
   // The host prefix is used during cross compilation. It is removed
diff --git a/src/thread.cc b/src/thread.cc
index 744a8aa..8037886 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -288,13 +288,14 @@
   // we can handshake with the corresponding native thread when it's ready.) Check this native
   // thread hasn't been through here already...
   CHECK(Thread::Current() == NULL);
-
   SetUpAlternateSignalStack();
   InitCpu();
   InitFunctionPointers();
   InitCardTable();
   InitTid();
-
+  if (Runtime::Current()->InterpreterOnly()) {
+    AtomicSetFlag(kEnterInterpreter);
+  }
   // Set pthread_self_ ahead of pthread_setspecific, that makes Thread::Current function, this
   // avoids pthread_self_ ever being invalid when discovered from Thread::Current().
   pthread_self_ = pthread_self();
diff --git a/src/thread.h b/src/thread.h
index 3eabe08..be7c673 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -96,10 +96,11 @@
 };
 
 enum ThreadFlag {
-  kSuspendRequest   = 1,  // If set implies that suspend_count_ > 0.
-  kExceptionPending = 2,  // If set implies that exception_ != NULL.
-  kEnterInterpreter = 4,  // Instruct managed code it should enter the interpreter.
-  kCheckpointRequest = 8, // Request that the thread do some set of work.
+  kSuspendRequest   = 1,  // If set implies that suspend_count_ > 0 and the Thread should enter the
+                          // safepoint handler.
+  kCheckpointRequest = 2, // Request that the thread do some checkpoint work and then continue.
+  kExceptionPending = 4,  // If set implies that exception_ != NULL.
+  kEnterInterpreter = 8,  // Instruct managed code it should enter the interpreter.
 };
 
 class PACKED Thread {