#include <memory>
+#include <math.h>
+
#include "class_linker.h"
#include "common_compiler_test.h"
#include "dex_file.h"
class JniCompilerTest : public CommonCompilerTest {
protected:
void CompileForTest(jobject class_loader, bool direct,
- const char* method_name, const char* method_sig) {
+ const char* method_name, const char* method_sig, bool generic = false) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> loader(
method = c->FindVirtualMethod(method_name, method_sig);
}
ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig;
- if (method->GetEntryPointFromQuickCompiledCode() == nullptr ||
- method->GetEntryPointFromQuickCompiledCode() == class_linker_->GetQuickGenericJniTrampoline()) {
- CompileMethod(method);
- ASSERT_TRUE(method->GetEntryPointFromQuickCompiledCode() != nullptr)
- << method_name << " " << method_sig;
- ASSERT_TRUE(method->GetEntryPointFromPortableCompiledCode() != nullptr)
- << method_name << " " << method_sig;
+ if (generic) {
+ method->SetEntryPointFromQuickCompiledCode(class_linker_->GetQuickGenericJniTrampoline());
+ } else {
+ if (method->GetEntryPointFromQuickCompiledCode() == nullptr ||
+ method->GetEntryPointFromQuickCompiledCode() == class_linker_->GetQuickGenericJniTrampoline()) {
+ CompileMethod(method);
+ ASSERT_TRUE(method->GetEntryPointFromQuickCompiledCode() != nullptr)
+ << method_name << " " << method_sig;
+ ASSERT_TRUE(method->GetEntryPointFromPortableCompiledCode() != nullptr)
+ << method_name << " " << method_sig;
+ }
}
}
void SetUpForTest(bool direct, const char* method_name, const char* method_sig,
- void* native_fnptr) {
+ void* native_fnptr, bool generic = false) {
// Initialize class loader and compile method when runtime not started.
if (!runtime_->IsStarted()) {
{
ScopedObjectAccess soa(Thread::Current());
class_loader_ = LoadDex("MyClassNatives");
}
- CompileForTest(class_loader_, direct, method_name, method_sig);
+ CompileForTest(class_loader_, direct, method_name, method_sig, generic);
// Start runtime.
Thread::Current()->TransitionFromSuspendedToRunnable();
bool started = runtime_->Start();
EXPECT_EQ(2, gJava_MyClassNatives_fooSDD_calls);
}
+// The x86 generic JNI code had a bug where it assumed a floating
+// point return value would be in xmm0. We use log, to somehow ensure
+// the compiler will use the floating point stack.
+
+jdouble Java_MyClassNatives_logD(JNIEnv* env, jclass klass, jdouble x) {
+ return log(x);
+}
+
+TEST_F(JniCompilerTest, RunGenericStaticLogDoubleethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ TEST_DISABLED_FOR_MIPS();
+ SetUpForTest(true, "logD", "(D)D",
+ reinterpret_cast<void*>(&Java_MyClassNatives_logD), true);
+
+ jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 2.0);
+ EXPECT_EQ(log(2.0), result);
+}
+
+jfloat Java_MyClassNatives_logF(JNIEnv* env, jclass klass, jfloat x) {
+ return logf(x);
+}
+
+TEST_F(JniCompilerTest, RunGenericStaticLogFloatMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ TEST_DISABLED_FOR_MIPS();
+ SetUpForTest(true, "logF", "(F)F",
+ reinterpret_cast<void*>(&Java_MyClassNatives_logF), true);
+
+ jfloat result = env_->CallStaticFloatMethod(jklass_, jmethod_, 2.0);
+ EXPECT_EQ(logf(2.0), result);
+}
+
+jboolean Java_MyClassNatives_returnTrue(JNIEnv* env, jclass klass) {
+ return JNI_TRUE;
+}
+
+jboolean Java_MyClassNatives_returnFalse(JNIEnv* env, jclass klass) {
+ return JNI_FALSE;
+}
+
+jint Java_MyClassNatives_returnInt(JNIEnv* env, jclass klass) {
+ return 42;
+}
+
+TEST_F(JniCompilerTest, RunGenericStaticReturnTrue) {
+ TEST_DISABLED_FOR_PORTABLE();
+ TEST_DISABLED_FOR_MIPS();
+ SetUpForTest(true, "returnTrue", "()Z",
+ reinterpret_cast<void*>(&Java_MyClassNatives_returnTrue), true);
+
+ jboolean result = env_->CallStaticBooleanMethod(jklass_, jmethod_);
+ EXPECT_TRUE(result);
+}
+
+TEST_F(JniCompilerTest, RunGenericStaticReturnFalse) {
+ TEST_DISABLED_FOR_PORTABLE();
+ TEST_DISABLED_FOR_MIPS();
+ SetUpForTest(true, "returnFalse", "()Z",
+ reinterpret_cast<void*>(&Java_MyClassNatives_returnFalse), true);
+
+ jboolean result = env_->CallStaticBooleanMethod(jklass_, jmethod_);
+ EXPECT_FALSE(result);
+}
+
+TEST_F(JniCompilerTest, RunGenericStaticReturnInt) {
+ TEST_DISABLED_FOR_PORTABLE();
+ TEST_DISABLED_FOR_MIPS();
+ SetUpForTest(true, "returnInt", "()I",
+ reinterpret_cast<void*>(&Java_MyClassNatives_returnInt), true);
+
+ jint result = env_->CallStaticIntMethod(jklass_, jmethod_);
+ EXPECT_EQ(42, result);
+}
+
int gJava_MyClassNatives_fooSIOO_calls = 0;
jobject Java_MyClassNatives_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
jobject z) {
// result sign extension is handled in C code
// prepare for artQuickGenericJniEndTrampoline call
// (Thread*, result, result_f)
- // r0 r1,r2 r3,stack <= C calling convention
+ // r0 r2,r3 stack <= C calling convention
// r11 r0,r1 r0,r1 <= where they are
- sub sp, sp, #12 // Stack alignment.
+ sub sp, sp, #8 // Stack alignment.
- push {r1}
- mov r3, r0
- mov r2, r1
- mov r1, r0
+ push {r0-r1}
+ mov r3, r1
+ mov r2, r0
mov r0, r11
blx artQuickGenericJniEndTrampoline
cbnz r2, .Lexception_in_native
// Tear down the callee-save frame.
- RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ add sp, #12 @ rewind sp
+ // Do not pop r0 and r1, they contain the return value.
+ pop {r2-r3, r5-r8, r10-r11, lr} @ 9 words of callee saves
+ .cfi_restore r2
+ .cfi_restore r3
+ .cfi_restore r5
+ .cfi_restore r6
+ .cfi_restore r7
+ .cfi_restore r8
+ .cfi_restore r10
+ .cfi_restore r11
+ .cfi_adjust_cfa_offset -48
bx lr // ret
Object o248, Object o249, Object o250, Object o251, Object o252, Object o253);
native void withoutImplementation();
-
+
native static void stackArgsIntsFirst(int i1, int i2, int i3, int i4, int i5, int i6, int i7,
int i8, int i9, int i10, float f1, float f2, float f3, float f4, float f5, float f6,
float f7, float f8, float f9, float f10);
-
+
native static void stackArgsFloatsFirst(float f1, float f2, float f3, float f4, float f5,
float f6, float f7, float f8, float f9, float f10, int i1, int i2, int i3, int i4, int i5,
int i6, int i7, int i8, int i9, int i10);
-
+
native static void stackArgsMixed(int i1, float f1, int i2, float f2, int i3, float f3, int i4,
float f4, int i5, float f5, int i6, float f6, int i7, float f7, int i8, float f8, int i9,
float f9, int i10, float f10);
+
+ static native double logD(double d);
+ static native float logF(float f);
+ static native boolean returnTrue();
+ static native boolean returnFalse();
+ static native int returnInt();
}