blob: c7af269fe0b6271aab9a5e7260602f5398b4b92e [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 runtime and attach thread
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070022 std::vector<RawDexFile*> boot_class_path;
23 boot_class_path.push_back(java_lang_raw_dex_file_.get());
24 runtime_ = Runtime::Create(boot_class_path);
Ian Rogersb033c752011-07-20 12:22:35 -070025 CHECK(runtime_->AttachCurrentThread());
26 // Create thunk code that performs the native to managed transition
27 thunk_code_size_ = 4096;
28 thunk_ = mmap(NULL, thunk_code_size_, PROT_READ | PROT_WRITE | PROT_EXEC,
29 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
30 CHECK_NE(MAP_FAILED, thunk_);
31 Assembler thk_asm;
32 // TODO: shouldn't have machine specific code in a general purpose file
33#if defined(__i386__)
34 thk_asm.pushl(EDI); // preserve EDI
35 thk_asm.movl(EAX, Address(ESP, 8)); // EAX = method->GetCode()
36 thk_asm.movl(EDI, Address(ESP, 12)); // EDI = method
37 thk_asm.pushl(Immediate(0)); // push pad
38 thk_asm.pushl(Immediate(0)); // push pad
39 thk_asm.pushl(Address(ESP, 40)); // push pad or jlong high
40 thk_asm.pushl(Address(ESP, 40)); // push jint or jlong low
41 thk_asm.pushl(Address(ESP, 40)); // push jint or jlong high
42 thk_asm.pushl(Address(ESP, 40)); // push jint or jlong low
43 thk_asm.pushl(Address(ESP, 40)); // push jobject
44 thk_asm.call(EAX); // Continue in method->GetCode()
45 thk_asm.addl(ESP, Immediate(28)); // pop arguments
46 thk_asm.popl(EDI); // restore EDI
47 thk_asm.ret();
48#else
49 LOG(FATAL) << "Unimplemented";
50#endif
51 size_t cs = thk_asm.CodeSize();
52 MemoryRegion code(thunk_, cs);
53 thk_asm.FinalizeInstructions(code);
54 thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
55 jobject, jint, jint, jint)
56 >(code.pointer());
57 thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
58 jobject, jdouble, jdouble)
59 >(code.pointer());
60 }
61
62 virtual void TearDown() {
63 // Release thunk code
64 CHECK(runtime_->DetachCurrentThread());
65 CHECK_EQ(0, munmap(thunk_, thunk_code_size_));
66 }
67
68 // Run generated code associated with method passing and returning int size
69 // arguments
70 jvalue RunMethod(Method* method, jvalue a, jvalue b, jvalue c, jvalue d) {
71 jvalue result;
72 // sanity checks
73 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
74 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
75 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
76 // perform call
77 result.i = (*thunk_entry1_)(method->GetCode(), method, a.l, b.i, c.i, d.i);
78 // sanity check post-call
79 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
80 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
81 return result;
82 }
83
84 // Run generated code associated with method passing and returning double size
85 // arguments
86 jvalue RunMethodD(Method* method, jvalue a, jvalue b, jvalue c) {
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
93 result.d = (*thunk_entry2_)(method->GetCode(), method, a.l, b.d, c.d);
94 // sanity check post-call
95 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
96 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
97 return result;
98 }
99
100 Runtime* runtime_;
101 void* thunk_;
102 size_t thunk_code_size_;
103 jint (*thunk_entry1_)(const void*, Method*, jobject, jint, jint, jint);
104 jdouble (*thunk_entry2_)(const void*, Method*, jobject, jdouble, jdouble);
105};
106
107int gJava_MyClass_foo_calls = 0;
108void Java_MyClass_foo(JNIEnv*, jobject) {
109 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
110 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
111 gJava_MyClass_foo_calls++;
112}
113
114int gJava_MyClass_fooI_calls = 0;
115jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
116 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
117 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
118 gJava_MyClass_fooI_calls++;
119 return x;
120}
121
122int gJava_MyClass_fooII_calls = 0;
123jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
124 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
125 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
126 gJava_MyClass_fooII_calls++;
127 return x - y; // non-commutative operator
128}
129
130int gJava_MyClass_fooDD_calls = 0;
131jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
132 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
133 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
134 gJava_MyClass_fooDD_calls++;
135 return x - y; // non-commutative operator
136}
137
138int gJava_MyClass_fooIOO_calls = 0;
139jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
140 jobject z) {
141 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
142 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
143 gJava_MyClass_fooIOO_calls++;
144 switch (x) {
145 case 1:
146 return y;
147 case 2:
148 return z;
149 default:
150 return thisObject;
151 }
152}
153
154int gJava_MyClass_fooSIOO_calls = 0;
155jobject Java_MyClass_fooSIOO(JNIEnv*, jclass klass, jint x, jobject y,
156 jobject z) {
157 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
158 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
159 gJava_MyClass_fooSIOO_calls++;
160 switch (x) {
161 case 1:
162 return y;
163 case 2:
164 return z;
165 default:
166 return klass;
167 }
168}
169
Ian Rogersdf20fe02011-07-20 20:34:16 -0700170int gJava_MyClass_fooSSIOO_calls = 0;
171jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
172 jobject z) {
173 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
174 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
175 gJava_MyClass_fooSSIOO_calls++;
176 switch (x) {
177 case 1:
178 return y;
179 case 2:
180 return z;
181 default:
182 return klass;
183 }
184}
185
Ian Rogersb033c752011-07-20 12:22:35 -0700186TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700187 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
188 class_linker_.get()->RegisterDexFile(dex.get());
189 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700190 Method* method = klass->FindVirtualMethod("foo");
191
192 Assembler jni_asm;
193 JniCompiler jni_compiler;
194 jni_compiler.Compile(&jni_asm, method);
195
196 // TODO: should really use JNIEnv to RegisterNative, but missing a
197 // complete story on this, so hack the RegisterNative below
198 // JNIEnv* env = Thread::Current()->GetJniEnv();
199 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
200 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
201
202 jvalue a;
203 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700204 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700205 RunMethod(method, a, a, a, a);
206 EXPECT_EQ(1, gJava_MyClass_foo_calls);
207 RunMethod(method, a, a, a, a);
208 EXPECT_EQ(2, gJava_MyClass_foo_calls);
209}
210
211TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700212 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
213 class_linker_.get()->RegisterDexFile(dex.get());
214 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700215 Method* method = klass->FindVirtualMethod("fooI");
216
217 Assembler jni_asm;
218 JniCompiler jni_compiler;
219 jni_compiler.Compile(&jni_asm, method);
220
221 // TODO: should really use JNIEnv to RegisterNative, but missing a
222 // complete story on this, so hack the RegisterNative below
223 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
224
225 jvalue a, b, c;
226 a.l = (jobject)NULL;
227 b.i = 42;
228 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
229 c = RunMethod(method, a, b, a, a);
230 ASSERT_EQ(42, c.i);
231 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
232 b.i = 0xCAFED00D;
233 c = RunMethod(method, a, b, a, a);
234 ASSERT_EQ((jint)0xCAFED00D, c.i);
235 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
236}
237
238TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700239 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
240 class_linker_.get()->RegisterDexFile(dex.get());
241 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700242 Method* method = klass->FindVirtualMethod("fooII");
243
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_fooII));
251
252 jvalue a, b, c, d;
253 a.l = (jobject)NULL;
254 b.i = 99;
255 c.i = 10;
256 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
257 d = RunMethod(method, a, b, c, a);
258 ASSERT_EQ(99 - 10, d.i);
259 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
260 b.i = 0xCAFEBABE;
261 c.i = 0xCAFED00D;
262 d = RunMethod(method, a, b, c, a);
263 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
264 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
265}
266
267
268TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700269 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
270 class_linker_.get()->RegisterDexFile(dex.get());
271 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700272 Method* method = klass->FindVirtualMethod("fooDD");
273
274 Assembler jni_asm;
275 JniCompiler jni_compiler;
276 jni_compiler.Compile(&jni_asm, method);
277
278 // TODO: should really use JNIEnv to RegisterNative, but missing a
279 // complete story on this, so hack the RegisterNative below
280 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
281
282 jvalue a, b, c, d;
283 a.l = (jobject)NULL;
284 b.d = 99;
285 c.d = 10;
286 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
287 d = RunMethodD(method, a, b, c);
288 ASSERT_EQ(b.d - c.d, d.d);
289 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
290 b.d = 3.14159265358979323846;
291 c.d = 0.69314718055994530942;
292 d = RunMethodD(method, a, b, c);
293 ASSERT_EQ(b.d - c.d, d.d);
294 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
295}
296
297TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700298 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
299 class_linker_.get()->RegisterDexFile(dex.get());
300 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700301 Method* method = klass->FindVirtualMethod("fooIOO");
302
303 Assembler jni_asm;
304 JniCompiler jni_compiler;
305 jni_compiler.Compile(&jni_asm, method);
306
307 // TODO: should really use JNIEnv to RegisterNative, but missing a
308 // complete story on this, so hack the RegisterNative below
309 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
310
311 jvalue a, b, c, d, e;
312 a.l = (jobject)NULL;
313 b.i = 0;
314 c.l = (jobject)NULL;
315 d.l = (jobject)NULL;
316 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
317 e = RunMethod(method, a, b, c, d);
318 ASSERT_EQ((jobject)NULL, e.l);
319 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
320 a.l = (jobject)8;
321 b.i = 0;
322 c.l = (jobject)NULL;
323 d.l = (jobject)16;
324 e = RunMethod(method, a, b, c, d);
325 ASSERT_EQ((jobject)8, e.l);
326 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
327 b.i = 1;
328 e = RunMethod(method, a, b, c, d);
329 ASSERT_EQ((jobject)NULL, e.l);
330 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
331 b.i = 2;
332 e = RunMethod(method, a, b, c, d);
333 ASSERT_EQ((jobject)16, e.l);
334 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
335 a.l = (jobject)8;
336 b.i = 0;
337 c.l = (jobject)16;
338 d.l = (jobject)NULL;
339 e = RunMethod(method, a, b, c, d);
340 ASSERT_EQ((jobject)8, e.l);
341 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
342 b.i = 1;
343 e = RunMethod(method, a, b, c, d);
344 ASSERT_EQ((jobject)16, e.l);
345 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
346 b.i = 2;
347 e = RunMethod(method, a, b, c, d);
348 ASSERT_EQ((jobject)NULL, e.l);
349 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
350}
351
352TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700353 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
354 class_linker_.get()->RegisterDexFile(dex.get());
355 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700356 Method* method = klass->FindDirectMethod("fooSIOO");
357
358 Assembler jni_asm;
359 JniCompiler jni_compiler;
360 jni_compiler.Compile(&jni_asm, method);
361
362 // TODO: should really use JNIEnv to RegisterNative, but missing a
363 // complete story on this, so hack the RegisterNative below
364 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
365
366 jvalue a, b, c, d;
367 a.i = 0;
368 b.l = (jobject)NULL;
369 c.l = (jobject)NULL;
370 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
371 d = RunMethod(method, a, b, c, a);
372 ASSERT_EQ((jobject)method->GetClass(), d.l);
373 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
374 a.i = 0;
375 b.l = (jobject)NULL;
376 c.l = (jobject)16;
377 d = RunMethod(method, a, b, c, a);
378 ASSERT_EQ((jobject)method->GetClass(), d.l);
379 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
380 a.i = 1;
381 d = RunMethod(method, a, b, c, a);
382 ASSERT_EQ((jobject)NULL, d.l);
383 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
384 a.i = 2;
385 d = RunMethod(method, a, b, c, a);
386 ASSERT_EQ((jobject)16, d.l);
387 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
388 a.i = 0;
389 b.l = (jobject)16;
390 c.l = (jobject)NULL;
391 d = RunMethod(method, a, b, c, a);
392 ASSERT_EQ((jobject)method->GetClass(), d.l);
393 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
394 a.i = 1;
395 d = RunMethod(method, a, b, c, a);
396 ASSERT_EQ((jobject)16, d.l);
397 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
398 a.i = 2;
399 d = RunMethod(method, a, b, c, a);
400 ASSERT_EQ((jobject)NULL, d.l);
401 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
402}
403
Ian Rogersdf20fe02011-07-20 20:34:16 -0700404TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700405 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
406 class_linker_.get()->RegisterDexFile(dex.get());
407 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersdf20fe02011-07-20 20:34:16 -0700408 Method* method = klass->FindDirectMethod("fooSSIOO");
409
410 Assembler jni_asm;
411 JniCompiler jni_compiler;
412 jni_compiler.Compile(&jni_asm, method);
413
414 // TODO: should really use JNIEnv to RegisterNative, but missing a
415 // complete story on this, so hack the RegisterNative below
416 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
417
418 jvalue a, b, c, d;
419 a.i = 0;
420 b.l = (jobject)NULL;
421 c.l = (jobject)NULL;
422 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
423 d = RunMethod(method, a, b, c, a);
424 ASSERT_EQ((jobject)method->GetClass(), d.l);
425 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
426 a.i = 0;
427 b.l = (jobject)NULL;
428 c.l = (jobject)16;
429 d = RunMethod(method, a, b, c, a);
430 ASSERT_EQ((jobject)method->GetClass(), d.l);
431 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
432 a.i = 1;
433 d = RunMethod(method, a, b, c, a);
434 ASSERT_EQ((jobject)NULL, d.l);
435 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
436 a.i = 2;
437 d = RunMethod(method, a, b, c, a);
438 ASSERT_EQ((jobject)16, d.l);
439 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
440 a.i = 0;
441 b.l = (jobject)16;
442 c.l = (jobject)NULL;
443 d = RunMethod(method, a, b, c, a);
444 ASSERT_EQ((jobject)method->GetClass(), d.l);
445 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
446 a.i = 1;
447 d = RunMethod(method, a, b, c, a);
448 ASSERT_EQ((jobject)16, d.l);
449 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
450 a.i = 2;
451 d = RunMethod(method, a, b, c, a);
452 ASSERT_EQ((jobject)NULL, d.l);
453 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
454}
455
Ian Rogers45a76cb2011-07-21 22:00:15 -0700456int gSuspendCounterHandler_calls;
457void SuspendCountHandler(Method** frame) {
458 EXPECT_EQ(0, (*frame)->GetName().compare("fooI"));
459 gSuspendCounterHandler_calls++;
460 Thread::Current()->DecrementSuspendCount();
461}
462TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700463 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
464 class_linker_.get()->RegisterDexFile(dex.get());
465 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogers45a76cb2011-07-21 22:00:15 -0700466 Method* method = klass->FindVirtualMethod("fooI");
467
468 Assembler jni_asm;
469 JniCompiler jni_compiler;
470 jni_compiler.Compile(&jni_asm, method);
471
472 // TODO: should really use JNIEnv to RegisterNative, but missing a
473 // complete story on this, so hack the RegisterNative below
474 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
475 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
476
477 gSuspendCounterHandler_calls = 0;
478 gJava_MyClass_fooI_calls = 0;
479 jvalue a, b, c;
480 a.l = (jobject)NULL;
481 b.i = 42;
482 c = RunMethod(method, a, b, a, a);
483 ASSERT_EQ(42, c.i);
484 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
485 EXPECT_EQ(0, gSuspendCounterHandler_calls);
486 Thread::Current()->IncrementSuspendCount();
487 c = RunMethod(method, a, b, a, a);
488 ASSERT_EQ(42, c.i);
489 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
490 EXPECT_EQ(1, gSuspendCounterHandler_calls);
491 c = RunMethod(method, a, b, a, a);
492 ASSERT_EQ(42, c.i);
493 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
494 EXPECT_EQ(1, gSuspendCounterHandler_calls);
495}
496
497int gExceptionHandler_calls;
498void ExceptionHandler(Method** frame) {
499 EXPECT_EQ(0, (*frame)->GetName().compare("foo"));
500 gExceptionHandler_calls++;
501 Thread::Current()->ClearException();
502}
503TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -0700504 scoped_ptr<RawDexFile> dex(OpenRawDexFileBase64(kMyClassNativesDex));
505 class_linker_.get()->RegisterDexFile(dex.get());
506 Class* klass = class_linker_.get()->FindClass("LMyClass;", NULL, dex.get());
Ian Rogers45a76cb2011-07-21 22:00:15 -0700507 Method* method = klass->FindVirtualMethod("foo");
508
509 Assembler jni_asm;
510 JniCompiler jni_compiler;
511 jni_compiler.Compile(&jni_asm, method);
512
513 // TODO: should really use JNIEnv to RegisterNative, but missing a
514 // complete story on this, so hack the RegisterNative below
515 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
516 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
517
518 gExceptionHandler_calls = 0;
519 gJava_MyClass_foo_calls = 0;
520 jvalue a;
521 a.l = (jobject)NULL;
522 RunMethod(method, a, a, a, a);
523 EXPECT_EQ(1, gJava_MyClass_foo_calls);
524 EXPECT_EQ(0, gExceptionHandler_calls);
525 // TODO: create a real exception here
526 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
527 RunMethod(method, a, a, a, a);
528 EXPECT_EQ(2, gJava_MyClass_foo_calls);
529 EXPECT_EQ(1, gExceptionHandler_calls);
530 RunMethod(method, a, a, a, a);
531 EXPECT_EQ(3, gJava_MyClass_foo_calls);
532 EXPECT_EQ(1, gExceptionHandler_calls);
533}
534
Ian Rogersb033c752011-07-20 12:22:35 -0700535} // namespace art