Merge "Support new VMRuntime native methods" into lmp-preview-dev
diff --git a/Android.mk b/Android.mk
index 3324458..cc37599 100644
--- a/Android.mk
+++ b/Android.mk
@@ -431,21 +431,21 @@
 use-art:
 	adb root && sleep 3
 	adb shell stop
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libart.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
 	adb shell start
 
 .PHONY: use-artd
 use-artd:
 	adb root && sleep 3
 	adb shell stop
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libartd.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
 	adb shell start
 
 .PHONY: use-dalvik
 use-dalvik:
 	adb root && sleep 3
 	adb shell stop
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libdvm.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libdvm.so
 	adb shell start
 
 .PHONY: use-art-full
@@ -455,7 +455,7 @@
 	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags ""
 	adb shell setprop dalvik.vm.image-dex2oat-flags ""
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libart.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
 	adb shell start
 
 .PHONY: use-artd-full
@@ -465,7 +465,7 @@
 	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags ""
 	adb shell setprop dalvik.vm.image-dex2oat-flags ""
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libartd.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
 	adb shell start
 
 .PHONY: use-art-smart
@@ -475,7 +475,7 @@
 	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags "--compiler-filter=interpret-only"
 	adb shell setprop dalvik.vm.image-dex2oat-flags ""
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libart.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
 	adb shell start
 
 .PHONY: use-art-interpret-only
@@ -485,7 +485,7 @@
 	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags "--compiler-filter=interpret-only"
 	adb shell setprop dalvik.vm.image-dex2oat-flags "--compiler-filter=interpret-only"
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libart.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
 	adb shell start
 
 .PHONY: use-art-verify-none
@@ -495,7 +495,7 @@
 	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags "--compiler-filter=verify-none"
 	adb shell setprop dalvik.vm.image-dex2oat-flags "--compiler-filter=verify-none"
-	adb shell setprop persist.sys.dalvik.vm.lib.1 libart.so
+	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
 	adb shell start
 
 ########################################################################
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 2dbcc80..194cb18 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -180,13 +180,6 @@
 
     virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       mirror::ArtMethod* m = GetMethod();
