blob: cfedb8589dabdfb81fa93889f7a6df92fd4e8375 [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;
Elliott Hughes330304d2011-08-12 14:28:05 -0700174jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
Ian Rogersb033c752011-07-20 12:22:35 -0700175 jobject z) {
Elliott Hughes330304d2011-08-12 14:28:05 -0700176 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
Ian Rogersb033c752011-07-20 12:22:35 -0700177 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
178 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
179 gJava_MyClass_fooSIOO_calls++;
180 switch (x) {
181 case 1:
182 return y;
183 case 2:
184 return z;
185 default:
186 return klass;
187 }
188}
189
Ian Rogersdf20fe02011-07-20 20:34:16 -0700190int gJava_MyClass_fooSSIOO_calls = 0;
191jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
192 jobject z) {
193 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
194 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
195 gJava_MyClass_fooSSIOO_calls++;
196 switch (x) {
197 case 1:
198 return y;
199 case 2:
200 return z;
201 default:
202 return klass;
203 }
204}
205
Ian Rogersb033c752011-07-20 12:22:35 -0700206TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700207 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700208 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700209
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700210 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700211 ASSERT_TRUE(klass != NULL);
212
213 Method* method = klass->FindVirtualMethod("foo", "()V");
214 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700215
216 Assembler jni_asm;
217 JniCompiler jni_compiler;
218 jni_compiler.Compile(&jni_asm, method);
219
220 // TODO: should really use JNIEnv to RegisterNative, but missing a
221 // complete story on this, so hack the RegisterNative below
222 // JNIEnv* env = Thread::Current()->GetJniEnv();
223 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
224 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
225
226 jvalue a;
227 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700228 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700229 RunMethod(method, a, a, a, a);
230 EXPECT_EQ(1, gJava_MyClass_foo_calls);
231 RunMethod(method, a, a, a, a);
232 EXPECT_EQ(2, gJava_MyClass_foo_calls);
233}
234
235TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700236 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700237 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700238
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700239 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700240 ASSERT_TRUE(klass != NULL);
241
242 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
243 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700244
245 Assembler jni_asm;
246 JniCompiler jni_compiler;
247 jni_compiler.Compile(&jni_asm, method);
248
249 // TODO: should really use JNIEnv to RegisterNative, but missing a
250 // complete story on this, so hack the RegisterNative below
251 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
252
253 jvalue a, b, c;
254 a.l = (jobject)NULL;
255 b.i = 42;
256 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
257 c = RunMethod(method, a, b, a, a);
258 ASSERT_EQ(42, c.i);
259 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
260 b.i = 0xCAFED00D;
261 c = RunMethod(method, a, b, a, a);
262 ASSERT_EQ((jint)0xCAFED00D, c.i);
263 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
264}
265
266TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700267 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700268 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700269
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700270 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700271 ASSERT_TRUE(klass != NULL);
272
273 Method* method = klass->FindVirtualMethod("fooII", "(II)I");
274 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700275
276 Assembler jni_asm;
277 JniCompiler jni_compiler;
278 jni_compiler.Compile(&jni_asm, method);
279
280 // TODO: should really use JNIEnv to RegisterNative, but missing a
281 // complete story on this, so hack the RegisterNative below
282 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
283
284 jvalue a, b, c, d;
285 a.l = (jobject)NULL;
286 b.i = 99;
287 c.i = 10;
288 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
289 d = RunMethod(method, a, b, c, a);
290 ASSERT_EQ(99 - 10, d.i);
291 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
292 b.i = 0xCAFEBABE;
293 c.i = 0xCAFED00D;
294 d = RunMethod(method, a, b, c, a);
295 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
296 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
297}
298
299
300TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700301 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700302 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700303
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700304 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700305 ASSERT_TRUE(klass != NULL);
306
307 Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
308 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700309
310 Assembler jni_asm;
311 JniCompiler jni_compiler;
312 jni_compiler.Compile(&jni_asm, method);
313
314 // TODO: should really use JNIEnv to RegisterNative, but missing a
315 // complete story on this, so hack the RegisterNative below
316 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
317
318 jvalue a, b, c, d;
319 a.l = (jobject)NULL;
320 b.d = 99;
321 c.d = 10;
322 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
323 d = RunMethodD(method, a, b, c);
324 ASSERT_EQ(b.d - c.d, d.d);
325 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
326 b.d = 3.14159265358979323846;
327 c.d = 0.69314718055994530942;
328 d = RunMethodD(method, a, b, c);
329 ASSERT_EQ(b.d - c.d, d.d);
330 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
331}
332
333TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700334 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700335 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700336
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700337 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700338 ASSERT_TRUE(klass != NULL);
339
340 Method* method = klass->FindVirtualMethod(
341 "fooIOO",
342 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
343 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700344
345 Assembler jni_asm;
346 JniCompiler jni_compiler;
347 jni_compiler.Compile(&jni_asm, method);
348
349 // TODO: should really use JNIEnv to RegisterNative, but missing a
350 // complete story on this, so hack the RegisterNative below
351 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
352
353 jvalue a, b, c, d, e;
354 a.l = (jobject)NULL;
355 b.i = 0;
356 c.l = (jobject)NULL;
357 d.l = (jobject)NULL;
358 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
359 e = RunMethod(method, a, b, c, d);
360 ASSERT_EQ((jobject)NULL, e.l);
361 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
362 a.l = (jobject)8;
363 b.i = 0;
364 c.l = (jobject)NULL;
365 d.l = (jobject)16;
366 e = RunMethod(method, a, b, c, d);
367 ASSERT_EQ((jobject)8, e.l);
368 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
369 b.i = 1;
370 e = RunMethod(method, a, b, c, d);
371 ASSERT_EQ((jobject)NULL, e.l);
372 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
373 b.i = 2;
374 e = RunMethod(method, a, b, c, d);
375 ASSERT_EQ((jobject)16, e.l);
376 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
377 a.l = (jobject)8;
378 b.i = 0;
379 c.l = (jobject)16;
380 d.l = (jobject)NULL;
381 e = RunMethod(method, a, b, c, d);
382 ASSERT_EQ((jobject)8, e.l);
383 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
384 b.i = 1;
385 e = RunMethod(method, a, b, c, d);
386 ASSERT_EQ((jobject)16, e.l);
387 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
388 b.i = 2;
389 e = RunMethod(method, a, b, c, d);
390 ASSERT_EQ((jobject)NULL, e.l);
391 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
392}
393
394TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700395 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700396 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700397
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700398 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700399 ASSERT_TRUE(klass != NULL);
400
401 Method* method = klass->FindDirectMethod(
402 "fooSIOO",
403 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
404 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700405
406 Assembler jni_asm;
407 JniCompiler jni_compiler;
408 jni_compiler.Compile(&jni_asm, method);
409
410 // TODO: should really use JNIEnv to RegisterNative, but missing a
411 // complete story on this, so hack the RegisterNative below
412 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
413
414 jvalue a, b, c, d;
415 a.i = 0;
416 b.l = (jobject)NULL;
417 c.l = (jobject)NULL;
418 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
419 d = RunMethod(method, a, b, c, a);
420 ASSERT_EQ((jobject)method->GetClass(), d.l);
421 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
422 a.i = 0;
423 b.l = (jobject)NULL;
424 c.l = (jobject)16;
425 d = RunMethod(method, a, b, c, a);
426 ASSERT_EQ((jobject)method->GetClass(), d.l);
427 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
428 a.i = 1;
429 d = RunMethod(method, a, b, c, a);
430 ASSERT_EQ((jobject)NULL, d.l);
431 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
432 a.i = 2;
433 d = RunMethod(method, a, b, c, a);
434 ASSERT_EQ((jobject)16, d.l);
435 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
436 a.i = 0;
437 b.l = (jobject)16;
438 c.l = (jobject)NULL;
439 d = RunMethod(method, a, b, c, a);
440 ASSERT_EQ((jobject)method->GetClass(), d.l);
441 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
442 a.i = 1;
443 d = RunMethod(method, a, b, c, a);
444 ASSERT_EQ((jobject)16, d.l);
445 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
446 a.i = 2;
447 d = RunMethod(method, a, b, c, a);
448 ASSERT_EQ((jobject)NULL, d.l);
449 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
450}
451
Ian Rogersdf20fe02011-07-20 20:34:16 -0700452TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700453 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700454 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700455
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700456 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700457 ASSERT_TRUE(klass != NULL);
458
459 Method* method = klass->FindDirectMethod(
460 "fooSSIOO",
461 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
462 ASSERT_TRUE(method != NULL);
Ian Rogersdf20fe02011-07-20 20:34:16 -0700463
464 Assembler jni_asm;
465 JniCompiler jni_compiler;
466 jni_compiler.Compile(&jni_asm, method);
467
468 // TODO: should really use JNIEnv to RegisterNative, but missing a
469 // complete story on this, so hack the RegisterNative below
470 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
471
472 jvalue a, b, c, d;
473 a.i = 0;
474 b.l = (jobject)NULL;
475 c.l = (jobject)NULL;
476 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
477 d = RunMethod(method, a, b, c, a);
478 ASSERT_EQ((jobject)method->GetClass(), d.l);
479 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
480 a.i = 0;
481 b.l = (jobject)NULL;
482 c.l = (jobject)16;
483 d = RunMethod(method, a, b, c, a);
484 ASSERT_EQ((jobject)method->GetClass(), d.l);
485 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
486 a.i = 1;
487 d = RunMethod(method, a, b, c, a);
488 ASSERT_EQ((jobject)NULL, d.l);
489 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
490 a.i = 2;
491 d = RunMethod(method, a, b, c, a);
492 ASSERT_EQ((jobject)16, d.l);
493 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
494 a.i = 0;
495 b.l = (jobject)16;
496 c.l = (jobject)NULL;
497 d = RunMethod(method, a, b, c, a);
498 ASSERT_EQ((jobject)method->GetClass(), d.l);
499 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
500 a.i = 1;
501 d = RunMethod(method, a, b, c, a);
502 ASSERT_EQ((jobject)16, d.l);
503 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
504 a.i = 2;
505 d = RunMethod(method, a, b, c, a);
506 ASSERT_EQ((jobject)NULL, d.l);
507 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
508}
509
Ian Rogers45a76cb2011-07-21 22:00:15 -0700510int gSuspendCounterHandler_calls;
511void SuspendCountHandler(Method** frame) {
Carl Shapiro8860c0e2011-08-04 17:36:16 -0700512 EXPECT_TRUE((*frame)->GetName()->Equals("fooI"));
Ian Rogers45a76cb2011-07-21 22:00:15 -0700513 gSuspendCounterHandler_calls++;
514 Thread::Current()->DecrementSuspendCount();
515}
516TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700517 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700518 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700519
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700520 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700521 ASSERT_TRUE(klass != NULL);
522
523 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
524 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700525
526 Assembler jni_asm;
527 JniCompiler jni_compiler;
528 jni_compiler.Compile(&jni_asm, method);
529
530 // TODO: should really use JNIEnv to RegisterNative, but missing a
531 // complete story on this, so hack the RegisterNative below
532 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
533 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
534
535 gSuspendCounterHandler_calls = 0;
536 gJava_MyClass_fooI_calls = 0;
537 jvalue a, b, c;
538 a.l = (jobject)NULL;
539 b.i = 42;
540 c = RunMethod(method, a, b, a, a);
541 ASSERT_EQ(42, c.i);
542 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
543 EXPECT_EQ(0, gSuspendCounterHandler_calls);
544 Thread::Current()->IncrementSuspendCount();
545 c = RunMethod(method, a, b, a, a);
546 ASSERT_EQ(42, c.i);
547 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
548 EXPECT_EQ(1, gSuspendCounterHandler_calls);
549 c = RunMethod(method, a, b, a, a);
550 ASSERT_EQ(42, c.i);
551 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
552 EXPECT_EQ(1, gSuspendCounterHandler_calls);
553}
554
555int gExceptionHandler_calls;
556void ExceptionHandler(Method** frame) {
Carl Shapiro8860c0e2011-08-04 17:36:16 -0700557 EXPECT_TRUE((*frame)->GetName()->Equals("foo"));
Ian Rogers45a76cb2011-07-21 22:00:15 -0700558 gExceptionHandler_calls++;
559 Thread::Current()->ClearException();
560}
561TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700562 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700563 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700564
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700565 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700566 ASSERT_TRUE(klass != NULL);
567
568 Method* method = klass->FindVirtualMethod("foo", "()V");
569 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700570
571 Assembler jni_asm;
572 JniCompiler jni_compiler;
573 jni_compiler.Compile(&jni_asm, method);
574
575 // TODO: should really use JNIEnv to RegisterNative, but missing a
576 // complete story on this, so hack the RegisterNative below
577 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
578 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
579
580 gExceptionHandler_calls = 0;
581 gJava_MyClass_foo_calls = 0;
582 jvalue a;
583 a.l = (jobject)NULL;
584 RunMethod(method, a, a, a, a);
585 EXPECT_EQ(1, gJava_MyClass_foo_calls);
586 EXPECT_EQ(0, gExceptionHandler_calls);
587 // TODO: create a real exception here
588 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
589 RunMethod(method, a, a, a, a);
590 EXPECT_EQ(2, gJava_MyClass_foo_calls);
591 EXPECT_EQ(1, gExceptionHandler_calls);
592 RunMethod(method, a, a, a, a);
593 EXPECT_EQ(3, gJava_MyClass_foo_calls);
594 EXPECT_EQ(1, gExceptionHandler_calls);
595}
596
Ian Rogersb033c752011-07-20 12:22:35 -0700597} // namespace art