blob: 5e19d4d6caad0dc30ca3b0b90be49c31620cb609 [file] [log] [blame]
Ian Rogersb033c752011-07-20 12:22:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Ian Rogersb033c752011-07-20 12:22:35 -07002
Elliott Hughes90a33692011-08-30 13:27:07 -07003#include "jni_compiler.h"
4
Ian Rogersb033c752011-07-20 12:22:35 -07005#include <sys/mman.h>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07006
Elliott Hughes90a33692011-08-30 13:27:07 -07007#include "UniquePtr.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07008#include "assembler.h"
9#include "class_linker.h"
10#include "common_test.h"
11#include "dex_file.h"
Elliott Hughes90a33692011-08-30 13:27:07 -070012#include "gtest/gtest.h"
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070013#include "indirect_reference_table.h"
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070014#include "jni_internal.h"
Brian Carlstromdb4d5402011-08-09 12:18:28 -070015#include "mem_map.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070016#include "runtime.h"
Ian Rogersaaa20802011-09-11 21:47:37 -070017#include "scoped_jni_thread_state.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070018#include "thread.h"
Ian Rogersb033c752011-07-20 12:22:35 -070019
Brian Carlstromb9cc1ca2012-01-27 00:57:42 -080020extern "C"
21JNIEXPORT jint JNICALL Java_MyClass_bar(JNIEnv* env, jobject thisObj, jint count) {
22 return count + 1;
23}
24
Ian Rogersb033c752011-07-20 12:22:35 -070025namespace art {
26
Brian Carlstromf734cf52011-08-17 16:28:14 -070027class JniCompilerTest : public CommonTest {
Ian Rogersb033c752011-07-20 12:22:35 -070028 protected:
Ian Rogersb033c752011-07-20 12:22:35 -070029
Brian Carlstrom40381fb2011-10-19 14:13:40 -070030 void CompileForTest(ClassLoader* class_loader, bool direct,
31 const char* method_name, const char* method_sig) {
Brian Carlstrom25c33252011-09-18 15:58:35 -070032 // Compile the native method before starting the runtime
Brian Carlstrom40381fb2011-10-19 14:13:40 -070033 Class* c = class_linker_->FindClass("LMyClass;", class_loader);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070034 Method* method;
35 if (direct) {
buzbeec143c552011-08-20 17:38:58 -070036 method = c->FindDirectMethod(method_name, method_sig);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070037 } else {
buzbeec143c552011-08-20 17:38:58 -070038 method = c->FindVirtualMethod(method_name, method_sig);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070039 }
40 ASSERT_TRUE(method != NULL);
Brian Carlstrom25c33252011-09-18 15:58:35 -070041 if (method->GetCode() != NULL) {
42 return;
43 }
Brian Carlstrom9baa4ae2011-09-01 21:14:14 -070044 CompileMethod(method);
Elliott Hughes1240dad2011-09-09 16:24:50 -070045 ASSERT_TRUE(method->GetCode() != NULL);
Brian Carlstrom25c33252011-09-18 15:58:35 -070046 }
47
Brian Carlstrom40381fb2011-10-19 14:13:40 -070048 void SetupForTest(ClassLoader* class_loader, bool direct,
49 const char* method_name, const char* method_sig,
Brian Carlstrom25c33252011-09-18 15:58:35 -070050 void* native_fnptr) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -070051 CompileForTest(class_loader, direct, method_name, method_sig);
Brian Carlstrom25c33252011-09-18 15:58:35 -070052 if (!runtime_->IsStarted()) {
53 runtime_->Start();
54 }
55
56 // JNI operations after runtime start
57 env_ = Thread::Current()->GetJniEnv();
58 jklass_ = env_->FindClass("MyClass");
59 ASSERT_TRUE(jklass_ != NULL);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070060
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070061 if (direct) {
62 jmethod_ = env_->GetStaticMethodID(jklass_, method_name, method_sig);
63 } else {
64 jmethod_ = env_->GetMethodID(jklass_, method_name, method_sig);
65 }
66 ASSERT_TRUE(jmethod_ != NULL);
67
Ian Rogersbdb03912011-09-14 00:55:44 -070068 if (native_fnptr != NULL) {
Shih-wei Liao31384c52011-09-06 15:27:45 -070069 JNINativeMethod methods[] = {{method_name, method_sig, native_fnptr}};
70 ASSERT_EQ(JNI_OK, env_->RegisterNatives(jklass_, methods, 1));
Ian Rogersbdb03912011-09-14 00:55:44 -070071 } else {
72 env_->UnregisterNatives(jklass_);
Shih-wei Liao31384c52011-09-06 15:27:45 -070073 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070074
75 jmethodID constructor = env_->GetMethodID(jklass_, "<init>", "()V");
76 jobj_ = env_->NewObject(jklass_, constructor);
77 ASSERT_TRUE(jobj_ != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070078 }
79
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070080 public:
81 static jclass jklass_;
82 static jobject jobj_;
83 protected:
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070084 JNIEnv* env_;
85 jmethodID jmethod_;
Ian Rogersb033c752011-07-20 12:22:35 -070086};
87
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070088jclass JniCompilerTest::jklass_;
89jobject JniCompilerTest::jobj_;
90
Ian Rogersb033c752011-07-20 12:22:35 -070091int gJava_MyClass_foo_calls = 0;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070092void Java_MyClass_foo(JNIEnv* env, jobject thisObj) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -070093 // 2 = SirtRef<ClassLoader> + thisObj
94 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Ian Rogersb033c752011-07-20 12:22:35 -070095 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070096 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
97 EXPECT_TRUE(thisObj != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -070098 EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
Ian Rogersb033c752011-07-20 12:22:35 -070099 gJava_MyClass_foo_calls++;
100}
101
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700102TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700103 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
104 SetupForTest(class_loader.get(), false, "foo", "()V",
105 reinterpret_cast<void*>(&Java_MyClass_foo));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700106
107 EXPECT_EQ(0, gJava_MyClass_foo_calls);
108 env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
109 EXPECT_EQ(1, gJava_MyClass_foo_calls);
110 env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
111 EXPECT_EQ(2, gJava_MyClass_foo_calls);
112}
113
Shih-wei Liao31384c52011-09-06 15:27:45 -0700114TEST_F(JniCompilerTest, CompileAndRunIntMethodThroughStub) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700115 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
116 SetupForTest(class_loader.get(), false, "bar", "(I)I",
Brian Carlstromb9cc1ca2012-01-27 00:57:42 -0800117 NULL /* calling through stub will load &Java_MyClass_bar */);
Shih-wei Liao31384c52011-09-06 15:27:45 -0700118
Shih-wei Liao31384c52011-09-06 15:27:45 -0700119 std::string reason;
Brian Carlstromb9cc1ca2012-01-27 00:57:42 -0800120 ASSERT_TRUE(Runtime::Current()->GetJavaVM()->LoadNativeLibrary("", class_loader.get(), reason))
121 << reason;
Shih-wei Liao31384c52011-09-06 15:27:45 -0700122
123 jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 24);
124 EXPECT_EQ(25, result);
125}
126
Ian Rogersb033c752011-07-20 12:22:35 -0700127int gJava_MyClass_fooI_calls = 0;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700128jint Java_MyClass_fooI(JNIEnv* env, jobject thisObj, jint x) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700129 // 2 = SirtRef<ClassLoader> + thisObj
130 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Ian Rogersb033c752011-07-20 12:22:35 -0700131 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700132 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
133 EXPECT_TRUE(thisObj != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700134 EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
Ian Rogersb033c752011-07-20 12:22:35 -0700135 gJava_MyClass_fooI_calls++;
136 return x;
137}
138
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700139TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700140 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
141 SetupForTest(class_loader.get(), false, "fooI", "(I)I",
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700142 reinterpret_cast<void*>(&Java_MyClass_fooI));
143
144 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
145 jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 42);
146 EXPECT_EQ(42, result);
147 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
148 result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 0xCAFED00D);
149 EXPECT_EQ(static_cast<jint>(0xCAFED00D), result);
150 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
151}
152
Ian Rogersb033c752011-07-20 12:22:35 -0700153int gJava_MyClass_fooII_calls = 0;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700154jint Java_MyClass_fooII(JNIEnv* env, jobject thisObj, jint x, jint y) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700155 // 2 = SirtRef<ClassLoader> + thisObj
156 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Ian Rogersb033c752011-07-20 12:22:35 -0700157 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700158 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
159 EXPECT_TRUE(thisObj != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700160 EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
Ian Rogersb033c752011-07-20 12:22:35 -0700161 gJava_MyClass_fooII_calls++;
162 return x - y; // non-commutative operator
163}
164
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700165TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700166 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
167 SetupForTest(class_loader.get(), false, "fooII", "(II)I",
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700168 reinterpret_cast<void*>(&Java_MyClass_fooII));
169
170 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
171 jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 99, 10);
172 EXPECT_EQ(99 - 10, result);
173 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
174 result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 0xCAFEBABE,
175 0xCAFED00D);
176 EXPECT_EQ(static_cast<jint>(0xCAFEBABE - 0xCAFED00D), result);
177 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
178}
179
Ian Rogers9b269d22011-09-04 14:06:05 -0700180int gJava_MyClass_fooJJ_calls = 0;
181jlong Java_MyClass_fooJJ(JNIEnv* env, jobject thisObj, jlong x, jlong y) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700182 // 2 = SirtRef<ClassLoader> + thisObj
183 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Ian Rogers9b269d22011-09-04 14:06:05 -0700184 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
185 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
186 EXPECT_TRUE(thisObj != NULL);
187 EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
188 gJava_MyClass_fooJJ_calls++;
189 return x - y; // non-commutative operator
190}
191
192TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700193 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
194 SetupForTest(class_loader.get(), false, "fooJJ", "(JJ)J",
Ian Rogers9b269d22011-09-04 14:06:05 -0700195 reinterpret_cast<void*>(&Java_MyClass_fooJJ));
196
197 EXPECT_EQ(0, gJava_MyClass_fooJJ_calls);
198 jlong a = 0x1234567890ABCDEFll;
199 jlong b = 0xFEDCBA0987654321ll;
200 jlong result = env_->CallNonvirtualLongMethod(jobj_, jklass_, jmethod_, a, b);
201 EXPECT_EQ(a - b, result);
202 EXPECT_EQ(1, gJava_MyClass_fooJJ_calls);
203 result = env_->CallNonvirtualLongMethod(jobj_, jklass_, jmethod_, b, a);
204 EXPECT_EQ(b - a, result);
205 EXPECT_EQ(2, gJava_MyClass_fooJJ_calls);
206}
207
Ian Rogersb033c752011-07-20 12:22:35 -0700208int gJava_MyClass_fooDD_calls = 0;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700209jdouble Java_MyClass_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdouble y) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700210 // 2 = SirtRef<ClassLoader> + thisObj
211 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Ian Rogersb033c752011-07-20 12:22:35 -0700212 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700213 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
214 EXPECT_TRUE(thisObj != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700215 EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
Ian Rogersb033c752011-07-20 12:22:35 -0700216 gJava_MyClass_fooDD_calls++;
217 return x - y; // non-commutative operator
218}
219
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700220TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700221 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
222 SetupForTest(class_loader.get(), false, "fooDD", "(DD)D",
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700223 reinterpret_cast<void*>(&Java_MyClass_fooDD));
224
225 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
226 jdouble result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_,
227 99.0, 10.0);
228 EXPECT_EQ(99.0 - 10.0, result);
229 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
230 jdouble a = 3.14159265358979323846;
231 jdouble b = 0.69314718055994530942;
232 result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_, a, b);
233 EXPECT_EQ(a - b, result);
234 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
235}
236
Ian Rogersb033c752011-07-20 12:22:35 -0700237int gJava_MyClass_fooIOO_calls = 0;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700238jobject Java_MyClass_fooIOO(JNIEnv* env, jobject thisObj, jint x, jobject y,
Ian Rogersb033c752011-07-20 12:22:35 -0700239 jobject z) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700240 // 4 = SirtRef<ClassLoader> + this + y + z
241 EXPECT_EQ(4U, Thread::Current()->NumSirtReferences());
Ian Rogersb033c752011-07-20 12:22:35 -0700242 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700243 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
244 EXPECT_TRUE(thisObj != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700245 EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
Ian Rogersb033c752011-07-20 12:22:35 -0700246 gJava_MyClass_fooIOO_calls++;
247 switch (x) {
248 case 1:
249 return y;
250 case 2:
251 return z;
252 default:
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700253 return thisObj;
Ian Rogersb033c752011-07-20 12:22:35 -0700254 }
255}
256
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700257TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700258 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
259 SetupForTest(class_loader.get(), false, "fooIOO",
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700260 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
261 reinterpret_cast<void*>(&Java_MyClass_fooIOO));
262
263 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
264 jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 0, NULL, NULL);
265 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
266 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
267
268 result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 0, NULL, jklass_);
269 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
270 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
271 result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 1, NULL, jklass_);
272 EXPECT_TRUE(env_->IsSameObject(NULL, result));
273 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
274 result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 2, NULL, jklass_);
275 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
276 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
277
278 result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 0, jklass_, NULL);
279 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
280 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
281 result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 1, jklass_, NULL);
282 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
283 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
284 result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 2, jklass_, NULL);
285 EXPECT_TRUE(env_->IsSameObject(NULL, result));
286 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
287}
288
Shih-wei Liao82da44b2011-09-01 00:38:04 -0700289int gJava_MyClass_fooSII_calls = 0;
290jint Java_MyClass_fooSII(JNIEnv* env, jclass klass, jint x, jint y) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700291 // 2 = SirtRef<ClassLoader> + klass
292 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Shih-wei Liao82da44b2011-09-01 00:38:04 -0700293 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
294 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
295 EXPECT_TRUE(klass != NULL);
296 EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
297 gJava_MyClass_fooSII_calls++;
298 return x + y;
299}
300
Shih-wei Liao82da44b2011-09-01 00:38:04 -0700301TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700302 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
303 SetupForTest(class_loader.get(), true, "fooSII", "(II)I",
Shih-wei Liao82da44b2011-09-01 00:38:04 -0700304 reinterpret_cast<void*>(&Java_MyClass_fooSII));
305
306 EXPECT_EQ(0, gJava_MyClass_fooSII_calls);
307 jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 20, 30);
308 EXPECT_EQ(50, result);
309 EXPECT_EQ(1, gJava_MyClass_fooSII_calls);
310}
311
Ian Rogers7a99c112011-09-07 12:48:27 -0700312int gJava_MyClass_fooSDD_calls = 0;
313jdouble Java_MyClass_fooSDD(JNIEnv* env, jclass klass, jdouble x, jdouble y) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700314 // 2 = SirtRef<ClassLoader> + klass
315 EXPECT_EQ(2U, Thread::Current()->NumSirtReferences());
Ian Rogers7a99c112011-09-07 12:48:27 -0700316 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
317 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
318 EXPECT_TRUE(klass != NULL);
319 EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
320 gJava_MyClass_fooSDD_calls++;
321 return x - y; // non-commutative operator
322}
323
324TEST_F(JniCompilerTest, CompileAndRunStaticDoubleDoubleMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700325 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
326 SetupForTest(class_loader.get(), true, "fooSDD", "(DD)D",
Ian Rogers7a99c112011-09-07 12:48:27 -0700327 reinterpret_cast<void*>(&Java_MyClass_fooSDD));
328
329 EXPECT_EQ(0, gJava_MyClass_fooSDD_calls);
330 jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 99.0, 10.0);
331 EXPECT_EQ(99.0 - 10.0, result);
332 EXPECT_EQ(1, gJava_MyClass_fooSDD_calls);
333 jdouble a = 3.14159265358979323846;
334 jdouble b = 0.69314718055994530942;
335 result = env_->CallStaticDoubleMethod(jklass_, jmethod_, a, b);
336 EXPECT_EQ(a - b, result);
337 EXPECT_EQ(2, gJava_MyClass_fooSDD_calls);
338}
339
Ian Rogersb033c752011-07-20 12:22:35 -0700340int gJava_MyClass_fooSIOO_calls = 0;
Elliott Hughes330304d2011-08-12 14:28:05 -0700341jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
Ian Rogersb033c752011-07-20 12:22:35 -0700342 jobject z) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700343 // 4 = SirtRef<ClassLoader> + klass + y + z
344 EXPECT_EQ(4U, Thread::Current()->NumSirtReferences());
Ian Rogersb033c752011-07-20 12:22:35 -0700345 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700346 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
347 EXPECT_TRUE(klass != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700348 EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
Ian Rogersb033c752011-07-20 12:22:35 -0700349 gJava_MyClass_fooSIOO_calls++;
350 switch (x) {
351 case 1:
352 return y;
353 case 2:
354 return z;
355 default:
356 return klass;
357 }
358}
359
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700360
361TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700362 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
363 SetupForTest(class_loader.get(), true, "fooSIOO",
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700364 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
365 reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
366
367 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
368 jobject result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, NULL);
369 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
370 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
371
372 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, jobj_);
373 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
374 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
375 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, NULL, jobj_);
376 EXPECT_TRUE(env_->IsSameObject(NULL, result));
377 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
378 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, NULL, jobj_);
379 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
380 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
381
382 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, jobj_, NULL);
383 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
384 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
385 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, jobj_, NULL);
386 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
387 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
388 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, jobj_, NULL);
389 EXPECT_TRUE(env_->IsSameObject(NULL, result));
390 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
391}
392
Ian Rogersdf20fe02011-07-20 20:34:16 -0700393int gJava_MyClass_fooSSIOO_calls = 0;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700394jobject Java_MyClass_fooSSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
Ian Rogersdf20fe02011-07-20 20:34:16 -0700395 jobject z) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700396 // 4 = SirtRef<ClassLoader> + klass + y + z
397 EXPECT_EQ(4U, Thread::Current()->NumSirtReferences());
Ian Rogersdf20fe02011-07-20 20:34:16 -0700398 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700399 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
400 EXPECT_TRUE(klass != NULL);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700401 EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700402 gJava_MyClass_fooSSIOO_calls++;
403 switch (x) {
404 case 1:
405 return y;
406 case 2:
407 return z;
408 default:
409 return klass;
410 }
411}
412
Ian Rogersdf20fe02011-07-20 20:34:16 -0700413TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700414 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
415 SetupForTest(class_loader.get(), true, "fooSSIOO",
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700416 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
417 reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700418
Ian Rogersdf20fe02011-07-20 20:34:16 -0700419 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700420 jobject result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, NULL);
421 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700422 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700423
424 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, jobj_);
425 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700426 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700427 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, NULL, jobj_);
428 EXPECT_TRUE(env_->IsSameObject(NULL, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700429 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700430 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, NULL, jobj_);
431 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700432 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700433
434 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, jobj_, NULL);
435 EXPECT_TRUE(env_->IsSameObject(jklass_, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700436 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700437 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, jobj_, NULL);
438 EXPECT_TRUE(env_->IsSameObject(jobj_, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700439 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700440 result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, jobj_, NULL);
441 EXPECT_TRUE(env_->IsSameObject(NULL, result));
Ian Rogersdf20fe02011-07-20 20:34:16 -0700442 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
443}
444
Elliott Hughesa2501992011-08-26 19:39:54 -0700445void Java_MyClass_throwException(JNIEnv* env, jobject) {
446 jclass c = env->FindClass("java/lang/RuntimeException");
447 env->ThrowNew(c, "hello");
448}
Ian Rogers45a76cb2011-07-21 22:00:15 -0700449
Elliott Hughesa2501992011-08-26 19:39:54 -0700450TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700451 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
452
Brian Carlstrom25c33252011-09-18 15:58:35 -0700453 // all compilation needs to happen before SetupForTest calls Runtime::Start
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700454 CompileForTest(class_loader.get(), false, "foo", "()V");
455 CompileForTest(class_loader.get(), false, "throwException", "()V");
456 CompileForTest(class_loader.get(), false, "foo", "()V");
Brian Carlstrom25c33252011-09-18 15:58:35 -0700457
Ian Rogers45a76cb2011-07-21 22:00:15 -0700458 gJava_MyClass_foo_calls = 0;
Elliott Hughesa2501992011-08-26 19:39:54 -0700459
Ian Rogers67375ac2011-09-14 00:55:44 -0700460 // Check a single call of a JNI method is ok
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700461 SetupForTest(class_loader.get(), false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClass_foo));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700462 env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700463 EXPECT_EQ(1, gJava_MyClass_foo_calls);
Ian Rogers67375ac2011-09-14 00:55:44 -0700464 EXPECT_FALSE(Thread::Current()->IsExceptionPending());
Elliott Hughesa2501992011-08-26 19:39:54 -0700465
Ian Rogers67375ac2011-09-14 00:55:44 -0700466 // Get class for exception we expect to be thrown
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700467 Class* jlre = class_linker_->FindClass("Ljava/lang/RuntimeException;", class_loader.get());
468 SetupForTest(class_loader.get(), false, "throwException", "()V",
469 reinterpret_cast<void*>(&Java_MyClass_throwException));
Ian Rogers67375ac2011-09-14 00:55:44 -0700470 // Call Java_MyClass_throwException (JNI method that throws exception)
Elliott Hughesa2501992011-08-26 19:39:54 -0700471 env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
472 EXPECT_EQ(1, gJava_MyClass_foo_calls);
Ian Rogers67375ac2011-09-14 00:55:44 -0700473 EXPECT_TRUE(Thread::Current()->IsExceptionPending());
474 EXPECT_TRUE(Thread::Current()->GetException()->InstanceOf(jlre));
475 Thread::Current()->ClearException();
Elliott Hughesa2501992011-08-26 19:39:54 -0700476
Ian Rogers67375ac2011-09-14 00:55:44 -0700477 // Check a single call of a JNI method is ok
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700478 SetupForTest(class_loader.get(), false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClass_foo));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700479 env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700480 EXPECT_EQ(2, gJava_MyClass_foo_calls);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700481}
482
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700483jint Java_MyClass_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) {
484 if (i <= 0) {
Ian Rogersaaa20802011-09-11 21:47:37 -0700485 // We want to check raw Object*/Array* below
486 ScopedJniThreadState ts(env);
487
488 // Build stack trace
Elliott Hughes01158d72011-09-19 19:47:10 -0700489 jobject internal = Thread::Current()->CreateInternalStackTrace(env);
490 jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal);
Ian Rogersaaa20802011-09-11 21:47:37 -0700491 ObjectArray<StackTraceElement>* trace_array =
492 Decode<ObjectArray<StackTraceElement>*>(env, ste_array);
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700493 EXPECT_TRUE(trace_array != NULL);
494 EXPECT_EQ(11, trace_array->GetLength());
495
Ian Rogersaaa20802011-09-11 21:47:37 -0700496 // Check stack trace entries have expected values
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700497 for (int32_t i = 0; i < trace_array->GetLength(); ++i) {
498 EXPECT_EQ(-2, trace_array->Get(i)->GetLineNumber());
Ian Rogersaaa20802011-09-11 21:47:37 -0700499 StackTraceElement* ste = trace_array->Get(i);
500 EXPECT_STREQ("MyClassNatives.java", ste->GetFileName()->ToModifiedUtf8().c_str());
501 EXPECT_STREQ("MyClass", ste->GetDeclaringClass()->ToModifiedUtf8().c_str());
502 EXPECT_STREQ("fooI", ste->GetMethodName()->ToModifiedUtf8().c_str());
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700503 }
Ian Rogersaaa20802011-09-11 21:47:37 -0700504
505 // end recursion
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700506 return 0;
507 } else {
508 jclass jklass = env->FindClass("MyClass");
509 EXPECT_TRUE(jklass != NULL);
510 jmethodID jmethod = env->GetMethodID(jklass, "fooI", "(I)I");
511 EXPECT_TRUE(jmethod != NULL);
512
Ian Rogersaaa20802011-09-11 21:47:37 -0700513 // Recurse with i - 1
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700514 jint result = env->CallNonvirtualIntMethod(thisObj, jklass, jmethod, i - 1);
Ian Rogersaaa20802011-09-11 21:47:37 -0700515
516 // Return sum of all depths
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700517 return i + result;
518 }
519}
520
521TEST_F(JniCompilerTest, NativeStackTraceElement) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700522 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
523 SetupForTest(class_loader.get(), false, "fooI", "(I)I",
524 reinterpret_cast<void*>(&Java_MyClass_nativeUpCall));
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700525 jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 10);
Ian Rogersaaa20802011-09-11 21:47:37 -0700526 EXPECT_EQ(10+9+8+7+6+5+4+3+2+1, result);
Shih-wei Liaoff0f9be2011-08-29 15:43:53 -0700527}
528
Ian Rogers9b269d22011-09-04 14:06:05 -0700529jobject Java_MyClass_fooO(JNIEnv* env, jobject thisObj, jobject x) {
Shih-wei Liao558788e2011-09-01 02:39:11 -0700530 return env->NewGlobalRef(x);
531}
532
Ian Rogersb9231c82011-09-05 22:13:19 -0700533TEST_F(JniCompilerTest, ReturnGlobalRef) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700534 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
535 SetupForTest(class_loader.get(), false, "fooO", "(Ljava/lang/Object;)Ljava/lang/Object;",
Ian Rogers9b269d22011-09-04 14:06:05 -0700536 reinterpret_cast<void*>(&Java_MyClass_fooO));
Shih-wei Liao558788e2011-09-01 02:39:11 -0700537 jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, jobj_);
538 EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(result));
539 EXPECT_TRUE(env_->IsSameObject(result, jobj_));
540}
541
Ian Rogersdc51b792011-09-22 20:41:37 -0700542jint local_ref_test(JNIEnv* env, jobject thisObj, jint x) {
543 // Add 10 local references
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700544 for (int i = 0; i < 10; i++) {
Ian Rogersdc51b792011-09-22 20:41:37 -0700545 AddLocalReference<jobject>(env, Decode<Object*>(env, thisObj));
546 }
547 return x+1;
548}
549
550TEST_F(JniCompilerTest, LocalReferenceTableClearingTest) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700551 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
552 SetupForTest(class_loader.get(), false, "fooI", "(I)I", reinterpret_cast<void*>(&local_ref_test));
Ian Rogersdc51b792011-09-22 20:41:37 -0700553 // 1000 invocations of a method that adds 10 local references
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700554 for (int i=0; i < 1000; i++) {
Ian Rogersdc51b792011-09-22 20:41:37 -0700555 jint result = env_->CallIntMethod(jobj_, jmethod_, i);
556 EXPECT_TRUE(result == i + 1);
557 }
558}
559
Ian Rogersb9231c82011-09-05 22:13:19 -0700560void my_arraycopy(JNIEnv* env, jclass klass, jobject src, jint src_pos, jobject dst, jint dst_pos, jint length) {
561 EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jklass_, klass));
562 EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jklass_, dst));
Ian Rogers82f3e092011-09-05 22:54:45 -0700563 EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, src));
Ian Rogersb9231c82011-09-05 22:13:19 -0700564 EXPECT_EQ(1234, src_pos);
565 EXPECT_EQ(5678, dst_pos);
566 EXPECT_EQ(9876, length);
567}
568
569TEST_F(JniCompilerTest, JavaLangSystemArrayCopy) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700570 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
571 SetupForTest(class_loader.get(), true, "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V",
Ian Rogersb9231c82011-09-05 22:13:19 -0700572 reinterpret_cast<void*>(&my_arraycopy));
Ian Rogers82f3e092011-09-05 22:54:45 -0700573 env_->CallStaticVoidMethod(jklass_, jmethod_, jobj_, 1234, jklass_, 5678, 9876);
Ian Rogersb9231c82011-09-05 22:13:19 -0700574}
575
Ian Rogers67375ac2011-09-14 00:55:44 -0700576jboolean my_casi(JNIEnv* env, jobject unsafe, jobject obj, jlong offset, jint expected, jint newval) {
577 EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, unsafe));
578 EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, obj));
579 EXPECT_EQ(0x12345678ABCDEF88ll, offset);
580 EXPECT_EQ(static_cast<jint>(0xCAFEF00D), expected);
581 EXPECT_EQ(static_cast<jint>(0xEBADF00D), newval);
582 return JNI_TRUE;
583}
584
585TEST_F(JniCompilerTest, CompareAndSwapInt) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -0700586 SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
587 SetupForTest(class_loader.get(), false, "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
Ian Rogers67375ac2011-09-14 00:55:44 -0700588 reinterpret_cast<void*>(&my_casi));
589 jboolean result = env_->CallBooleanMethod(jobj_, jmethod_, jobj_, 0x12345678ABCDEF88ll, 0xCAFEF00D, 0xEBADF00D);
590 EXPECT_EQ(result, JNI_TRUE);
591}
592
Ian Rogersb033c752011-07-20 12:22:35 -0700593} // namespace art