-      if (GetCurrentQuickFrame() == NULL) {
-        if (kVerboseInstrumentation) {
-          LOG(INFO) << "  Ignoring a shadow frame. Frame " << GetFrameId()
-                    << " Method=" << PrettyMethod(m);
-        }
-        return true;  // Ignore shadow frames.
-      }
       if (m == NULL) {
         if (kVerboseInstrumentation) {
           LOG(INFO) << "  Skipping upcall. Frame " << GetFrameId();
@@ -204,6 +197,14 @@
       if (kVerboseInstrumentation) {
         LOG(INFO) << "  Installing exit stub in " << DescribeLocation();
       }
+      if (GetCurrentQuickFrame() == NULL) {
+        InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, 0, GetFrameId(), false);
+        if (kVerboseInstrumentation) {
+          LOG(INFO) << "Pushing shadow frame " << instrumentation_frame.Dump();
+        }
+        shadow_stack_.push_back(instrumentation_frame);
+        return true;  // Continue.
+      }
       uintptr_t return_pc = GetReturnPc();
       if (return_pc == instrumentation_exit_pc_) {
         // We've reached a frame which has already been installed with instrumentation exit stub.
@@ -238,6 +239,7 @@
       return true;  // Continue.
     }
     std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
+    std::vector<InstrumentationStackFrame> shadow_stack_;
     const size_t existing_instrumentation_frames_count_;
     std::vector<uint32_t> dex_pcs_;
     const uintptr_t instrumentation_exit_pc_;
@@ -261,14 +263,16 @@
   if (instrumentation->ShouldNotifyMethodEnterExitEvents()) {
     // Create method enter events for all methods currently on the thread's stack. We only do this
     // if no debugger is attached to prevent from posting events twice.
-    typedef std::deque<InstrumentationStackFrame>::const_reverse_iterator It;
-    for (It it = thread->GetInstrumentationStack()->rbegin(),
-        end = thread->GetInstrumentationStack()->rend(); it != end; ++it) {
-      mirror::Object* this_object = (*it).this_object_;
-      mirror::ArtMethod* method = (*it).method_;
+    auto ssi = visitor.shadow_stack_.rbegin();
+    for (auto isi = thread->GetInstrumentationStack()->rbegin(),
+        end = thread->GetInstrumentationStack()->rend(); isi != end; ++isi) {
+      while (ssi != visitor.shadow_stack_.rend() && (*ssi).frame_id_ < (*isi).frame_id_) {
+        instrumentation->MethodEnterEvent(thread, (*ssi).this_object_, (*ssi).method_, 0);
+        ++ssi;
+      }
       uint32_t dex_pc = visitor.dex_pcs_.back();
       visitor.dex_pcs_.pop_back();
-      instrumentation->MethodEnterEvent(thread, this_object, method, dex_pc);
+      instrumentation->MethodEnterEvent(thread, (*isi).this_object_, (*isi).method_, dex_pc);
     }
   }
   thread->VerifyStack();
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 8f74dd7..a0a294a 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -206,8 +206,8 @@
     if (result != nullptr) {
       for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-        const char* descriptor = dex_file->GetClassDescriptor(class_def);
-        ScopedLocalRef<jstring> jdescriptor(env, env->NewStringUTF(descriptor));
+        std::string descriptor(DescriptorToDot(dex_file->GetClassDescriptor(class_def)));
+        ScopedLocalRef<jstring> jdescriptor(env, env->NewStringUTF(descriptor.c_str()));
         if (jdescriptor.get() == nullptr) {
           return nullptr;
         }
diff --git a/test/071-dexfile/expected.txt b/test/071-dexfile/expected.txt
index b7af75e..d14c986 100644
--- a/test/071-dexfile/expected.txt
+++ b/test/071-dexfile/expected.txt
@@ -1,3 +1,4 @@
 Constructing another
 Got expected ULE
+Another
 done
diff --git a/test/071-dexfile/src/Main.java b/test/071-dexfile/src/Main.java
index 117a391..2f85790 100644
--- a/test/071-dexfile/src/Main.java
+++ b/test/071-dexfile/src/Main.java
@@ -17,6 +17,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
 
 /**
  * DexFile tests (Dalvik-specific).
@@ -24,47 +26,37 @@
 public class Main {
     private static final String CLASS_PATH = System.getenv("DEX_LOCATION") + "/071-dexfile-ex.jar";
     private static final String ODEX_DIR = System.getenv("DEX_LOCATION");
-    //private static final String ODEX_DIR = ".";
     private static final String ODEX_ALT = "/tmp";
     private static final String LIB_DIR = "/nowhere/nothing/";
 
+    private static final String getOdexDir() {
+        return new File(ODEX_DIR).isDirectory() ? ODEX_DIR : ODEX_ALT;
+    }
+
     /**
      * Prep the environment then run the test.
      */
-    public static void main(String[] args) {
-        Process p;
-        try {
-            /*
-             * Create a sub-process to see if the ProcessManager wait
-             * interferes with the dexopt invocation wait.
-             *
-             * /dev/random never hits EOF, so we're sure that we'll still
-             * be waiting for the process to complete.  On the device it
-             * stops pretty quickly (which means the child won't be
-             * spinning).
-             */
-            ProcessBuilder pb = new ProcessBuilder("cat", "/dev/random");
-            p = pb.start();
-        } catch (IOException ioe) {
-            System.err.println("cmd failed: " + ioe.getMessage());
-            p = null;
-        }
+    public static void main(String[] args) throws Exception {
+        /*
+         * Create a sub-process to see if the ProcessManager wait
+         * interferes with the dexopt invocation wait.
+         *
+         * /dev/random never hits EOF, so we're sure that we'll still
+         * be waiting for the process to complete.  On the device it
+         * stops pretty quickly (which means the child won't be
+         * spinning).
+         */
+        ProcessBuilder pb = new ProcessBuilder("cat", "/dev/random");
+        Process p = pb.start();
 
-        try {
-            testDexClassLoader();
-        } finally {
-            // shouldn't be necessary, but it's good to be tidy
-            if (p != null) {
-                p.destroy();
-            }
+        testDexClassLoader();
+        testDexFile();
 
-            // let the ProcessManager's daemon thread finish before we shut down
-            // (avoids the occasional segmentation fault)
-            try {
-                Thread.sleep(500);
-            } catch (Exception ex) {}
-        }
-
+        // shouldn't be necessary, but it's good to be tidy
+        p.destroy();
+        // let the ProcessManager's daemon thread finish before we shut down
+        // (avoids the occasional segmentation fault)
+        Thread.sleep(500);
         System.out.println("done");
     }
 
@@ -72,25 +64,10 @@
      * Create a class loader, explicitly specifying the source DEX and
      * the location for the optimized DEX.
      */
-    private static void testDexClassLoader() {
+    private static void testDexClassLoader() throws Exception {
         ClassLoader dexClassLoader = getDexClassLoader();
-
-        Class anotherClass;
-        try {
-            anotherClass = dexClassLoader.loadClass("Another");
-        } catch (ClassNotFoundException cnfe) {
-            throw new RuntimeException("Another?", cnfe);
-        }
-
-        Object another;
-        try {
-            another = anotherClass.newInstance();
-        } catch (IllegalAccessException ie) {
-            throw new RuntimeException("new another", ie);
-        } catch (InstantiationException ie) {
-            throw new RuntimeException("new another", ie);
-        }
-
+        Class Another = dexClassLoader.loadClass("Another");
+        Object another = Another.newInstance();
         // not expected to work; just exercises the call
         dexClassLoader.getResource("nonexistent");
     }
@@ -100,51 +77,30 @@
      * have visibility into dalvik.system.*, so we do this through
      * reflection.
      */
-    private static ClassLoader getDexClassLoader() {
-        String odexDir;
-
-        if (false) {
-            String androidData = System.getenv("ANDROID_DATA");
-            if (androidData == null) {
-                androidData = "";
-            }
-            odexDir = androidData + "/" + ODEX_DIR;
-        }
-
-        File test = new File(ODEX_DIR);
-        if (test.isDirectory()) {
-            odexDir = ODEX_DIR;
-        } else {
-            odexDir = ODEX_ALT;
-        }
-        if (false) {
-            System.out.println("Output dir is " + odexDir);
-        }
-
-        ClassLoader myLoader = Main.class.getClassLoader();
-        Class dclClass;
-        try {
-            dclClass = myLoader.loadClass("dalvik.system.DexClassLoader");
-        } catch (ClassNotFoundException cnfe) {
-            throw new RuntimeException("dalvik.system.DexClassLoader not found", cnfe);
-        }
-
-        Constructor ctor;
-        try {
-            ctor = dclClass.getConstructor(String.class, String.class,
-                String.class, ClassLoader.class);
-        } catch (NoSuchMethodException nsme) {
-            throw new RuntimeException("DCL ctor", nsme);
-        }
-
+    private static ClassLoader getDexClassLoader() throws Exception {
+        ClassLoader classLoader = Main.class.getClassLoader();
+        Class DexClassLoader = classLoader.loadClass("dalvik.system.DexClassLoader");
+        Constructor DexClassLoader_init = DexClassLoader.getConstructor(String.class,
+                                                                        String.class,
+                                                                        String.class,
+                                                                        ClassLoader.class);
         // create an instance, using the path we found
-        Object dclObj;
-        try {
-            dclObj = ctor.newInstance(CLASS_PATH, odexDir, LIB_DIR, myLoader);
-        } catch (Exception ex) {
-            throw new RuntimeException("DCL newInstance", ex);
-        }
+        return (ClassLoader) DexClassLoader_init.newInstance(CLASS_PATH, getOdexDir(), LIB_DIR, classLoader);
+    }
 
-        return (ClassLoader) dclObj;
+    private static void testDexFile() throws Exception {
+        ClassLoader classLoader = Main.class.getClassLoader();
+        Class DexFile = classLoader.loadClass("dalvik.system.DexFile");
+        Method DexFile_loadDex = DexFile.getMethod("loadDex",
+                                                   String.class,
+                                                   String.class,
+                                                   Integer.TYPE);
+        Method DexFile_entries = DexFile.getMethod("entries");
+        Object dexFile = DexFile_loadDex.invoke(null, CLASS_PATH, null, 0);
+        Enumeration<String> e = (Enumeration<String>) DexFile_entries.invoke(dexFile);
+        while (e.hasMoreElements()) {
+            String className = e.nextElement();
+            System.out.println(className);
+        }
     }
 }
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index d95559f..5d6d16a 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -89,11 +89,6 @@
 
 msg "------------------------------"
 
-mkdir $DEX_LOCATION/dalvik-cache
-if [ $? -ne 0 ]; then
-    exit
-fi
-
 export ANDROID_PRINTF_LOG=brief
 if [ "$DEV_MODE" = "y" ]; then
     export ANDROID_LOG_TAGS='*:d'