blob: 3041927c46355d164e928ec6503593193c9ab9ca [file] [log] [blame]
Ian Rogersb033c752011-07-20 12:22:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2// Author: irogers@google.com (Ian Rogers)
3
4#include <sys/mman.h>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07005
6#include "assembler.h"
7#include "class_linker.h"
8#include "common_test.h"
9#include "dex_file.h"
10#include "jni_compiler.h"
11#include "runtime.h"
12#include "thread.h"
Ian Rogersb033c752011-07-20 12:22:35 -070013#include "gtest/gtest.h"
14
15namespace art {
16
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070017class JniCompilerTest : public RuntimeTest {
Ian Rogersb033c752011-07-20 12:22:35 -070018 protected:
19 virtual void SetUp() {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070020 RuntimeTest::SetUp();
Ian Rogersb033c752011-07-20 12:22:35 -070021 // Create thunk code that performs the native to managed transition
Brian Carlstromb0460ea2011-07-29 10:08:05 -070022 thunk_code_size_ = kPageSize;
Ian Rogersb033c752011-07-20 12:22:35 -070023 thunk_ = mmap(NULL, thunk_code_size_, PROT_READ | PROT_WRITE | PROT_EXEC,
24 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
25 CHECK_NE(MAP_FAILED, thunk_);
26 Assembler thk_asm;
27 // TODO: shouldn't have machine specific code in a general purpose file
28#if defined(__i386__)
29 thk_asm.pushl(EDI); // preserve EDI
30 thk_asm.movl(EAX, Address(ESP, 8)); // EAX = method->GetCode()
31 thk_asm.movl(EDI, Address(ESP, 12)); // EDI = method
32 thk_asm.pushl(Immediate(0)); // push pad
33 thk_asm.pushl(Immediate(0)); // push pad
Carl Shapiroe2d373e2011-07-25 15:20:06 -070034 thk_asm.pushl(Address(ESP, 44)); // push pad or jlong high
35 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
36 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong high
37 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
38 thk_asm.pushl(Address(ESP, 44)); // push jobject
Ian Rogersb033c752011-07-20 12:22:35 -070039 thk_asm.call(EAX); // Continue in method->GetCode()
40 thk_asm.addl(ESP, Immediate(28)); // pop arguments
41 thk_asm.popl(EDI); // restore EDI
42 thk_asm.ret();
Carl Shapiroe2d373e2011-07-25 15:20:06 -070043#elif defined(__arm__)
44 thk_asm.AddConstant(SP, -32); // Build frame
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070045 thk_asm.StoreToOffset(kStoreWord, LR, SP, 28); // Spill link register
46 thk_asm.StoreToOffset(kStoreWord, R9, SP, 24); // Spill R9
47 thk_asm.mov(R12, ShifterOperand(R0)); // R12 = method->GetCode()
48 thk_asm.mov(R0, ShifterOperand(R1)); // R0 = method
49 thk_asm.mov(R9, ShifterOperand(R2)); // R9 = Thread::Current()
50 thk_asm.mov(R1, ShifterOperand(R3)); // R1 = arg1 (jint/jlong low)
51 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 44); // R3 = arg5 (pad/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070052 thk_asm.StoreToOffset(kStoreWord, R3, SP, 4);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070053 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 40); // R3 = arg4 (jint/jlong low)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070054 thk_asm.StoreToOffset(kStoreWord, R3, SP, 0);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070055 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 36); // R3 = arg3 (jint/jlong high)
56 thk_asm.LoadFromOffset(kLoadWord, R2, SP, 32); // R2 = arg2 (jint/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070057 thk_asm.blx(R12); // Branch and link R12
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070058 thk_asm.LoadFromOffset(kLoadWord, LR, SP, 28); // Fill link register
59 thk_asm.LoadFromOffset(kLoadWord, R9, SP, 24); // Fill R9
Carl Shapiroe2d373e2011-07-25 15:20:06 -070060 thk_asm.AddConstant(SP, 32); // Remove frame
61 thk_asm.mov(PC, ShifterOperand(LR)); // Return
Ian Rogersb033c752011-07-20 12:22:35 -070062#else
Carl Shapiroe2d373e2011-07-25 15:20:06 -070063#error Unimplemented
Ian Rogersb033c752011-07-20 12:22:35 -070064#endif
65 size_t cs = thk_asm.CodeSize();
66 MemoryRegion code(thunk_, cs);
67 thk_asm.FinalizeInstructions(code);
68 thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070069 Thread*, jobject, jint, jint,
70 jint)
Ian Rogersb033c752011-07-20 12:22:35 -070071 >(code.pointer());
72 thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070073 Thread*, jobject, jdouble,
74 jdouble)
Ian Rogersb033c752011-07-20 12:22:35 -070075 >(code.pointer());
76 }
77
78 virtual void TearDown() {
79 // Release thunk code
80 CHECK(runtime_->DetachCurrentThread());
81 CHECK_EQ(0, munmap(thunk_, thunk_code_size_));
82 }
83
84 // Run generated code associated with method passing and returning int size
85 // arguments
86 jvalue RunMethod(Method* method, jvalue a, jvalue b, jvalue c, jvalue d) {
87 jvalue result;
88 // sanity checks
89 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
90 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
91 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
92 // perform call
Carl Shapiroe2d373e2011-07-25 15:20:06 -070093 result.i = (*thunk_entry1_)(method->GetCode(), method, Thread::Current(),
94 a.l, b.i, c.i, d.i);
Ian Rogersb033c752011-07-20 12:22:35 -070095 // sanity check post-call
96 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
97 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
98 return result;
99 }
100
101 // Run generated code associated with method passing and returning double size
102 // arguments
103 jvalue RunMethodD(Method* method, jvalue a, jvalue b, jvalue c) {
104 jvalue result;
105 // sanity checks
106 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
107 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
108 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
109 // perform call
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700110 result.d = (*thunk_entry2_)(method->GetCode(), method, Thread::Current(),
111 a.l, b.d, c.d);
Ian Rogersb033c752011-07-20 12:22:35 -0700112 // sanity check post-call
113 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
114 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
115 return result;
116 }
117
Ian Rogersb033c752011-07-20 12:22:35 -0700118 void* thunk_;
119 size_t thunk_code_size_;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700120 jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
121 jint);
122 jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
123 jdouble);
Ian Rogersb033c752011-07-20 12:22:35 -0700124};
125
126int gJava_MyClass_foo_calls = 0;
127void Java_MyClass_foo(JNIEnv*, jobject) {
128 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
129 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
130 gJava_MyClass_foo_calls++;
131}
132
133int gJava_MyClass_fooI_calls = 0;
134jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
135 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
136 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
137 gJava_MyClass_fooI_calls++;
138 return x;
139}
140
141int gJava_MyClass_fooII_calls = 0;
142jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
143 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
144 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
145 gJava_MyClass_fooII_calls++;
146 return x - y; // non-commutative operator
147}
148
149int gJava_MyClass_fooDD_calls = 0;
150jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
151 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
152 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
153 gJava_MyClass_fooDD_calls++;
154 return x - y; // non-commutative operator
155}
156
157int gJava_MyClass_fooIOO_calls = 0;
158jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
159 jobject z) {
160 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
161 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
162 gJava_MyClass_fooIOO_calls++;
163 switch (x) {
164 case 1:
165 return y;
166 case 2:
167 return z;
168 default:
169 return thisObject;
170 }
171}
172
173int gJava_MyClass_fooSIOO_calls = 0;
174jobject Java_MyClass_fooSIOO(JNIEnv*, jclass klass, jint x, jobject y,
175 jobject z) {
176 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
177 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
178 gJava_MyClass_fooSIOO_calls++;
179 switch (x) {
180 case 1:
181 return y;
182 case 2:
183 return z;
184 default:
185 return klass;
186 }
187}
188
Ian Rogersdf20fe02011-07-20 20:34:16 -0700189int gJava_MyClass_fooSSIOO_calls = 0;
190jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
191 jobject z) {
192 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
193 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
194 gJava_MyClass_fooSSIOO_calls++;
195 switch (x) {
196 case 1:
197 return y;
198 case 2:
199 return z;
200 default:
201 return klass;
202 }
203}
204
Ian Rogersb033c752011-07-20 12:22:35 -0700205TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700206 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700207 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700208
Carl Shapiro7a909592011-07-24 19:21:59 -0700209 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700210 ASSERT_TRUE(klass != NULL);
211
212 Method* method = klass->FindVirtualMethod("foo", "()V");
213 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700214
215 Assembler jni_asm;
216 JniCompiler jni_compiler;
217 jni_compiler.Compile(&jni_asm, method);
218
219 // TODO: should really use JNIEnv to RegisterNative, but missing a
220 // complete story on this, so hack the RegisterNative below
221 // JNIEnv* env = Thread::Current()->GetJniEnv();
222 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
223 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
224
225 jvalue a;
226 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700227 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700228 RunMethod(method, a, a, a, a);
229 EXPECT_EQ(1, gJava_MyClass_foo_calls);
230 RunMethod(method, a, a, a, a);
231 EXPECT_EQ(2, gJava_MyClass_foo_calls);
232}
233
234TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700235 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700236 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700237
Carl Shapiro7a909592011-07-24 19:21:59 -0700238 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700239 ASSERT_TRUE(klass != NULL);
240
241 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
242 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700243
244 Assembler jni_asm;
245 JniCompiler jni_compiler;
246 jni_compiler.Compile(&jni_asm, method);
247
248 // TODO: should really use JNIEnv to RegisterNative, but missing a
249 // complete story on this, so hack the RegisterNative below
250 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
251
252 jvalue a, b, c;
253 a.l = (jobject)NULL;
254 b.i = 42;
255 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
256 c = RunMethod(method, a, b, a, a);
257 ASSERT_EQ(42, c.i);
258 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
259 b.i = 0xCAFED00D;
260 c = RunMethod(method, a, b, a, a);
261 ASSERT_EQ((jint)0xCAFED00D, c.i);
262 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
263}
264
265TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700266 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700267 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700268
Carl Shapiro7a909592011-07-24 19:21:59 -0700269 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700270 ASSERT_TRUE(klass != NULL);
271
272 Method* method = klass->FindVirtualMethod("fooII", "(II)I");
273 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700274
275 Assembler jni_asm;
276 JniCompiler jni_compiler;
277 jni_compiler.Compile(&jni_asm, method);
278
279 // TODO: should really use JNIEnv to RegisterNative, but missing a
280 // complete story on this, so hack the RegisterNative below
281 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
282
283 jvalue a, b, c, d;
284 a.l = (jobject)NULL;
285 b.i = 99;
286 c.i = 10;
287 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
288 d = RunMethod(method, a, b, c, a);
289 ASSERT_EQ(99 - 10, d.i);
290 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
291 b.i = 0xCAFEBABE;
292 c.i = 0xCAFED00D;
293 d = RunMethod(method, a, b, c, a);
294 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
295 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
296}
297
298
299TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700300 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700301 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700302
Carl Shapiro7a909592011-07-24 19:21:59 -0700303 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700304 ASSERT_TRUE(klass != NULL);
305
306 Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
307 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700308
309 Assembler jni_asm;
310 JniCompiler jni_compiler;
311 jni_compiler.Compile(&jni_asm, method);
312
313 // TODO: should really use JNIEnv to RegisterNative, but missing a
314 // complete story on this, so hack the RegisterNative below
315 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
316
317 jvalue a, b, c, d;
318 a.l = (jobject)NULL;
319 b.d = 99;
320 c.d = 10;
321 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
322 d = RunMethodD(method, a, b, c);
323 ASSERT_EQ(b.d - c.d, d.d);
324 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
325 b.d = 3.14159265358979323846;
326 c.d = 0.69314718055994530942;
327 d = RunMethodD(method, a, b, c);
328 ASSERT_EQ(b.d - c.d, d.d);
329 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
330}
331
332TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700333 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700334 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700335
Carl Shapiro7a909592011-07-24 19:21:59 -0700336 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700337 ASSERT_TRUE(klass != NULL);
338
339 Method* method = klass->FindVirtualMethod(
340 "fooIOO",
341 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
342 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700343
344 Assembler jni_asm;
345 JniCompiler jni_compiler;
346 jni_compiler.Compile(&jni_asm, method);
347
348 // TODO: should really use JNIEnv to RegisterNative, but missing a
349 // complete story on this, so hack the RegisterNative below
350 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
351
352 jvalue a, b, c, d, e;
353 a.l = (jobject)NULL;
354 b.i = 0;
355 c.l = (jobject)NULL;
356 d.l = (jobject)NULL;
357 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
358 e = RunMethod(method, a, b, c, d);
359 ASSERT_EQ((jobject)NULL, e.l);
360 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
361 a.l = (jobject)8;
362 b.i = 0;
363 c.l = (jobject)NULL;
364 d.l = (jobject)16;
365 e = RunMethod(method, a, b, c, d);
366 ASSERT_EQ((jobject)8, e.l);
367 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
368 b.i = 1;
369 e = RunMethod(method, a, b, c, d);
370 ASSERT_EQ((jobject)NULL, e.l);
371 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
372 b.i = 2;
373 e = RunMethod(method, a, b, c, d);
374 ASSERT_EQ((jobject)16, e.l);
375 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
376 a.l = (jobject)8;
377 b.i = 0;
378 c.l = (jobject)16;
379 d.l = (jobject)NULL;
380 e = RunMethod(method, a, b, c, d);
381 ASSERT_EQ((jobject)8, e.l);
382 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
383 b.i = 1;
384 e = RunMethod(method, a, b, c, d);
385 ASSERT_EQ((jobject)16, e.l);
386 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
387 b.i = 2;
388 e = RunMethod(method, a, b, c, d);
389 ASSERT_EQ((jobject)NULL, e.l);
390 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
391}
392
393TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700394 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700395 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700396
Carl Shapiro7a909592011-07-24 19:21:59 -0700397 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700398 ASSERT_TRUE(klass != NULL);
399
400 Method* method = klass->FindDirectMethod(
401 "fooSIOO",
402 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
403 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700404
405 Assembler jni_asm;
406 JniCompiler jni_compiler;
407 jni_compiler.Compile(&jni_asm, method);
408
409 // TODO: should really use JNIEnv to RegisterNative, but missing a
410 // complete story on this, so hack the RegisterNative below
411 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
412
413 jvalue a, b, c, d;
414 a.i = 0;
415 b.l = (jobject)NULL;
416 c.l = (jobject)NULL;
417 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
418 d = RunMethod(method, a, b, c, a);
419 ASSERT_EQ((jobject)method->GetClass(), d.l);
420 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
421 a.i = 0;
422 b.l = (jobject)NULL;
423 c.l = (jobject)16;
424 d = RunMethod(method, a, b, c, a);
425 ASSERT_EQ((jobject)method->GetClass(), d.l);
426 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
427 a.i = 1;
428 d = RunMethod(method, a, b, c, a);
429 ASSERT_EQ((jobject)NULL, d.l);
430 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
431 a.i = 2;
432 d = RunMethod(method, a, b, c, a);
433 ASSERT_EQ((jobject)16, d.l);
434 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
435 a.i = 0;
436 b.l = (jobject)16;
437 c.l = (jobject)NULL;
438 d = RunMethod(method, a, b, c, a);
439 ASSERT_EQ((jobject)method->GetClass(), d.l);
440 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
441 a.i = 1;
442 d = RunMethod(method, a, b, c, a);
443 ASSERT_EQ((jobject)16, d.l);
444 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
445 a.i = 2;
446 d = RunMethod(method, a, b, c, a);
447 ASSERT_EQ((jobject)NULL, d.l);
448 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
449}
450
Ian Rogersdf20fe02011-07-20 20:34:16 -0700451TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700452 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700453 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700454
Carl Shapiro7a909592011-07-24 19:21:59 -0700455 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700456 ASSERT_TRUE(klass != NULL);
457
458 Method* method = klass->FindDirectMethod(
459 "fooSSIOO",
460 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
461 ASSERT_TRUE(method != NULL);
Ian Rogersdf20fe02011-07-20 20:34:16 -0700462
463 Assembler jni_asm;
464 JniCompiler jni_compiler;
465 jni_compiler.Compile(&jni_asm, method);
466
467 // TODO: should really use JNIEnv to RegisterNative, but missing a
468 // complete story on this, so hack the RegisterNative below
469 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
470
471 jvalue a, b, c, d;
472 a.i = 0;
473 b.l = (jobject)NULL;
474 c.l = (jobject)NULL;
475 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
476 d = RunMethod(method, a, b, c, a);
477 ASSERT_EQ((jobject)method->GetClass(), d.l);
478 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
479 a.i = 0;
480 b.l = (jobject)NULL;
481 c.l = (jobject)16;
482 d = RunMethod(method, a, b, c, a);
483 ASSERT_EQ((jobject)method->GetClass(), d.l);
484 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
485 a.i = 1;
486 d = RunMethod(method, a, b, c, a);
487 ASSERT_EQ((jobject)NULL, d.l);
488 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
489 a.i = 2;
490 d = RunMethod(method, a, b, c, a);
491 ASSERT_EQ((jobject)16, d.l);
492 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
493 a.i = 0;
494 b.l = (jobject)16;
495 c.l = (jobject)NULL;
496 d = RunMethod(method, a, b, c, a);
497 ASSERT_EQ((jobject)method->GetClass(), d.l);
498 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
499 a.i = 1;
500 d = RunMethod(method, a, b, c, a);
501 ASSERT_EQ((jobject)16, d.l);
502 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
503 a.i = 2;
504 d = RunMethod(method, a, b, c, a);
505 ASSERT_EQ((jobject)NULL, d.l);
506 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
507}
508
Ian Rogers45a76cb2011-07-21 22:00:15 -0700509int gSuspendCounterHandler_calls;
510void SuspendCountHandler(Method** frame) {
Jesse Wilsonf7e85a52011-08-01 18:45:58 -0700511 EXPECT_PRED2(String::EqualsUtf8, (*frame)->GetName(), "fooI");
Ian Rogers45a76cb2011-07-21 22:00:15 -0700512 gSuspendCounterHandler_calls++;
513 Thread::Current()->DecrementSuspendCount();
514}
515TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700516 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700517 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700518
Carl Shapiro7a909592011-07-24 19:21:59 -0700519 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700520 ASSERT_TRUE(klass != NULL);
521
522 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
523 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700524
525 Assembler jni_asm;
526 JniCompiler jni_compiler;
527 jni_compiler.Compile(&jni_asm, method);
528
529 // TODO: should really use JNIEnv to RegisterNative, but missing a
530 // complete story on this, so hack the RegisterNative below
531 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
532 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
533
534 gSuspendCounterHandler_calls = 0;
535 gJava_MyClass_fooI_calls = 0;
536 jvalue a, b, c;
537 a.l = (jobject)NULL;
538 b.i = 42;
539 c = RunMethod(method, a, b, a, a);
540 ASSERT_EQ(42, c.i);
541 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
542 EXPECT_EQ(0, gSuspendCounterHandler_calls);
543 Thread::Current()->IncrementSuspendCount();
544 c = RunMethod(method, a, b, a, a);
545 ASSERT_EQ(42, c.i);
546 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
547 EXPECT_EQ(1, gSuspendCounterHandler_calls);
548 c = RunMethod(method, a, b, a, a);
549 ASSERT_EQ(42, c.i);
550 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
551 EXPECT_EQ(1, gSuspendCounterHandler_calls);
552}
553
554int gExceptionHandler_calls;
555void ExceptionHandler(Method** frame) {
Jesse Wilsonf7e85a52011-08-01 18:45:58 -0700556 EXPECT_PRED2(String::EqualsUtf8, (*frame)->GetName(), "foo");
Ian Rogers45a76cb2011-07-21 22:00:15 -0700557 gExceptionHandler_calls++;
558 Thread::Current()->ClearException();
559}
560TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700561 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700562 class_linker_->RegisterDexFile(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700563
Carl Shapiro7a909592011-07-24 19:21:59 -0700564 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700565 ASSERT_TRUE(klass != NULL);
566
567 Method* method = klass->FindVirtualMethod("foo", "()V");
568 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700569
570 Assembler jni_asm;
571 JniCompiler jni_compiler;
572 jni_compiler.Compile(&jni_asm, method);
573
574 // TODO: should really use JNIEnv to RegisterNative, but missing a
575 // complete story on this, so hack the RegisterNative below
576 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
577 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
578
579 gExceptionHandler_calls = 0;
580 gJava_MyClass_foo_calls = 0;
581 jvalue a;
582 a.l = (jobject)NULL;
583 RunMethod(method, a, a, a, a);
584 EXPECT_EQ(1, gJava_MyClass_foo_calls);
585 EXPECT_EQ(0, gExceptionHandler_calls);
586 // TODO: create a real exception here
587 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
588 RunMethod(method, a, a, a, a);
589 EXPECT_EQ(2, gJava_MyClass_foo_calls);
590 EXPECT_EQ(1, gExceptionHandler_calls);
591 RunMethod(method, a, a, a, a);
592 EXPECT_EQ(3, gJava_MyClass_foo_calls);
593 EXPECT_EQ(1, gExceptionHandler_calls);
594}
595
Ian Rogersb033c752011-07-20 12:22:35 -0700596} // namespace art