1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <iostream> 18 #include <pthread.h> 19 #include <stdio.h> 20 #include <vector> 21 22 #include "art_method-inl.h" 23 #include "base/logging.h" 24 #include "jni.h" 25 26 namespace art { 27 28 static JavaVM* jvm = nullptr; 29 30 static jint Java_Main_intFastNativeMethod(JNIEnv*, jclass, jint a, jint b, jint c); 31 static jint Java_Main_intCriticalNativeMethod(jint a, jint b, jint c); 32 33 static JNINativeMethod sMainMethods[] = { 34 {"intFastNativeMethod", "(III)I", reinterpret_cast<void*>(Java_Main_intFastNativeMethod) }, 35 {"intCriticalNativeMethod", "(III)I", reinterpret_cast<void*>(Java_Main_intCriticalNativeMethod) }, 36 }; 37 38 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void*) { 39 CHECK(vm != nullptr); 40 CHECK(jvm == nullptr); 41 jvm = vm; 42 std::cout << "JNI_OnLoad called" << std::endl; 43 44 return JNI_VERSION_1_6; 45 } 46 47 extern "C" JNIEXPORT void JNI_OnUnload(JavaVM*, void*) { 48 // std::cout since LOG(INFO) adds extra stuff like pid. 49 std::cout << "JNI_OnUnload called" << std::endl; 50 // Clear jvm for CHECK in test 004-JniTest. 51 jvm = nullptr; 52 } 53 54 static void* AttachHelper(void* arg) { 55 CHECK(jvm != nullptr); 56 57 JNIEnv* env = nullptr; 58 JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, nullptr }; 59 int attach_result = jvm->AttachCurrentThread(&env, &args); 60 CHECK_EQ(attach_result, 0); 61 62 typedef void (*Fn)(JNIEnv*); 63 Fn fn = reinterpret_cast<Fn>(arg); 64 fn(env); 65 66 int detach_result = jvm->DetachCurrentThread(); 67 CHECK_EQ(detach_result, 0); 68 return nullptr; 69 } 70 71 static void PthreadHelper(void (*fn)(JNIEnv*)) { 72 pthread_t pthread; 73 int pthread_create_result = pthread_create(&pthread, nullptr, AttachHelper, 74 reinterpret_cast<void*>(fn)); 75 CHECK_EQ(pthread_create_result, 0); 76 int pthread_join_result = pthread_join(pthread, nullptr); 77 CHECK_EQ(pthread_join_result, 0); 78 } 79 80 static void testFindClassOnAttachedNativeThread(JNIEnv* env) { 81 jclass clazz = env->FindClass("Main"); 82 CHECK(clazz != nullptr); 83 CHECK(!env->ExceptionCheck()); 84 85 jobjectArray array = env->NewObjectArray(0, clazz, nullptr); 86 CHECK(array != nullptr); 87 CHECK(!env->ExceptionCheck()); 88 } 89 90 // http://b/10994325 91 extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*, jclass) { 92 PthreadHelper(&testFindClassOnAttachedNativeThread); 93 } 94 95 static void testFindFieldOnAttachedNativeThread(JNIEnv* env) { 96 jclass clazz = env->FindClass("Main"); 97 CHECK(clazz != nullptr); 98 CHECK(!env->ExceptionCheck()); 99 100 jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z"); 101 CHECK(field != nullptr); 102 CHECK(!env->ExceptionCheck()); 103 104 env->SetStaticBooleanField(clazz, field, JNI_TRUE); 105 } 106 107 extern "C" JNIEXPORT void JNICALL Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv*, 108 jclass) { 109 PthreadHelper(&testFindFieldOnAttachedNativeThread); 110 } 111 112 static void testReflectFieldGetFromAttachedNativeThread(JNIEnv* env) { 113 jclass clazz = env->FindClass("Main"); 114 CHECK(clazz != nullptr); 115 CHECK(!env->ExceptionCheck()); 116 117 jclass class_clazz = env->FindClass("java/lang/Class"); 118 CHECK(class_clazz != nullptr); 119 CHECK(!env->ExceptionCheck()); 120 121 jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField", 122 "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); 123 CHECK(getFieldMetodId != nullptr); 124 CHECK(!env->ExceptionCheck()); 125 126 jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField"); 127 CHECK(field_name != nullptr); 128 CHECK(!env->ExceptionCheck()); 129 130 jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name); 131 CHECK(field != nullptr); 132 CHECK(!env->ExceptionCheck()); 133 134 jclass field_clazz = env->FindClass("java/lang/reflect/Field"); 135 CHECK(field_clazz != nullptr); 136 CHECK(!env->ExceptionCheck()); 137 138 jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean", 139 "(Ljava/lang/Object;)Z"); 140 CHECK(getBooleanMetodId != nullptr); 141 CHECK(!env->ExceptionCheck()); 142 143 jboolean value = env->CallBooleanMethod(field, getBooleanMetodId, /* ignored */ clazz); 144 CHECK(value == false); 145 CHECK(!env->ExceptionCheck()); 146 } 147 148 // http://b/15539150 149 extern "C" JNIEXPORT void JNICALL Java_Main_testReflectFieldGetFromAttachedNativeThreadNative( 150 JNIEnv*, jclass) { 151 PthreadHelper(&testReflectFieldGetFromAttachedNativeThread); 152 } 153 154 155 // http://b/11243757 156 extern "C" JNIEXPORT void JNICALL Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, 157 jclass) { 158 jclass super_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SuperClass"); 159 CHECK(super_class != nullptr); 160 161 jmethodID execute = env->GetStaticMethodID(super_class, "execute", "()V"); 162 CHECK(execute != nullptr); 163 164 jclass sub_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SubClass"); 165 CHECK(sub_class != nullptr); 166 167 env->CallStaticVoidMethod(sub_class, execute); 168 } 169 170 extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass) { 171 jclass abstract_class = env->FindClass("Main$testGetMirandaMethod_MirandaAbstract"); 172 CHECK(abstract_class != nullptr); 173 jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z"); 174 CHECK(miranda_method != nullptr); 175 return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE); 176 } 177 178 // https://code.google.com/p/android/issues/detail?id=63055 179 extern "C" void JNICALL Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass) { 180 std::vector<uint8_t> buffer(1); 181 jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0); 182 CHECK(byte_buffer != nullptr); 183 CHECK(!env->ExceptionCheck()); 184 185 CHECK_EQ(env->GetDirectBufferAddress(byte_buffer), &buffer[0]); 186 CHECK_EQ(env->GetDirectBufferCapacity(byte_buffer), 0); 187 } 188 189 constexpr size_t kByteReturnSize = 7; 190 jbyte byte_returns[kByteReturnSize] = { 0, 1, 2, 127, -1, -2, -128 }; 191 192 extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv*, jclass, jbyte b1, jbyte b2, 193 jbyte b3, jbyte b4, jbyte b5, jbyte b6, 194 jbyte b7, jbyte b8, jbyte b9, jbyte b10) { 195 // We use b1 to drive the output. 196 CHECK_EQ(b2, 2); 197 CHECK_EQ(b3, -3); 198 CHECK_EQ(b4, 4); 199 CHECK_EQ(b5, -5); 200 CHECK_EQ(b6, 6); 201 CHECK_EQ(b7, -7); 202 CHECK_EQ(b8, 8); 203 CHECK_EQ(b9, -9); 204 CHECK_EQ(b10, 10); 205 206 CHECK_LE(0, b1); 207 CHECK_LT(b1, static_cast<jbyte>(kByteReturnSize)); 208 209 return byte_returns[b1]; 210 } 211 212 constexpr size_t kShortReturnSize = 9; 213 jshort short_returns[kShortReturnSize] = { 0, 1, 2, 127, 32767, -1, -2, -128, 214 static_cast<jshort>(0x8000) }; 215 // The weird static_cast is because short int is only guaranteed down to -32767, not Java's -32768. 216 217 extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv*, jclass, jshort s1, jshort s2, 218 jshort s3, jshort s4, jshort s5, jshort s6, 219 jshort s7, jshort s8, jshort s9, jshort s10) { 220 // We use s1 to drive the output. 221 CHECK_EQ(s2, 2); 222 CHECK_EQ(s3, -3); 223 CHECK_EQ(s4, 4); 224 CHECK_EQ(s5, -5); 225 CHECK_EQ(s6, 6); 226 CHECK_EQ(s7, -7); 227 CHECK_EQ(s8, 8); 228 CHECK_EQ(s9, -9); 229 CHECK_EQ(s10, 10); 230 231 CHECK_LE(0, s1); 232 CHECK_LT(s1, static_cast<jshort>(kShortReturnSize)); 233 234 return short_returns[s1]; 235 } 236 237 extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv*, jclass, jboolean b1, 238 jboolean b2, jboolean b3, jboolean b4, 239 jboolean b5, jboolean b6, jboolean b7, 240 jboolean b8, jboolean b9, jboolean b10) { 241 // We use b1 to drive the output. 242 CHECK_EQ(b2, JNI_TRUE); 243 CHECK_EQ(b3, JNI_FALSE); 244 CHECK_EQ(b4, JNI_TRUE); 245 CHECK_EQ(b5, JNI_FALSE); 246 CHECK_EQ(b6, JNI_TRUE); 247 CHECK_EQ(b7, JNI_FALSE); 248 CHECK_EQ(b8, JNI_TRUE); 249 CHECK_EQ(b9, JNI_FALSE); 250 CHECK_EQ(b10, JNI_TRUE); 251 252 CHECK(b1 == JNI_TRUE || b1 == JNI_FALSE); 253 return b1; 254 } 255 256 constexpr size_t kCharReturnSize = 8; 257 jchar char_returns[kCharReturnSize] = { 0, 1, 2, 127, 255, 256, 15000, 34000 }; 258 259 extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv*, jclass, jchar c1, jchar c2, 260 jchar c3, jchar c4, jchar c5, jchar c6, jchar c7, 261 jchar c8, jchar c9, jchar c10) { 262 // We use c1 to drive the output. 263 CHECK_EQ(c2, 'a'); 264 CHECK_EQ(c3, 'b'); 265 CHECK_EQ(c4, 'c'); 266 CHECK_EQ(c5, '0'); 267 CHECK_EQ(c6, '1'); 268 CHECK_EQ(c7, '2'); 269 CHECK_EQ(c8, 1234); 270 CHECK_EQ(c9, 2345); 271 CHECK_EQ(c10, 3456); 272 273 CHECK_LT(c1, static_cast<jchar>(kCharReturnSize)); 274 275 return char_returns[c1]; 276 } 277 278 extern "C" JNIEXPORT void JNICALL Java_Main_removeLocalObject(JNIEnv* env, jclass, jclass o) { 279 // Delete the arg to see if it crashes. 280 env->DeleteLocalRef(o); 281 } 282 283 extern "C" JNIEXPORT jboolean JNICALL Java_Main_nativeIsAssignableFrom(JNIEnv* env, jclass, 284 jclass from, jclass to) { 285 return env->IsAssignableFrom(from, to); 286 } 287 288 static void testShallowGetCallingClassLoader(JNIEnv* env) { 289 // Test direct call. 290 { 291 jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); 292 CHECK(vmstack_clazz != nullptr); 293 CHECK(!env->ExceptionCheck()); 294 295 jmethodID getCallingClassLoaderMethodId = env->GetStaticMethodID(vmstack_clazz, 296 "getCallingClassLoader", 297 "()Ljava/lang/ClassLoader;"); 298 CHECK(getCallingClassLoaderMethodId != nullptr); 299 CHECK(!env->ExceptionCheck()); 300 301 jobject class_loader = env->CallStaticObjectMethod(vmstack_clazz, 302 getCallingClassLoaderMethodId); 303 CHECK(class_loader == nullptr); 304 CHECK(!env->ExceptionCheck()); 305 } 306 307 // Test one-level call. Use System.loadLibrary(). 308 { 309 jclass system_clazz = env->FindClass("java/lang/System"); 310 CHECK(system_clazz != nullptr); 311 CHECK(!env->ExceptionCheck()); 312 313 jmethodID loadLibraryMethodId = env->GetStaticMethodID(system_clazz, "loadLibrary", 314 "(Ljava/lang/String;)V"); 315 CHECK(loadLibraryMethodId != nullptr); 316 CHECK(!env->ExceptionCheck()); 317 318 // Create a string object. 319 jobject library_string = env->NewStringUTF("non_existing_library"); 320 CHECK(library_string != nullptr); 321 CHECK(!env->ExceptionCheck()); 322 323 env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string); 324 CHECK(env->ExceptionCheck()); 325 326 // We expect UnsatisfiedLinkError. 327 jthrowable thrown = env->ExceptionOccurred(); 328 env->ExceptionClear(); 329 330 jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError"); 331 jclass thrown_class = env->GetObjectClass(thrown); 332 CHECK(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class)); 333 } 334 } 335 336 // http://b/16867274 337 extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetCallingClassLoader(JNIEnv*, 338 jclass) { 339 PthreadHelper(&testShallowGetCallingClassLoader); 340 } 341 342 static void testShallowGetStackClass2(JNIEnv* env) { 343 jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); 344 CHECK(vmstack_clazz != nullptr); 345 CHECK(!env->ExceptionCheck()); 346 347 // Test direct call. 348 { 349 jmethodID getStackClass2MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass2", 350 "()Ljava/lang/Class;"); 351 CHECK(getStackClass2MethodId != nullptr); 352 CHECK(!env->ExceptionCheck()); 353 354 jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass2MethodId); 355 CHECK(caller_class == nullptr); 356 CHECK(!env->ExceptionCheck()); 357 } 358 359 // Test one-level call. Use VMStack.getStackClass1(). 360 { 361 jmethodID getStackClass1MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass1", 362 "()Ljava/lang/Class;"); 363 CHECK(getStackClass1MethodId != nullptr); 364 CHECK(!env->ExceptionCheck()); 365 366 jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass1MethodId); 367 CHECK(caller_class == nullptr); 368 CHECK(!env->ExceptionCheck()); 369 } 370 371 // For better testing we would need to compile against libcore and have a two-deep stack 372 // ourselves. 373 } 374 375 extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetStackClass2(JNIEnv*, jclass) { 376 PthreadHelper(&testShallowGetStackClass2); 377 } 378 379 class JniCallNonvirtualVoidMethodTest { 380 public: 381 explicit JniCallNonvirtualVoidMethodTest(JNIEnv* env) 382 : env_(env), 383 check_jni_ri_(true), 384 check_jni_android_(true), 385 super_(GetClass("JniCallNonvirtualTest")), 386 sub_(GetClass("JniCallNonvirtualTestSubclass")), 387 super_constructor_(GetMethodID(super_, true, "<init>")), 388 super_static_(GetMethodID(super_, false, "staticMethod")), 389 super_nonstatic_(GetMethodID(super_, true, "nonstaticMethod")), 390 sub_constructor_(GetMethodID(sub_, true, "<init>")), 391 sub_static_(GetMethodID(sub_, false, "staticMethod")), 392 sub_nonstatic_(GetMethodID(sub_, true, "nonstaticMethod")), 393 super_field_(GetFieldID(super_, "nonstaticMethodSuperCalled")), 394 sub_field_(GetFieldID(super_, "nonstaticMethodSubCalled")) {} 395 396 void Test() { 397 TestStaticCallNonvirtualMethod(); 398 TestNewObject(); 399 TestnonstaticCallNonvirtualMethod(); 400 } 401 402 JNIEnv* const env_; 403 404 bool const check_jni_ri_; 405 bool const check_jni_android_; 406 407 jclass const super_; 408 jclass const sub_; 409 410 jmethodID const super_constructor_; 411 jmethodID const super_static_; 412 jmethodID const super_nonstatic_; 413 jmethodID const sub_constructor_; 414 jmethodID const sub_static_; 415 jmethodID const sub_nonstatic_; 416 417 jfieldID const super_field_; 418 jfieldID const sub_field_; 419 420 private: 421 jclass GetClass(const char* class_name) { 422 jclass c = env_->FindClass(class_name); 423 if (env_->ExceptionCheck()) { 424 env_->ExceptionDescribe(); 425 env_->FatalError(__FUNCTION__); 426 } 427 CHECK(!env_->ExceptionCheck()); 428 CHECK(c != nullptr); 429 return c; 430 } 431 432 jmethodID GetMethodID(jclass c, bool nonstatic, const char* method_name) { 433 jmethodID m = ((nonstatic) ? 434 env_->GetMethodID(c, method_name, "()V") : 435 env_->GetStaticMethodID(c, method_name, "()V")); 436 if (env_->ExceptionCheck()) { 437 env_->ExceptionDescribe(); 438 env_->FatalError(__FUNCTION__); 439 } 440 CHECK(m != nullptr); 441 return m; 442 } 443 444 jobject CallConstructor(jclass c, jmethodID m) { 445 jobject o = env_->NewObject(c, m); 446 if (env_->ExceptionCheck()) { 447 env_->ExceptionDescribe(); 448 env_->FatalError(__FUNCTION__); 449 } 450 CHECK(o != nullptr); 451 return o; 452 } 453 454 void CallMethod(jobject o, jclass c, jmethodID m, bool nonstatic, const char* test_case) { 455 printf("RUNNING %s\n", test_case); 456 env_->CallNonvirtualVoidMethod(o, c, m); 457 bool exception_check = env_->ExceptionCheck(); 458 if (c == nullptr || !nonstatic) { 459 if (!exception_check) { 460 printf("FAILED %s due to missing exception\n", test_case); 461 env_->FatalError("Expected NullPointerException with null jclass"); 462 } 463 env_->ExceptionClear(); 464 } else if (exception_check) { 465 printf("FAILED %s due to pending exception\n", test_case); 466 env_->ExceptionDescribe(); 467 env_->FatalError(test_case); 468 } 469 printf("PASSED %s\n", test_case); 470 } 471 472 jfieldID GetFieldID(jclass c, const char* field_name) { 473 jfieldID m = env_->GetFieldID(c, field_name, "Z"); 474 if (env_->ExceptionCheck()) { 475 env_->ExceptionDescribe(); 476 env_->FatalError(__FUNCTION__); 477 } 478 CHECK(m != nullptr); 479 return m; 480 } 481 482 jboolean GetBooleanField(jobject o, jfieldID f) { 483 jboolean b = env_->GetBooleanField(o, f); 484 if (env_->ExceptionCheck()) { 485 env_->ExceptionDescribe(); 486 env_->FatalError(__FUNCTION__); 487 } 488 return b; 489 } 490 491 void TestStaticCallNonvirtualMethod() { 492 if (!check_jni_ri_&& !check_jni_android_) { 493 CallMethod(nullptr, nullptr, super_static_, false, "null object, null class, super static"); 494 } 495 if (!check_jni_android_) { 496 CallMethod(nullptr, super_, super_static_, false, "null object, super class, super static"); 497 } 498 if (!check_jni_android_) { 499 CallMethod(nullptr, sub_, super_static_, false, "null object, sub class, super static"); 500 } 501 502 if (!check_jni_ri_ && !check_jni_android_) { 503 CallMethod(nullptr, nullptr, sub_static_, false, "null object, null class, sub static"); 504 } 505 if (!check_jni_android_) { 506 CallMethod(nullptr, sub_, sub_static_, false, "null object, super class, sub static"); 507 } 508 if (!check_jni_android_) { 509 CallMethod(nullptr, super_, sub_static_, false, "null object, super class, sub static"); 510 } 511 } 512 513 void TestNewObject() { 514 jobject super_super = CallConstructor(super_, super_constructor_); 515 jobject super_sub = CallConstructor(super_, sub_constructor_); 516 jobject sub_super = CallConstructor(sub_, super_constructor_); 517 jobject sub_sub = CallConstructor(sub_, sub_constructor_); 518 519 CHECK(env_->IsInstanceOf(super_super, super_)); 520 CHECK(!env_->IsInstanceOf(super_super, sub_)); 521 522 // Note that even though we called (and ran) the subclass 523 // constructor, we are not the subclass. 524 CHECK(env_->IsInstanceOf(super_sub, super_)); 525 CHECK(!env_->IsInstanceOf(super_sub, sub_)); 526 527 // Note that even though we called the superclass constructor, we 528 // are still the subclass. 529 CHECK(env_->IsInstanceOf(sub_super, super_)); 530 CHECK(env_->IsInstanceOf(sub_super, sub_)); 531 532 CHECK(env_->IsInstanceOf(sub_sub, super_)); 533 CHECK(env_->IsInstanceOf(sub_sub, sub_)); 534 } 535 536 void TestnonstaticCallNonvirtualMethod(bool super_object, bool super_class, bool super_method, const char* test_case) { 537 if (check_jni_android_) { 538 if (super_object && !super_method) { 539 return; // We don't allow a call with sub class method on the super class instance. 540 } 541 if (super_class && !super_method) { 542 return; // We don't allow a call with the sub class method with the super class argument. 543 } 544 } 545 jobject o = ((super_object) ? 546 CallConstructor(super_, super_constructor_) : 547 CallConstructor(sub_, sub_constructor_)); 548 jclass c = (super_class) ? super_ : sub_; 549 jmethodID m = (super_method) ? super_nonstatic_ : sub_nonstatic_; 550 CallMethod(o, c, m, true, test_case); 551 jboolean super_field = GetBooleanField(o, super_field_); 552 jboolean sub_field = GetBooleanField(o, sub_field_); 553 CHECK_EQ(super_field, super_method); 554 CHECK_NE(sub_field, super_method); 555 } 556 557 void TestnonstaticCallNonvirtualMethod() { 558 TestnonstaticCallNonvirtualMethod(true, true, true, "super object, super class, super nonstatic"); 559 TestnonstaticCallNonvirtualMethod(true, false, true, "super object, sub class, super nonstatic"); 560 TestnonstaticCallNonvirtualMethod(true, false, false, "super object, sub class, sub nonstatic"); 561 TestnonstaticCallNonvirtualMethod(true, true, false, "super object, super class, sub nonstatic"); 562 563 TestnonstaticCallNonvirtualMethod(false, true, true, "sub object, super class, super nonstatic"); 564 TestnonstaticCallNonvirtualMethod(false, false, true, "sub object, sub class, super nonstatic"); 565 TestnonstaticCallNonvirtualMethod(false, false, false, "sub object, sub class, sub nonstatic"); 566 TestnonstaticCallNonvirtualMethod(false, true, false, "sub object, super class, sub nonstatic"); 567 } 568 }; 569 570 extern "C" void JNICALL Java_Main_testCallNonvirtual(JNIEnv* env, jclass) { 571 JniCallNonvirtualVoidMethodTest(env).Test(); 572 } 573 574 extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jclass) { 575 jclass c = env->FindClass("java/lang/String"); 576 CHECK(c != nullptr); 577 578 jmethodID mid1 = env->GetMethodID(c, "<init>", "()V"); 579 CHECK(mid1 != nullptr); 580 CHECK(!env->ExceptionCheck()); 581 jmethodID mid2 = env->GetMethodID(c, "<init>", "([B)V"); 582 CHECK(mid2 != nullptr); 583 CHECK(!env->ExceptionCheck()); 584 jmethodID mid3 = env->GetMethodID(c, "<init>", "([C)V"); 585 CHECK(mid3 != nullptr); 586 CHECK(!env->ExceptionCheck()); 587 jmethodID mid4 = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V"); 588 CHECK(mid4 != nullptr); 589 CHECK(!env->ExceptionCheck()); 590 591 const char* test_array = "Test"; 592 int byte_array_length = strlen(test_array); 593 jbyteArray byte_array = env->NewByteArray(byte_array_length); 594 env->SetByteArrayRegion(byte_array, 0, byte_array_length, reinterpret_cast<const jbyte*>(test_array)); 595 596 // Test NewObject 597 jstring s = reinterpret_cast<jstring>(env->NewObject(c, mid2, byte_array)); 598 CHECK(s != nullptr); 599 CHECK_EQ(env->GetStringLength(s), byte_array_length); 600 CHECK_EQ(env->GetStringUTFLength(s), byte_array_length); 601 const char* chars = env->GetStringUTFChars(s, nullptr); 602 CHECK_EQ(strcmp(test_array, chars), 0); 603 env->ReleaseStringUTFChars(s, chars); 604 605 // Test AllocObject and Call(Nonvirtual)VoidMethod 606 jstring s1 = reinterpret_cast<jstring>(env->AllocObject(c)); 607 CHECK(s1 != nullptr); 608 jstring s2 = reinterpret_cast<jstring>(env->AllocObject(c)); 609 CHECK(s2 != nullptr); 610 jstring s3 = reinterpret_cast<jstring>(env->AllocObject(c)); 611 CHECK(s3 != nullptr); 612 jstring s4 = reinterpret_cast<jstring>(env->AllocObject(c)); 613 CHECK(s4 != nullptr); 614 615 jcharArray char_array = env->NewCharArray(5); 616 jstring string_arg = env->NewStringUTF("helloworld"); 617 618 // With Var Args 619 env->CallVoidMethod(s1, mid1); 620 env->CallNonvirtualVoidMethod(s2, c, mid2, byte_array); 621 622 // With JValues 623 jvalue args3[1]; 624 args3[0].l = char_array; 625 jvalue args4[1]; 626 args4[0].l = string_arg; 627 env->CallVoidMethodA(s3, mid3, args3); 628 env->CallNonvirtualVoidMethodA(s4, c, mid4, args4); 629 630 // Test with global and weak global references 631 jstring s5 = reinterpret_cast<jstring>(env->AllocObject(c)); 632 CHECK(s5 != nullptr); 633 s5 = reinterpret_cast<jstring>(env->NewGlobalRef(s5)); 634 jstring s6 = reinterpret_cast<jstring>(env->AllocObject(c)); 635 CHECK(s6 != nullptr); 636 s6 = reinterpret_cast<jstring>(env->NewWeakGlobalRef(s6)); 637 638 env->CallVoidMethod(s5, mid1); 639 env->CallNonvirtualVoidMethod(s6, c, mid2, byte_array); 640 CHECK_EQ(env->GetStringLength(s5), 0); 641 CHECK_EQ(env->GetStringLength(s6), byte_array_length); 642 const char* chars6 = env->GetStringUTFChars(s6, nullptr); 643 CHECK_EQ(strcmp(test_array, chars6), 0); 644 env->ReleaseStringUTFChars(s6, chars6); 645 } 646 647 extern "C" JNIEXPORT jlong JNICALL Java_Main_testGetMethodID(JNIEnv* env, jclass, jclass c) { 648 return reinterpret_cast<jlong>(env->GetMethodID(c, "a", "()V")); 649 } 650 651 extern "C" JNIEXPORT void JNICALL Java_Main_enterJniCriticalSection(JNIEnv* env, jclass, 652 jint arraySize, 653 jbyteArray array0, 654 jbyteArray array1) { 655 for (int i = 0; i < 50000; ++i) { 656 char* data0 = reinterpret_cast<char*>(env->GetPrimitiveArrayCritical(array0, nullptr)); 657 char* data1 = reinterpret_cast<char*>(env->GetPrimitiveArrayCritical(array1, nullptr)); 658 bool up = i % 2 == 0; 659 for (int j = 0; j < arraySize; ++j) { 660 if (up) { 661 data1[j] = data0[j] + 1; 662 } else { 663 data0[j] = data1[j] + 1; 664 } 665 } 666 env->ReleasePrimitiveArrayCritical(array1, data1, 0); 667 env->ReleasePrimitiveArrayCritical(array0, data0, 0); 668 } 669 } 670 671 class JniCallDefaultMethodsTest { 672 public: 673 explicit JniCallDefaultMethodsTest(JNIEnv* env) 674 : env_(env), concrete_class_(env_->FindClass("ConcreteClass")) { 675 CHECK(!env_->ExceptionCheck()); 676 CHECK(concrete_class_ != nullptr); 677 } 678 679 void Test() { 680 TestCalls("ConcreteClass", { "JniCallNonOverridenDefaultMethod", 681 "JniCallOverridenDefaultMethod", 682 "JniCallOverridenDefaultMethodWithSuper", 683 "JniCallOverridenAbstractMethod", 684 "JniCallConflictDefaultMethod", 685 "JniCallSoftConflictMethod" }); 686 TestCalls("DefaultInterface", { "JniCallNonOverridenDefaultMethod", 687 "JniCallOverridenDefaultMethod", 688 "JniCallOverridenAbstractMethod", 689 "JniCallConflictDefaultMethod", 690 "JniCallSoftConflictMethod" }); 691 TestCalls("AbstractInterface", { "JniCallSoftConflictMethod" }); 692 TestCalls("ConflictInterface", { "JniCallConflictDefaultMethod" }); 693 } 694 695 private: 696 void TestCalls(const char* declaring_class, std::vector<const char*> methods) { 697 jmethodID new_method = env_->GetMethodID(concrete_class_, "<init>", "()V"); 698 jobject obj = env_->NewObject(concrete_class_, new_method); 699 CHECK(!env_->ExceptionCheck()); 700 CHECK(obj != nullptr); 701 jclass decl_class = env_->FindClass(declaring_class); 702 CHECK(!env_->ExceptionCheck()); 703 CHECK(decl_class != nullptr); 704 for (const char* method : methods) { 705 jmethodID method_id = env_->GetMethodID(decl_class, method, "()V"); 706 CHECK(!env_->ExceptionCheck()); 707 printf("Calling method %s->%s on object of type ConcreteClass\n", declaring_class, method); 708 env_->CallVoidMethod(obj, method_id); 709 if (env_->ExceptionCheck()) { 710 jthrowable thrown = env_->ExceptionOccurred(); 711 env_->ExceptionClear(); 712 jmethodID to_string = env_->GetMethodID( 713 env_->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;"); 714 jstring exception_string = (jstring) env_->CallObjectMethod(thrown, to_string); 715 CHECK(!env_->ExceptionCheck()); 716 const char* exception_string_utf8 = env_->GetStringUTFChars(exception_string, nullptr); 717 CHECK(!env_->ExceptionCheck()); 718 CHECK(exception_string_utf8 != nullptr); 719 printf("EXCEPTION OCCURED: %s\n", exception_string_utf8); 720 env_->ReleaseStringUTFChars(exception_string, exception_string_utf8); 721 } 722 } 723 } 724 725 JNIEnv* env_; 726 jclass concrete_class_; 727 }; 728 729 extern "C" JNIEXPORT void JNICALL Java_Main_testCallDefaultMethods(JNIEnv* env) { 730 JniCallDefaultMethodsTest(env).Test(); 731 } 732 733 static void InvokeSpecificMethod(JNIEnv* env, jobject obj, const char* method) { 734 jclass lambda_class = env->FindClass("LambdaInterface"); 735 CHECK(!env->ExceptionCheck()); 736 CHECK(lambda_class != nullptr); 737 jmethodID method_id = env->GetMethodID(lambda_class, method, "()V"); 738 CHECK(!env->ExceptionCheck()); 739 env->CallVoidMethod(obj, method_id); 740 CHECK(!env->ExceptionCheck()); 741 } 742 743 extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaDefaultMethod( 744 JNIEnv* e, jclass, jobject l) { 745 InvokeSpecificMethod(e, l, "sayHiTwice"); 746 } 747 748 extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaMethod(JNIEnv* e, jclass, jobject l) { 749 InvokeSpecificMethod(e, l, "sayHi"); 750 } 751 752 // Register on-demand because many tests share this JNI library and 753 // we can't unconditionally register them. 754 extern "C" JNIEXPORT jboolean JNICALL Java_Main_registerNativesJniTest(JNIEnv* e, jclass kls) { 755 const size_t numMethods = sizeof(sMainMethods)/sizeof(JNINativeMethod); 756 757 if (e->RegisterNatives(kls, sMainMethods, numMethods) < 0) { 758 std::cerr << "RegisterNatives failed for 'Main'" << std::endl; 759 return JNI_FALSE; 760 } 761 762 return JNI_TRUE; 763 } 764 765 // Annotated with @FastNative in Java code. Doesn't need to be explicitly registered with "!". 766 // NOTE: Has to be registered explicitly to avoid mutator lock check failures. 767 static jint Java_Main_intFastNativeMethod(JNIEnv*, jclass, jint a, jint b, jint c) { 768 return a + b + c; 769 } 770 771 // Annotated with @CriticalNative in Java code. Doesn't need to be explicitly registered with "!". 772 // NOTE: Has to be registered explicitly to avoid mutator lock check failures. 773 static jint Java_Main_intCriticalNativeMethod(jint a, jint b, jint c) { 774 // Note that unlike a "Fast Native" method this excludes JNIEnv and the jclass parameters. 775 return a + b + c; 776 } 777 778 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isSlowDebug(JNIEnv*, jclass) { 779 // Return whether slow-debug is on. Only relevant for debug builds. 780 if (kIsDebugBuild) { 781 // Register a dummy flag and get the default value it should be initialized with. 782 static bool dummy_flag = false; 783 dummy_flag = RegisterRuntimeDebugFlag(&dummy_flag); 784 785 return dummy_flag ? JNI_TRUE : JNI_FALSE; 786 } 787 // To pass the Java-side test, just so "on" for release builds. 788 return JNI_TRUE; 789 } 790 791 } // namespace art 792 793