Implement upcalls with compiled JNI callback bridges.
Change-Id: Ib475a5957a3e2596a812df1314fbc73a96f01725
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index a7f6917..457bae8 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -1,8 +1,11 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-#include "common_test.h"
+#include "jni_internal.h"
-#include <stdio.h>
+#include <cmath>
+#include <sys/mman.h>
+
+#include "common_test.h"
#include "gtest/gtest.h"
namespace art {
@@ -54,4 +57,754 @@
EXPECT_CLASS_NOT_FOUND("K");
}
-} // namespace art
+bool EnsureInvokeStub(Method* method);
+
+byte* AllocateCode(void* code, size_t length) {
+ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+ void* addr = mmap(NULL, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ CHECK(addr != MAP_FAILED);
+ memcpy(addr, code, length);
+ __builtin___clear_cache(addr, (byte*)addr + length);
+ // Set the low-order bit so a BLX will switch to Thumb mode.
+ return reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(addr) | 1);
+}
+
+Method::InvokeStub* AllocateStub(Method* method,
+ byte* code,
+ size_t length) {
+ CHECK(method->GetInvokeStub() == NULL);
+ EnsureInvokeStub(method);
+ Method::InvokeStub* stub = method->GetInvokeStub();
+ CHECK(stub != NULL);
+ method->SetCode(AllocateCode(code, length));
+ CHECK(method->GetCode() != NULL);
+ return stub;
+}
+
+void FreeStub(Method* method, size_t length) {
+ void* addr = const_cast<void*>(method->GetCode());
+ munmap(addr, length);
+ method->SetCode(NULL);
+}
+
+#if defined(__arm__)
+TEST_F(JniInternalTest, StaticMainMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kMainDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LMain;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("main", "([Ljava/lang/String;)V");
+ ASSERT_TRUE(method != NULL);
+
+ byte main_LV_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8, 0x00, 0x00,
+ 0xcd, 0xf8, 0x14, 0x10, 0x03, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ main_LV_code,
+ sizeof(main_LV_code));
+
+ Object* arg = NULL;
+
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), NULL);
+
+ FreeStub(method, sizeof(main_LV_code));
+}
+
+TEST_F(JniInternalTest, StaticNopMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("nop", "()V");
+ ASSERT_TRUE(method != NULL);
+
+ byte nop_V_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0x03, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ nop_V_code,
+ sizeof(nop_V_code));
+ ASSERT_TRUE(stub);
+
+ (*stub)(method, NULL, NULL, NULL, NULL);
+
+ FreeStub(method, sizeof(nop_V_code));
+}
+
+TEST_F(JniInternalTest, StaticIdentityByteMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("identity", "(B)B");
+ ASSERT_TRUE(method != NULL);
+
+ byte identity_BB_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0x05, 0x98,
+ 0x03, 0xb0, 0xbd, 0xe8, 0x00, 0x80, 0x00, 0x00,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ identity_BB_code,
+ sizeof(identity_BB_code));
+
+ int arg;
+ JValue result;
+
+ arg = 0;
+ result.b = -1;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(0, result.b);
+
+ arg = -1;
+ result.b = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(-1, result.b);
+
+ arg = SCHAR_MAX;
+ result.b = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(SCHAR_MAX, result.b);
+
+ arg = SCHAR_MIN;
+ result.b = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(SCHAR_MIN, result.b);
+
+ FreeStub(method, sizeof(identity_BB_code));
+}
+
+TEST_F(JniInternalTest, StaticIdentityIntMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("identity", "(I)I");
+ ASSERT_TRUE(method != NULL);
+
+ byte identity_II_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0x05, 0x98,
+ 0x03, 0xb0, 0xbd, 0xe8, 0x00, 0x80, 0x00, 0x00,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ identity_II_code,
+ sizeof(identity_II_code));
+
+ int arg;
+ JValue result;
+
+ arg = 0;
+ result.i = -1;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(0, result.i);
+
+ arg = -1;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(-1, result.i);
+
+ arg = INT_MAX;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(INT_MAX, result.i);
+
+ arg = INT_MIN;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(INT_MIN, result.i);
+
+ FreeStub(method, sizeof(identity_II_code));
+}
+
+TEST_F(JniInternalTest, StaticIdentityDoubleMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("identity", "(D)D");
+ ASSERT_TRUE(method != NULL);
+
+ byte identity_DD_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0xcd, 0xf8,
+ 0x18, 0x20, 0x05, 0x98, 0x06, 0x99, 0x03, 0xb0,
+ 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ identity_DD_code,
+ sizeof(identity_DD_code));
+
+ double arg;
+ JValue result;
+
+ arg = 0.0;
+ result.d = -1.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(0.0, result.d);
+
+ arg = -1.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(-1.0, result.d);
+
+ arg = DBL_MAX;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(DBL_MAX, result.d);
+
+ arg = DBL_MIN;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ EXPECT_EQ(DBL_MIN, result.d);
+
+ FreeStub(method, sizeof(identity_DD_code));
+}
+
+TEST_F(JniInternalTest, StaticSumIntIntMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(II)I");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_III_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0xcd, 0xf8,
+ 0x18, 0x20, 0x05, 0x98, 0x06, 0x99, 0x42, 0x18,
+ 0xcd, 0xf8, 0x04, 0x20, 0x01, 0x98, 0x03, 0xb0,
+ 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_III_code,
+ sizeof(sum_III_code));
+
+ int args[2];
+ JValue result;
+
+ args[0] = 0;
+ args[1] = 0;
+ result.i = -1;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0, result.i);
+
+ args[0] = 1;
+ args[1] = 2;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(3, result.i);
+
+ args[0] = -2;
+ args[1] = 5;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(3, result.i);
+
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
+ result.i = 1234;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-1, result.i);
+
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
+ result.i = INT_MIN;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-2, result.i);
+
+ FreeStub(method, sizeof(sum_III_code));
+}
+
+TEST_F(JniInternalTest, StaticSumIntIntIntMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(III)I");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_IIII_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0xcd, 0xf8,
+ 0x18, 0x20, 0xcd, 0xf8, 0x1c, 0x30, 0x05, 0x98,
+ 0x06, 0x99, 0x42, 0x18, 0xcd, 0xf8, 0x04, 0x20,
+ 0x01, 0x9b, 0xdd, 0xf8, 0x1c, 0xc0, 0x13, 0xeb,
+ 0x0c, 0x03, 0xcd, 0xf8, 0x04, 0x30, 0x01, 0x98,
+ 0x03, 0xb0, 0xbd, 0xe8, 0x00, 0x80, 0x00, 0x00,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_IIII_code,
+ sizeof(sum_IIII_code));
+
+ int args[3];
+ JValue result;
+
+ args[0] = 0;
+ args[1] = 0;
+ args[2] = 0;
+ result.i = -1;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0, result.i);
+
+ args[0] = 1;
+ args[1] = 2;
+ args[2] = 3;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(6, result.i);
+
+ args[0] = -1;
+ args[1] = 2;
+ args[2] = -3;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-2, result.i);
+
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
+ args[2] = INT_MAX;
+ result.i = 1234;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(2147483646, result.i);
+
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
+ args[2] = INT_MAX;
+ result.i = INT_MIN;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(2147483645, result.i);
+
+ FreeStub(method, sizeof(sum_IIII_code));
+}
+
+TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(IIII)I");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_IIIII_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0xcd, 0xf8,
+ 0x18, 0x20, 0xcd, 0xf8, 0x1c, 0x30, 0x05, 0x98,
+ 0x06, 0x99, 0x42, 0x18, 0xcd, 0xf8, 0x04, 0x20,
+ 0x01, 0x9b, 0xdd, 0xf8, 0x1c, 0xc0, 0x13, 0xeb,
+ 0x0c, 0x03, 0xcd, 0xf8, 0x04, 0x30, 0x01, 0x98,
+ 0x08, 0x99, 0x40, 0x18, 0xcd, 0xf8, 0x04, 0x00,
+ 0x01, 0x98, 0x03, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_IIIII_code,
+ sizeof(sum_IIIII_code));
+
+ int args[4];
+ JValue result;
+
+ args[0] = 0;
+ args[1] = 0;
+ args[2] = 0;
+ args[3] = 0;
+ result.i = -1;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0, result.i);
+
+ args[0] = 1;
+ args[1] = 2;
+ args[2] = 3;
+ args[3] = 4;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(10, result.i);
+
+ args[0] = -1;
+ args[1] = 2;
+ args[2] = -3;
+ args[3] = 4;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(2, result.i);
+
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
+ args[2] = INT_MAX;
+ args[3] = INT_MIN;
+ result.i = 1234;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-2, result.i);
+
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
+ args[2] = INT_MAX;
+ args[3] = INT_MAX;
+ result.i = INT_MIN;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-4, result.i);
+
+ FreeStub(method, sizeof(sum_IIIII_code));
+}
+
+TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(IIIII)I");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_IIIIII_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x83, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x14, 0x10, 0xcd, 0xf8,
+ 0x18, 0x20, 0xcd, 0xf8, 0x1c, 0x30, 0x05, 0x98,
+ 0x06, 0x99, 0x42, 0x18, 0xcd, 0xf8, 0x04, 0x20,
+ 0x01, 0x9b, 0xdd, 0xf8, 0x1c, 0xc0, 0x13, 0xeb,
+ 0x0c, 0x03, 0xcd, 0xf8, 0x04, 0x30, 0x01, 0x98,
+ 0x08, 0x99, 0x40, 0x18, 0xcd, 0xf8, 0x04, 0x00,
+ 0x01, 0x9a, 0x09, 0x9b, 0xd2, 0x18, 0xcd, 0xf8,
+ 0x04, 0x20, 0x01, 0x98, 0x03, 0xb0, 0xbd, 0xe8,
+ 0x00, 0x80, 0x00, 0x00,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_IIIIII_code,
+ sizeof(sum_IIIIII_code));
+
+ int args[5];
+ JValue result;
+
+ args[0] = 0;
+ args[1] = 0;
+ args[2] = 0;
+ args[3] = 0;
+ args[4] = 0;
+ result.i = -1.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0, result.i);
+
+ args[0] = 1;
+ args[1] = 2;
+ args[2] = 3;
+ args[3] = 4;
+ args[4] = 5;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(15, result.i);
+
+ args[0] = -1;
+ args[1] = 2;
+ args[2] = -3;
+ args[3] = 4;
+ args[4] = -5;
+ result.i = 0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-3, result.i);
+
+ 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, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(2147483645, result.i);
+
+ 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, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(2147483643, result.i);
+
+ FreeStub(method, sizeof(sum_IIIIII_code));
+}
+
+TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(DD)D");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_DDD_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x87, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x24, 0x10, 0xcd, 0xf8,
+ 0x28, 0x20, 0xcd, 0xf8, 0x2c, 0x30, 0x9d, 0xed,
+ 0x09, 0x0b, 0x9d, 0xed, 0x0b, 0x1b, 0x30, 0xee,
+ 0x01, 0x2b, 0x8d, 0xed, 0x04, 0x2b, 0x04, 0x98,
+ 0x05, 0x99, 0x07, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_DDD_code,
+ sizeof(sum_DDD_code));
+
+ double args[2];
+ JValue result;
+
+ args[0] = 0.0;
+ args[1] = 0.0;
+ result.d = -1.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = 2.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(3.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = -2.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-1.0, result.d);
+
+ args[0] = DBL_MAX;
+ args[1] = DBL_MIN;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(1.7976931348623157e308, result.d);
+
+ args[0] = DBL_MAX;
+ args[1] = DBL_MAX;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(INFINITY, result.d);
+
+ FreeStub(method, sizeof(sum_DDD_code));
+}
+
+TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(DDD)D");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_DDDD_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x87, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x24, 0x10, 0xcd, 0xf8,
+ 0x28, 0x20, 0xcd, 0xf8, 0x2c, 0x30, 0x9d, 0xed,
+ 0x09, 0x0b, 0x9d, 0xed, 0x0b, 0x1b, 0x30, 0xee,
+ 0x01, 0x2b, 0x8d, 0xed, 0x04, 0x2b, 0x9d, 0xed,
+ 0x04, 0x3b, 0x9d, 0xed, 0x0d, 0x4b, 0x33, 0xee,
+ 0x04, 0x3b, 0x8d, 0xed, 0x04, 0x3b, 0x04, 0x98,
+ 0x05, 0x99, 0x07, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_DDDD_code,
+ sizeof(sum_DDDD_code));
+
+ double args[3];
+ JValue result;
+
+ args[0] = 0.0;
+ args[1] = 0.0;
+ args[2] = 0.0;
+ result.d = -1.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = 2.0;
+ args[2] = 3.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(6.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = -2.0;
+ args[2] = 3.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(2.0, result.d);
+
+ FreeStub(method, sizeof(sum_DDDD_code));
+}
+
+TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(DDDD)D");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_DDDDD_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x87, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x24, 0x10, 0xcd, 0xf8,
+ 0x28, 0x20, 0xcd, 0xf8, 0x2c, 0x30, 0x9d, 0xed,
+ 0x09, 0x0b, 0x9d, 0xed, 0x0b, 0x1b, 0x30, 0xee,
+ 0x01, 0x2b, 0x8d, 0xed, 0x04, 0x2b, 0x9d, 0xed,
+ 0x04, 0x3b, 0x9d, 0xed, 0x0d, 0x4b, 0x33, 0xee,
+ 0x04, 0x3b, 0x8d, 0xed, 0x04, 0x3b, 0x9d, 0xed,
+ 0x04, 0x5b, 0x9d, 0xed, 0x0f, 0x6b, 0x35, 0xee,
+ 0x06, 0x5b, 0x8d, 0xed, 0x04, 0x5b, 0x04, 0x98,
+ 0x05, 0x99, 0x07, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_DDDDD_code,
+ sizeof(sum_DDDDD_code));
+
+ double args[4];
+ JValue result;
+
+ args[0] = 0.0;
+ args[1] = 0.0;
+ args[2] = 0.0;
+ args[3] = 0.0;
+ result.d = -1.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = 2.0;
+ args[2] = 3.0;
+ args[3] = 4.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(10.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = -2.0;
+ args[2] = 3.0;
+ args[3] = -4.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(-2.0, result.d);
+
+ FreeStub(method, sizeof(sum_DDDDD_code));
+}
+
+TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ ASSERT_TRUE(class_loader != NULL);
+
+ Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method = klass->FindDirectMethod("sum", "(DDDDD)D");
+ ASSERT_TRUE(method != NULL);
+
+ byte sum_DDDDDD_code[] = {
+ 0x2d, 0xe9, 0x00, 0x40, 0x87, 0xb0, 0xcd, 0xf8,
+ 0x00, 0x00, 0xcd, 0xf8, 0x24, 0x10, 0xcd, 0xf8,
+ 0x28, 0x20, 0xcd, 0xf8, 0x2c, 0x30, 0x9d, 0xed,
+ 0x09, 0x0b, 0x9d, 0xed, 0x0b, 0x1b, 0x30, 0xee,
+ 0x01, 0x2b, 0x8d, 0xed, 0x04, 0x2b, 0x9d, 0xed,
+ 0x04, 0x3b, 0x9d, 0xed, 0x0d, 0x4b, 0x33, 0xee,
+ 0x04, 0x3b, 0x8d, 0xed, 0x04, 0x3b, 0x9d, 0xed,
+ 0x04, 0x5b, 0x9d, 0xed, 0x0f, 0x6b, 0x35, 0xee,
+ 0x06, 0x5b, 0x8d, 0xed, 0x04, 0x5b, 0x9d, 0xed,
+ 0x04, 0x7b, 0x9d, 0xed, 0x11, 0x0b, 0x37, 0xee,
+ 0x00, 0x7b, 0x8d, 0xed, 0x04, 0x7b, 0x04, 0x98,
+ 0x05, 0x99, 0x07, 0xb0, 0xbd, 0xe8, 0x00, 0x80,
+ };
+
+ Method::InvokeStub* stub = AllocateStub(method,
+ sum_DDDDDD_code,
+ sizeof(sum_DDDDDD_code));
+
+ double args[5];
+ JValue result;
+
+ args[0] = 0.0;
+ args[1] = 0.0;
+ args[2] = 0.0;
+ args[3] = 0.0;
+ args[4] = 0.0;
+ result.d = -1.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(0.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = 2.0;
+ args[2] = 3.0;
+ args[3] = 4.0;
+ args[4] = 5.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(15.0, result.d);
+
+ args[0] = 1.0;
+ args[1] = -2.0;
+ args[2] = 3.0;
+ args[3] = -4.0;
+ args[4] = 5.0;
+ result.d = 0.0;
+ (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ EXPECT_EQ(3.0, result.d);
+
+ FreeStub(method, sizeof(sum_DDDDDD_code));
+}
+#endif // __arm__
+
+}