Implement Link-loading and pass 62 tests in JniInternalTest.

The passed tests include the 12 originally ARM-only tests. Now it works
on x86 as well if defined(ART_USE_LLVM_COMPILER).

Change-Id: I03092637fa4f0979ca77e0cac06e5d31a867e465
diff --git a/src/common_test.h b/src/common_test.h
index 7083b8c..7087c70 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -24,6 +24,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "compiler.h"
+#include "compiler_llvm/utils_llvm.h"
 #include "constants.h"
 #include "dex_file.h"
 #include "file.h"
@@ -174,8 +175,10 @@
   }
 
   static void MakeExecutable(const std::vector<uint8_t>& code) {
+#if !defined(ART_USE_LLVM_COMPILER)  // LLVM compilation uses ELF instead
     CHECK_NE(code.size(), 0U);
     MakeExecutable(&code[0], code.size());
+#endif
   }
 
   // Create an OatMethod based on pointers (for unit tests)
@@ -232,7 +235,11 @@
                                                       &compiled_method->GetVmapTable()[0],
                                                       NULL,
                                                       method_invoke_stub);
+#if !defined(ART_USE_LLVM_COMPILER)
       oat_method.LinkMethodPointers(method);
+#else
+      LLVMLinkLoadMethod("-0", method);
+#endif
     } else {
       MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
       const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index 45c4bb7..7a2857c 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -143,6 +143,8 @@
 
   target_options.FloatABIType = llvm::FloatABI::Soft;
   target_options.UseSoftFloat = false;
+  target_options.NoFramePointerElim = true;
+  target_options.NoFramePointerElimNonLeaf = true;
 
   // Create the llvm::TargetMachine
   llvm::TargetMachine* target_machine =
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 56f0b07..0985894 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -55,8 +55,8 @@
 
 
 CompilerLLVM::CompilerLLVM(Compiler* compiler, InstructionSet insn_set)
-: compiler_(compiler), compiler_lock_("llvm_compiler_lock"),
-  insn_set_(insn_set), cunit_counter_(0) {
+    : compiler_(compiler), compiler_lock_("llvm_compiler_lock"),
+      insn_set_(insn_set), cunit_counter_(0) {
 
   // Initialize LLVM libraries
   pthread_once(&llvm_initialized, InitializeLLVM);
@@ -69,6 +69,7 @@
 
 
 void CompilerLLVM::EnsureCompilationUnit() {
+  MutexLock GUARD(compiler_lock_);
   DCHECK_NE(llvm_initialized, PTHREAD_ONCE_INIT);
   if (cunit_.get() == NULL) {
     cunit_.reset(new CompilationUnit(insn_set_));
diff --git a/src/compiler_llvm/utils_llvm.cc b/src/compiler_llvm/utils_llvm.cc
index 1a8e8a2..a924793 100644
--- a/src/compiler_llvm/utils_llvm.cc
+++ b/src/compiler_llvm/utils_llvm.cc
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
+#include <android/librsloader.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+
 #include "utils_llvm.h"
 
 #include "class_loader.h"
@@ -86,4 +92,112 @@
   return long_name;
 }
 
+std::string LLVMStubName(const Method* m) {
+  MethodHelper mh(m);
+  std::string stub_name;
+  if (m->IsStatic()) {
+    stub_name += "ArtSUpcall_";
+  } else {
+    stub_name += "ArtUpcall_";
+  }
+  stub_name += mh.GetShorty();
+
+  return stub_name;
+}
+
+// TODO: Remove these when art_llvm.ll runtime support is ready.
+void art_push_shadow_frame_from_code(void* frame) {
+}
+
+void art_pop_shadow_frame_from_code() {
+}
+
+int art_is_exception_pending_from_code() {
+  return 0;
+}
+
+void art_test_suspend_from_code() {
+}
+
+void art_set_current_thread_from_code(void* thread_object_addr) {
+}
+
+// Linker's call back function. Added some for debugging.
+void* find_sym(void* context, char const* name) {
+  struct func_entry_t {
+    char const* name;
+    size_t name_len;
+    void* addr;
+  };
+
+  static struct func_entry_t const tab[] = {
+#define DEF(NAME, ADDR) \
+    { NAME, sizeof(NAME) - 1, (void *)(&(ADDR)) },
+
+    DEF("art_push_shadow_frame_from_code", art_push_shadow_frame_from_code)
+    DEF("art_pop_shadow_frame_from_code", art_pop_shadow_frame_from_code)
+    DEF("art_is_exception_pending_from_code", art_is_exception_pending_from_code)
+    DEF("art_test_suspend_from_code", art_test_suspend_from_code)
+    DEF("art_set_current_thread_from_code", art_set_current_thread_from_code)
+    DEF("printf", printf)
+    DEF("scanf", scanf)
+    DEF("__isoc99_scanf", scanf)
+    DEF("rand", rand)
+    DEF("time", time)
+    DEF("srand", srand)
+#undef DEF
+  };
+
+  static size_t const tab_size = sizeof(tab) / sizeof(struct func_entry_t);
+
+  // Note: Since our table is small, we are using trivial O(n) searching
+  // function.  For bigger table, it will be better to use binary
+  // search or hash function.
+  size_t i;
+  size_t name_len = strlen(name);
+  for (i = 0; i < tab_size; ++i) {
+    if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
+      return tab[i].addr;
+    }
+  }
+
+  CHECK(0) << "Error: Can't find symbol " << name;
+  return 0;
+}
+
+void LLVMLinkLoadMethod(const std::string& file_name, Method* method) {
+  CHECK(method != NULL);
+
+  int fd = open(file_name.c_str(), O_RDONLY);
+  CHECK(fd >= 0) << "Error: ELF not found: " << file_name;
+
+  struct stat sb;
+  CHECK(fstat(fd, &sb) == 0) << "Error: Unable to stat ELF: " << file_name;
+
+  unsigned char const *image = (unsigned char const *)
+      mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  CHECK(image != MAP_FAILED) << "Error: Unable to mmap ELF: " << file_name;
+
+  RSExecRef relocatable = rsloaderCreateExec(image, sb.st_size, find_sym, 0);
+  CHECK(relocatable) << "Error: Unable to load ELF: " << file_name;
+
+  const void *addr = rsloaderGetSymbolAddress(relocatable, LLVMLongName(method).c_str());
+  CHECK(addr) << "Error: ELF (" << file_name << ") has no symbol " << LLVMLongName(method);
+  method->SetCode(reinterpret_cast<const uint32_t*>(addr));
+
+  method->SetFrameSizeInBytes(0);
+  method->SetCoreSpillMask(0);
+  method->SetFpSpillMask(0);
+  method->SetMappingTable(reinterpret_cast<const uint32_t*>(NULL));
+  method->SetVmapTable(reinterpret_cast<const uint16_t*>(NULL));
+  method->SetGcMap(reinterpret_cast<const uint8_t*>(NULL));
+
+  addr = rsloaderGetSymbolAddress(relocatable, LLVMStubName(method).c_str());
+  CHECK(addr) << "Error: ELF (" << file_name << ") has no symbol " << LLVMStubName(method);
+  method->SetInvokeStub(reinterpret_cast<void (*)(const art::Method*, art::Object*, art::Thread*,
+                                                  art::byte*, art::JValue*)>(addr));
+
+  close(fd);
+}
+
 }  // namespace art
diff --git a/src/compiler_llvm/utils_llvm.h b/src/compiler_llvm/utils_llvm.h
index a1624d7..fb4da34 100644
--- a/src/compiler_llvm/utils_llvm.h
+++ b/src/compiler_llvm/utils_llvm.h
@@ -33,6 +33,10 @@
 // Returns the LLVM function name for the overloaded method 'm'.
 std::string LLVMLongName(const Method* m);
 
+// Returns the LLVM stub function name for the overloaded method 'm'.
+std::string LLVMStubName(const Method* m);
+
+void LLVMLinkLoadMethod(const std::string& file_name, Method* method);
 }  // namespace art
 
 #endif  // ART_SRC_UTILS_LLVM_H_
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index d4ed0cc..65283bd 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -698,6 +698,9 @@
     return EXIT_FAILURE;
   }
 
