Revert "Revert "Optimizing: Better invoke-static/-direct dispatch.""

Fixed kCallArtMethod to use correct callee location for
kRecursive. This combination is used when compiling with
debuggable flag set.

This reverts commit b2c431e80e92eb6437788cc544cee6c88c3156df.

Change-Id: Idee0f2a794199ebdf24892c60f8a5dcf057db01c
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index f09e958..2374c9c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -27,6 +27,7 @@
 #include "handle_scope.h"
 #include "invoke_type.h"
 #include "locations.h"
+#include "method_reference.h"
 #include "mirror/class.h"
 #include "offsets.h"
 #include "primitive.h"
@@ -2977,13 +2978,81 @@
     kImplicit,  // Static call implicitly requiring a clinit check.
   };
 
+  // Determines how to load the target ArtMethod*.
+  enum class MethodLoadKind {
+    // Use a String init ArtMethod* loaded from Thread entrypoints.
+    kStringInit,
+
+    // Use the method's own ArtMethod* loaded by the register allocator.
+    kRecursive,
+
+    // Use ArtMethod* at a known address, embed the direct address in the code.
+    // Used for app->boot calls with non-relocatable image and for JIT-compiled calls.
+    kDirectAddress,
+
+    // Use ArtMethod* at an address that will be known at link time, embed the direct
+    // address in the code. If the image is relocatable, emit .patch_oat entry.
+    // Used for app->boot calls with relocatable image and boot->boot calls, whether
+    // the image relocatable or not.
+    kDirectAddressWithFixup,
+
+    // Load from resoved methods array in the dex cache using a PC-relative load.
+    // Used when we need to use the dex cache, for example for invoke-static that
+    // may cause class initialization (the entry may point to a resolution method),
+    // and we know that we can access the dex cache arrays using a PC-relative load.
+    kDexCachePcRelative,
+
+    // Use ArtMethod* from the resolved methods of the compiled method's own ArtMethod*.
+    // Used for JIT when we need to use the dex cache. This is also the last-resort-kind
+    // used when other kinds are unavailable (say, dex cache arrays are not PC-relative)
+    // or unimplemented or impractical (i.e. slow) on a particular architecture.
+    kDexCacheViaMethod,
+  };
+
+  // Determines the location of the code pointer.
+  enum class CodePtrLocation {
+    // Recursive call, use local PC-relative call instruction.
+    kCallSelf,
+
+    // Use PC-relative call instruction patched at link time.
+    // Used for calls within an oat file, boot->boot or app->app.
+    kCallPCRelative,
+
+    // Call to a known target address, embed the direct address in code.
+    // Used for app->boot call with non-relocatable image and for JIT-compiled calls.
+    kCallDirect,
+
+    // Call to a target address that will be known at link time, embed the direct
+    // address in code. If the image is relocatable, emit .patch_oat entry.
+    // Used for app->boot calls with relocatable image and boot->boot calls, whether
+    // the image relocatable or not.
+    kCallDirectWithFixup,
+
+    // Use code pointer from the ArtMethod*.
+    // Used when we don't know the target code. This is also the last-resort-kind used when
+    // other kinds are unimplemented or impractical (i.e. slow) on a particular architecture.
+    kCallArtMethod,
+  };
+
+  struct DispatchInfo {
+    const MethodLoadKind method_load_kind;
+    const CodePtrLocation code_ptr_location;
+    // The method load data holds
+    //   - thread entrypoint offset for kStringInit method if this is a string init invoke.
+    //     Note that there are multiple string init methods, each having its own offset.
+    //   - the method address for kDirectAddress
+    //   - the dex cache arrays offset for kDexCachePcRel.
+    const uint64_t method_load_data;
+    const uint64_t direct_code_ptr;
+  };
+
   HInvokeStaticOrDirect(ArenaAllocator* arena,
                         uint32_t number_of_arguments,
                         Primitive::Type return_type,
                         uint32_t dex_pc,
-                        uint32_t dex_method_index,
-                        bool is_recursive,
-                        int32_t string_init_offset,
+                        uint32_t method_index,
+                        MethodReference target_method,
+                        DispatchInfo dispatch_info,
                         InvokeType original_invoke_type,
                         InvokeType invoke_type,
                         ClinitCheckRequirement clinit_check_requirement)
