blob: 225ca5c6af9e9b92b2aa6316036c0fd425ef558b [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
22 thunk_code_size_ = 4096;
23 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
34 thk_asm.pushl(Address(ESP, 40)); // push pad or jlong high
35 thk_asm.pushl(Address(ESP, 40)); // push jint or jlong low
36 thk_asm.pushl(Address(ESP, 40)); // push jint or jlong high
37 thk_asm.pushl(Address(ESP, 40)); // push jint or jlong low
38 thk_asm.pushl(Address(ESP, 40)); // push jobject
39 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();
43#else
44 LOG(FATAL) << "Unimplemented";
45#endif
46 size_t cs = thk_asm.CodeSize();
47 MemoryRegion code(thunk_, cs);
48 thk_asm.FinalizeInstructions(code);
49 thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
50 jobject, jint, jint, jint)
51 >(code.pointer());
52 thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
53 jobject, jdouble, jdouble)
54 >(code.pointer());
55 }
56
57 virtual void TearDown() {
58 // Release thunk code
59 CHECK(runtime_->DetachCurrentThread());
60 CHECK_EQ(0, munmap(thunk_, thunk_code_size_));
61 }
62
63 // Run generated code associated with method passing and returning int size
64 // arguments
65 jvalue RunMethod(Method* method, jvalue a, jvalue b, jvalue c, jvalue d) {
66 jvalue result;
67 // sanity checks
68 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
69 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
70 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
71 // perform call
72 result.i = (*thunk_entry1_)(method->GetCode(), method, a.l, b.i, c.i, d.i);
73 // sanity check post-call
74 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
75 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
76 return result;
77 }
78
79 // Run generated code associated with method passing and returning double size
80 // arguments
81 jvalue RunMethodD(Method* method, jvalue a, jvalue b, jvalue c) {
82 jvalue result;
83 // sanity checks
84 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
85 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
86 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
87 // perform call
88 result.d = (*thunk_entry2_)(method->GetCode(), method, a.l, b.d, c.d);
89 // sanity check post-call
90 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
91 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
92 return result;
93 }
94
Ian Rogersb033c752011-07-20 12:22:35 -070095 void* thunk_;
96 size_t thunk_code_size_;
97 jint (*thunk_entry1_)(const void*, Method*, jobject, jint, jint, jint);
98 jdouble (*thunk_entry2_)(const void*, Method*, jobject, jdouble, jdouble);
99};
100
101int gJava_MyClass_foo_calls = 0;
102void Java_MyClass_foo(JNIEnv*, jobject) {
103 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
104 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
105 gJava_MyClass_foo_calls++;
106}
107
108int gJava_MyClass_fooI_calls = 0;
109jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
110 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
111 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
112 gJava_MyClass_fooI_calls++;
113 return x;
114}
115
116int gJava_MyClass_fooII_calls = 0;
117jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
118 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
119 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
120 gJava_MyClass_fooII_calls++;
121 return x - y; // non-commutative operator
122}
123
124int gJava_MyClass_fooDD_calls = 0;
125jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
126 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
127 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
128 gJava_MyClass_fooDD_calls++;
129 return x - y; // non-commutative operator
130}
131
132int gJava_MyClass_fooIOO_calls = 0;
133jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
134 jobject z) {
135 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
136 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
137 gJava_MyClass_fooIOO_calls++;
138 switch (x) {
139 case 1:
140 return y;
141 case 2:
142 return z;
143 default:
144 return thisObject;
145 }
146}
147
148int gJava_MyClass_fooSIOO_calls = 0;
149jobject Java_MyClass_fooSIOO(JNIEnv*, jclass klass, jint x, jobject y,
150 jobject z) {
151 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
152 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
153 gJava_MyClass_fooSIOO_calls++;
154 switch (x) {
155 case 1:
156 return y;
157 case 2:
158 return z;
159 default:
160 return klass;
161 }
162}
163
Ian Rogersdf20fe02011-07-20 20:34:16 -0700164int gJava_MyClass_fooSSIOO_calls = 0;
165jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
166 jobject z) {
167 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
168 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
169 gJava_MyClass_fooSSIOO_calls++;
170 switch (x) {
171 case 1:
172 return y;
173 case 2:
174 return z;
175 default:
176 return klass;
177 }
178}
179
Ian Rogersb033c752011-07-20 12:22:35 -0700180TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700181 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700182 class_linker_->RegisterDexFile(dex.get());
183 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700184 Method* method = klass->FindVirtualMethod("foo");
185
186 Assembler jni_asm;
187 JniCompiler jni_compiler;
188 jni_compiler.Compile(&jni_asm, method);
189
190 // TODO: should really use JNIEnv to RegisterNative, but missing a
191 // complete story on this, so hack the RegisterNative below
192 // JNIEnv* env = Thread::Current()->GetJniEnv();
193 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
194 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
195
196 jvalue a;
197 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700198 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700199 RunMethod(method, a, a, a, a);
200 EXPECT_EQ(1, gJava_MyClass_foo_calls);
201 RunMethod(method, a, a, a, a);
202 EXPECT_EQ(2, gJava_MyClass_foo_calls);
203}
204
205TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
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());
208 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700209 Method* method = klass->FindVirtualMethod("fooI");
210
211 Assembler jni_asm;
212 JniCompiler jni_compiler;
213 jni_compiler.Compile(&jni_asm, method);
214
215 // TODO: should really use JNIEnv to RegisterNative, but missing a
216 // complete story on this, so hack the RegisterNative below
217 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
218
219 jvalue a, b, c;
220 a.l = (jobject)NULL;
221 b.i = 42;
222 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
223 c = RunMethod(method, a, b, a, a);
224 ASSERT_EQ(42, c.i);
225 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
226 b.i = 0xCAFED00D;
227 c = RunMethod(method, a, b, a, a);
228 ASSERT_EQ((jint)0xCAFED00D, c.i);
229 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
230}
231
232TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700233 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700234 class_linker_->RegisterDexFile(dex.get());
235 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700236 Method* method = klass->FindVirtualMethod("fooII");
237
238 Assembler jni_asm;
239 JniCompiler jni_compiler;
240 jni_compiler.Compile(&jni_asm, method);
241
242 // TODO: should really use JNIEnv to RegisterNative, but missing a
243 // complete story on this, so hack the RegisterNative below
244 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
245
246 jvalue a, b, c, d;
247 a.l = (jobject)NULL;
248 b.i = 99;
249 c.i = 10;
250 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
251 d = RunMethod(method, a, b, c, a);
252 ASSERT_EQ(99 - 10, d.i);
253 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
254 b.i = 0xCAFEBABE;
255 c.i = 0xCAFED00D;
256 d = RunMethod(method, a, b, c, a);
257 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
258 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
259}
260
261
262TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700263 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700264 class_linker_->RegisterDexFile(dex.get());
265 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700266 Method* method = klass->FindVirtualMethod("fooDD");
267
268 Assembler jni_asm;
269 JniCompiler jni_compiler;
270 jni_compiler.Compile(&jni_asm, method);
271
272 // TODO: should really use JNIEnv to RegisterNative, but missing a
273 // complete story on this, so hack the RegisterNative below
274 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
275
276 jvalue a, b, c, d;
277 a.l = (jobject)NULL;
278 b.d = 99;
279 c.d = 10;
280 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
281 d = RunMethodD(method, a, b, c);
282 ASSERT_EQ(b.d - c.d, d.d);
283 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
284 b.d = 3.14159265358979323846;
285 c.d = 0.69314718055994530942;
286 d = RunMethodD(method, a, b, c);
287 ASSERT_EQ(b.d - c.d, d.d);
288 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
289}
290
291TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700292 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700293 class_linker_->RegisterDexFile(dex.get());
294 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700295 Method* method = klass->FindVirtualMethod("fooIOO");
296
297 Assembler jni_asm;
298 JniCompiler jni_compiler;
299 jni_compiler.Compile(&jni_asm, method);
300
301 // TODO: should really use JNIEnv to RegisterNative, but missing a
302 // complete story on this, so hack the RegisterNative below
303 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
304
305 jvalue a, b, c, d, e;
306 a.l = (jobject)NULL;
307 b.i = 0;
308 c.l = (jobject)NULL;
309 d.l = (jobject)NULL;
310 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
311 e = RunMethod(method, a, b, c, d);
312 ASSERT_EQ((jobject)NULL, e.l);
313 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
314 a.l = (jobject)8;
315 b.i = 0;
316 c.l = (jobject)NULL;
317 d.l = (jobject)16;
318 e = RunMethod(method, a, b, c, d);
319 ASSERT_EQ((jobject)8, e.l);
320 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
321 b.i = 1;
322 e = RunMethod(method, a, b, c, d);
323 ASSERT_EQ((jobject)NULL, e.l);
324 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
325 b.i = 2;
326 e = RunMethod(method, a, b, c, d);
327 ASSERT_EQ((jobject)16, e.l);
328 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
329 a.l = (jobject)8;
330 b.i = 0;
331 c.l = (jobject)16;
332 d.l = (jobject)NULL;
333 e = RunMethod(method, a, b, c, d);
334 ASSERT_EQ((jobject)8, e.l);
335 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
336 b.i = 1;
337 e = RunMethod(method, a, b, c, d);
338 ASSERT_EQ((jobject)16, e.l);
339 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
340 b.i = 2;
341 e = RunMethod(method, a, b, c, d);
342 ASSERT_EQ((jobject)NULL, e.l);
343 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
344}
345
346TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700347 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700348 class_linker_->RegisterDexFile(dex.get());
349 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700350 Method* method = klass->FindDirectMethod("fooSIOO");
351
352 Assembler jni_asm;
353 JniCompiler jni_compiler;
354 jni_compiler.Compile(&jni_asm, method);
355
356 // TODO: should really use JNIEnv to RegisterNative, but missing a
357 // complete story on this, so hack the RegisterNative below
358 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
359
360 jvalue a, b, c, d;
361 a.i = 0;
362 b.l = (jobject)NULL;
363 c.l = (jobject)NULL;
364 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
365 d = RunMethod(method, a, b, c, a);
366 ASSERT_EQ((jobject)method->GetClass(), d.l);
367 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
368 a.i = 0;
369 b.l = (jobject)NULL;
370 c.l = (jobject)16;
371 d = RunMethod(method, a, b, c, a);
372 ASSERT_EQ((jobject)method->GetClass(), d.l);
373 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
374 a.i = 1;
375 d = RunMethod(method, a, b, c, a);
376 ASSERT_EQ((jobject)NULL, d.l);
377 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
378 a.i = 2;
379 d = RunMethod(method, a, b, c, a);
380 ASSERT_EQ((jobject)16, d.l);
381 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
382 a.i = 0;
383 b.l = (jobject)16;
384 c.l = (jobject)NULL;
385 d = RunMethod(method, a, b, c, a);
386 ASSERT_EQ((jobject)method->GetClass(), d.l);
387 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
388 a.i = 1;
389 d = RunMethod(method, a, b, c, a);
390 ASSERT_EQ((jobject)16, d.l);
391 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
392 a.i = 2;
393 d = RunMethod(method, a, b, c, a);
394 ASSERT_EQ((jobject)NULL, d.l);
395 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
396}
397
Ian Rogersdf20fe02011-07-20 20:34:16 -0700398TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700399 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700400 class_linker_->RegisterDexFile(dex.get());
401 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersdf20fe02011-07-20 20:34:16 -0700402 Method* method = klass->FindDirectMethod("fooSSIOO");
403
404 Assembler jni_asm;
405 JniCompiler jni_compiler;
406 jni_compiler.Compile(&jni_asm, method);
407
408 // TODO: should really use JNIEnv to RegisterNative, but missing a
409 // complete story on this, so hack the RegisterNative below
410 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
411
412 jvalue a, b, c, d;
413 a.i = 0;
414 b.l = (jobject)NULL;
415 c.l = (jobject)NULL;
416 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
417 d = RunMethod(method, a, b, c, a);
418 ASSERT_EQ((jobject)method->GetClass(), d.l);
419 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
420 a.i = 0;
421 b.l = (jobject)NULL;
422 c.l = (jobject)16;
423 d = RunMethod(method, a, b, c, a);
424 ASSERT_EQ((jobject)method->GetClass(), d.l);
425 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
426 a.i = 1;
427 d = RunMethod(method, a, b, c, a);
428 ASSERT_EQ((jobject)NULL, d.l);
429 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
430 a.i = 2;
431 d = RunMethod(method, a, b, c, a);
432 ASSERT_EQ((jobject)16, d.l);
433 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
434 a.i = 0;
435 b.l = (jobject)16;
436 c.l = (jobject)NULL;
437 d = RunMethod(method, a, b, c, a);
438 ASSERT_EQ((jobject)method->GetClass(), d.l);
439 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
440 a.i = 1;
441 d = RunMethod(method, a, b, c, a);
442 ASSERT_EQ((jobject)16, d.l);
443 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
444 a.i = 2;
445 d = RunMethod(method, a, b, c, a);
446 ASSERT_EQ((jobject)NULL, d.l);
447 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
448}
449
Ian Rogers45a76cb2011-07-21 22:00:15 -0700450int gSuspendCounterHandler_calls;
451void SuspendCountHandler(Method** frame) {
452 EXPECT_EQ(0, (*frame)->GetName().compare("fooI"));
453 gSuspendCounterHandler_calls++;
454 Thread::Current()->DecrementSuspendCount();
455}
456TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700457 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700458 class_linker_->RegisterDexFile(dex.get());
459 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogers45a76cb2011-07-21 22:00:15 -0700460 Method* method = klass->FindVirtualMethod("fooI");
461
462 Assembler jni_asm;
463 JniCompiler jni_compiler;
464 jni_compiler.Compile(&jni_asm, method);
465
466 // TODO: should really use JNIEnv to RegisterNative, but missing a
467 // complete story on this, so hack the RegisterNative below
468 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
469 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
470
471 gSuspendCounterHandler_calls = 0;
472 gJava_MyClass_fooI_calls = 0;
473 jvalue a, b, c;
474 a.l = (jobject)NULL;
475 b.i = 42;
476 c = RunMethod(method, a, b, a, a);
477 ASSERT_EQ(42, c.i);
478 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
479 EXPECT_EQ(0, gSuspendCounterHandler_calls);
480 Thread::Current()->IncrementSuspendCount();
481 c = RunMethod(method, a, b, a, a);
482 ASSERT_EQ(42, c.i);
483 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
484 EXPECT_EQ(1, gSuspendCounterHandler_calls);
485 c = RunMethod(method, a, b, a, a);
486 ASSERT_EQ(42, c.i);
487 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
488 EXPECT_EQ(1, gSuspendCounterHandler_calls);
489}
490
491int gExceptionHandler_calls;
492void ExceptionHandler(Method** frame) {
493 EXPECT_EQ(0, (*frame)->GetName().compare("foo"));
494 gExceptionHandler_calls++;
495 Thread::Current()->ClearException();
496}
497TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700498 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700499 class_linker_->RegisterDexFile(dex.get());
500 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogers45a76cb2011-07-21 22:00:15 -0700501 Method* method = klass->FindVirtualMethod("foo");
502
503 Assembler jni_asm;
504 JniCompiler jni_compiler;
505 jni_compiler.Compile(&jni_asm, method);
506
507 // TODO: should really use JNIEnv to RegisterNative, but missing a
508 // complete story on this, so hack the RegisterNative below
509 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
510 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
511
512 gExceptionHandler_calls = 0;
513 gJava_MyClass_foo_calls = 0;
514 jvalue a;
515 a.l = (jobject)NULL;
516 RunMethod(method, a, a, a, a);
517 EXPECT_EQ(1, gJava_MyClass_foo_calls);
518 EXPECT_EQ(0, gExceptionHandler_calls);
519 // TODO: create a real exception here
520 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
521 RunMethod(method, a, a, a, a);
522 EXPECT_EQ(2, gJava_MyClass_foo_calls);
523 EXPECT_EQ(1, gExceptionHandler_calls);
524 RunMethod(method, a, a, a, a);
525 EXPECT_EQ(3, gJava_MyClass_foo_calls);
526 EXPECT_EQ(1, gExceptionHandler_calls);
527}
528
Ian Rogersb033c752011-07-20 12:22:35 -0700529} // namespace art