+#if defined(ART_USE_LLVM_COMPILER)
+  LOG(INFO) << "oat=" << oat_location << " elf=" << elf_filename;
+#endif
   if (!image) {
     LOG(INFO) << "Oat file written successfully: " << oat_location;
     return EXIT_SUCCESS;
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index ee801be..61bad43 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -677,6 +677,7 @@
   } while (false)
 
 
+#if !defined(ART_USE_LLVM_COMPILER)
 TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) {
   SirtRef<ClassLoader> class_loader(LoadDex("AllFields"));
   runtime_->Start();
@@ -734,6 +735,7 @@
   env_->SetObjectField(o, i_fid, s2);
   ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid)));
 }
+#endif
 
 TEST_F(JniInternalTest, NewLocalRef_NULL) {
   EXPECT_TRUE(env_->NewLocalRef(NULL) == NULL);
@@ -889,7 +891,7 @@
   env_->DeleteWeakGlobalRef(o2);
 }
 
-#if defined(__arm__)
+#if defined(__arm__) || defined(ART_USE_LLVM_COMPILER)
 TEST_F(JniInternalTest, StaticMainMethod) {
   SirtRef<ClassLoader> class_loader(LoadDex("Main"));
   CompileDirectMethod(class_loader.get(), "Main", "main", "([Ljava/lang/String;)V");
@@ -1030,6 +1032,37 @@
   EXPECT_EQ(DBL_MIN, result.d);
 }
 