@@ -2993,15 +3062,15 @@
                 // potentially one other if the clinit check is explicit, and one other
                 // if the method is a string factory.
                 1u + (clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 1u : 0u)
-                   + (string_init_offset ? 1u : 0u),
+                   + (dispatch_info.method_load_kind == MethodLoadKind::kStringInit ? 1u : 0u),
                 return_type,
                 dex_pc,
-                dex_method_index,
+                method_index,
                 original_invoke_type),
         invoke_type_(invoke_type),
-        is_recursive_(is_recursive),
         clinit_check_requirement_(clinit_check_requirement),
-        string_init_offset_(string_init_offset) {}
+        target_method_(target_method),
+        dispatch_info_(dispatch_info) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
     UNUSED(obj);
@@ -3015,11 +3084,36 @@
   }
 
   InvokeType GetInvokeType() const { return invoke_type_; }
-  bool IsRecursive() const { return is_recursive_; }
-  bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); }
-  bool IsStringInit() const { return string_init_offset_ != 0; }
-  int32_t GetStringInitOffset() const { return string_init_offset_; }
+  MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; }
+  CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; }
+  bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; }
+  bool NeedsDexCache() const OVERRIDE { return !IsRecursive() && !IsStringInit(); }
+  bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; }
   uint32_t GetCurrentMethodInputIndex() const { return GetNumberOfArguments(); }
+  bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; }
+  bool HasPcRelDexCache() const { return GetMethodLoadKind() == MethodLoadKind::kDexCachePcRelative; }
+  bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; }
+  MethodReference GetTargetMethod() const { return target_method_; }
+
+  int32_t GetStringInitOffset() const {
+    DCHECK(IsStringInit());
+    return dispatch_info_.method_load_data;
+  }
+
+  uint64_t GetMethodAddress() const {
+    DCHECK(HasMethodAddress());
+    return dispatch_info_.method_load_data;
+  }
+
+  uint32_t GetDexCacheArrayOffset() const {
+    DCHECK(HasPcRelDexCache());
+    return dispatch_info_.method_load_data;
+  }
+
+  uint64_t GetDirectCodePtr() const {
+    DCHECK(HasDirectCodePtr());
+    return dispatch_info_.direct_code_ptr;
+  }
 
   // Is this instruction a call to a static method?
   bool IsStatic() const {
@@ -3090,11 +3184,12 @@
 
  private:
   const InvokeType invoke_type_;
-  const bool is_recursive_;
   ClinitCheckRequirement clinit_check_requirement_;
-  // Thread entrypoint offset for string init method if this is a string init invoke.
-  // Note that there are multiple string init methods, each having its own offset.
-  int32_t string_init_offset_;
+  // The target method may refer to different dex file or method index than the original
+  // invoke. This happens for sharpened calls and for calls where a method was redeclared
+  // in derived class to increase visibility.
+  MethodReference target_method_;
+  DispatchInfo dispatch_info_;
 
   DISALLOW_COPY_AND_ASSIGN(HInvokeStaticOrDirect);
 };
@@ -4998,6 +5093,16 @@
                                    : constant->AsLongConstant()->GetValue();
 }
 
+inline bool IsSameDexFile(const DexFile& lhs, const DexFile& rhs) {
+  // For the purposes of the compiler, the dex files must actually be the same object
+  // if we want to safely treat them as the same. This is especially important for JIT
+  // as custom class loaders can open the same underlying file (or memory) multiple
+  // times and provide different class resolution but no two class loaders should ever
+  // use the same DexFile object - doing so is an unsupported hack that can lead to
+  // all sorts of weird failures.
+  return &lhs == &rhs;
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_NODES_H_