+static byte* CreateArgArray(Method* method, JValue* args) {
+  const char* shorty = MethodHelper(method).GetShorty();
+  size_t shorty_len = strlen(shorty);
+  UniquePtr<byte[]> arg_array(new byte[shorty_len * 8]);
+  for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
+    switch (shorty[i]) {
+    case 'Z':
+    case 'B':
+    case 'C':
+    case 'S':
+    case 'I':
+      *reinterpret_cast<uint32_t*>(&arg_array[offset]) = args[i - 1].i;
+      break;
+    case 'F':
+      *reinterpret_cast<float*>(&arg_array[offset]) = args[i - 1].f;
+      break;
+    case 'L':
+      *reinterpret_cast<Object**>(&arg_array[offset]) = args[i - 1].l;
+      break;
+    case 'D':
+      *reinterpret_cast<double*>(&arg_array[offset]) = args[i - 1].d;
+      break;
+    case 'J':
+      *reinterpret_cast<uint64_t*>(&arg_array[offset]) = args[i - 1].j;
+      break;
+    }
+    offset += 8;
+  }
+  return arg_array.release();
+}
+
 TEST_F(JniInternalTest, StaticSumIntIntMethod) {
   SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
   CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(II)I");
@@ -1042,37 +1075,67 @@
 
   Method::InvokeStub* stub = method->GetInvokeStub();
 
-  int args[2];
   JValue result;
-
+  result.i = -1;
+#if !defined(ART_USE_LLVM_COMPILER)
+  int args[2];
   args[0] = 0;
   args[1] = 0;
-  result.i = -1;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  JValue args[2];
+  args[0].i = 0;
+  args[1].i = 0;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(0, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = 1;
   args[1] = 2;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = 1;
+  args[1].i = 2;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(3, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = -2;
   args[1] = 5;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = -2;
+  args[1].i = 5;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(3, result.i);
 
+  result.i = 1234;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MIN;
-  result.i = 1234;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MIN;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(-1, result.i);
 
+  result.i = INT_MIN;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MAX;
-  result.i = INT_MIN;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MAX;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(-2, result.i);
 }
 
@@ -1088,42 +1151,77 @@
 
   Method::InvokeStub* stub = method->GetInvokeStub();
 
-  int args[3];
   JValue result;
-
+  result.i = -1;
+#if !defined(ART_USE_LLVM_COMPILER)
+  int args[3];
   args[0] = 0;
   args[1] = 0;
   args[2] = 0;
-  result.i = -1;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  JValue args[3];
+  args[0].i = 0;
+  args[1].i = 0;
+  args[2].i = 0;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(0, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = 1;
   args[1] = 2;
   args[2] = 3;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = 1;
+  args[1].i = 2;
+  args[2].i = 3;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(6, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = -1;
   args[1] = 2;
   args[2] = -3;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = -1;
+  args[1].i = 2;
+  args[2].i = -3;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(-2, result.i);
 
+  result.i = 1234;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MIN;
   args[2] = INT_MAX;
-  result.i = 1234;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MIN;
+  args[2].i = INT_MAX;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(2147483646, result.i);
 
+  result.i = INT_MIN;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MAX;
   args[2] = INT_MAX;
-  result.i = INT_MIN;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MAX;
+  args[2].i = INT_MAX;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(2147483645, result.i);
 }
 
@@ -1139,47 +1237,87 @@
 
   Method::InvokeStub* stub = method->GetInvokeStub();
 
-  int args[4];
   JValue result;
-
+  result.i = -1;
+#if !defined(ART_USE_LLVM_COMPILER)
+  int args[4];
   args[0] = 0;
   args[1] = 0;
   args[2] = 0;
   args[3] = 0;
-  result.i = -1;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  JValue args[4];
+  args[0].i = 0;
+  args[1].i = 0;
+  args[2].i = 0;
+  args[3].i = 0;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(0, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = 1;
   args[1] = 2;
   args[2] = 3;
   args[3] = 4;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = 1;
+  args[1].i = 2;
+  args[2].i = 3;
+  args[3].i = 4;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(10, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = -1;
   args[1] = 2;
   args[2] = -3;
   args[3] = 4;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = -1;
+  args[1].i = 2;
+  args[2].i = -3;
+  args[3].i = 4;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(2, result.i);
 
+  result.i = 1234;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MIN;
   args[2] = INT_MAX;
   args[3] = INT_MIN;
-  result.i = 1234;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MIN;
+  args[2].i = INT_MAX;
+  args[3].i = INT_MIN;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(-2, result.i);
 
+  result.i = INT_MIN;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MAX;
   args[2] = INT_MAX;
   args[3] = INT_MAX;
-  result.i = INT_MIN;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MAX;
+  args[2].i = INT_MAX;
+  args[3].i = INT_MAX;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(-4, result.i);
 }
 
@@ -1195,52 +1333,97 @@
 
   Method::InvokeStub* stub = method->GetInvokeStub();
 
-  int args[5];
   JValue result;
-
+  result.i = -1.0;
+#if !defined(ART_USE_LLVM_COMPILER)
+  int args[5];
   args[0] = 0;
   args[1] = 0;
   args[2] = 0;
   args[3] = 0;
   args[4] = 0;
-  result.i = -1.0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  JValue args[5];
+  args[0].i = 0;
+  args[1].i = 0;
+  args[2].i = 0;
+  args[3].i = 0;
+  args[4].i = 0;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(0, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = 1;
   args[1] = 2;
   args[2] = 3;
   args[3] = 4;
   args[4] = 5;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = 1;
+  args[1].i = 2;
+  args[2].i = 3;
+  args[3].i = 4;
+  args[4].i = 5;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(15, result.i);
 
+  result.i = 0;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = -1;
   args[1] = 2;
   args[2] = -3;
   args[3] = 4;
   args[4] = -5;
-  result.i = 0;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = -1;
+  args[1].i = 2;
+  args[2].i = -3;
+  args[3].i = 4;
+  args[4].i = -5;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(-3, result.i);
 
+  result.i = 1234;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MIN;
   args[2] = INT_MAX;
   args[3] = INT_MIN;
   args[4] = INT_MAX;
-  result.i = 1234;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MIN;
+  args[2].i = INT_MAX;
+  args[3].i = INT_MIN;
+  args[4].i = INT_MAX;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(2147483645, result.i);
 
+  result.i = INT_MIN;
+#if !defined(ART_USE_LLVM_COMPILER)
   args[0] = INT_MAX;
   args[1] = INT_MAX;
   args[2] = INT_MAX;
   args[3] = INT_MAX;
   args[4] = INT_MAX;
-  result.i = INT_MIN;
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
+#else
+  args[0].i = INT_MAX;
+  args[1].i = INT_MAX;
+  args[2].i = INT_MAX;
+  args[3].i = INT_MAX;
+  args[4].i = INT_MAX;
+  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
+#endif
   EXPECT_EQ(2147483643, result.i);
 }
 
@@ -1409,7 +1592,7 @@
   (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(3.0, result.d);
 }
-#endif  // __arm__
+#endif  // __arm__ || ART_USE_LLVM_COMPILER
 
 TEST_F(JniInternalTest, Throw) {
   EXPECT_EQ(JNI_ERR, env_->Throw(NULL));
diff --git a/src/object.h b/src/object.h
index ca143ac..89b9df4 100644
--- a/src/object.h
+++ b/src/object.h
@@ -755,7 +755,9 @@
 
   void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) {
     DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
+#if !defined(ART_USE_LLVM_COMPILER)  // LLVM uses shadow stack instead.
     DCHECK_LE(static_cast<size_t>(kStackAlignment), new_frame_size_in_bytes);
+#endif
     SetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_),
                new_frame_size_in_bytes, false);
   }