1 /* 2 * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "jni.h" 27 #include "classfile/javaClasses.hpp" 28 #include "classfile/symbolTable.hpp" 29 #include "classfile/systemDictionary.hpp" 30 #include "classfile/vmSymbols.hpp" 31 #include "jfr/jni/jfrJavaCall.hpp" 32 #include "jfr/jni/jfrJavaSupport.hpp" 33 #include "jfr/utilities/jfrLog.hpp" 34 #include "memory/resourceArea.hpp" 35 #include "oops/instanceOop.hpp" 36 #include "oops/oop.inline.hpp" 37 #include "oops/objArrayKlass.hpp" 38 #include "oops/objArrayOop.hpp" 39 #include "runtime/handles.inline.hpp" 40 #include "runtime/fieldDescriptor.hpp" 41 #include "runtime/java.hpp" 42 #include "runtime/jniHandles.hpp" 43 #include "runtime/synchronizer.hpp" 44 #include "runtime/thread.inline.hpp" 45 46 #ifdef ASSERT 47 void JfrJavaSupport::check_java_thread_in_vm(Thread* t) { 48 assert(t != NULL, "invariant"); 49 assert(t->is_Java_thread(), "invariant"); 50 assert(((JavaThread*)t)->thread_state() == _thread_in_vm, "invariant"); 51 } 52 53 void JfrJavaSupport::check_java_thread_in_native(Thread* t) { 54 assert(t != NULL, "invariant"); 55 assert(t->is_Java_thread(), "invariant"); 56 assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant"); 57 } 58 #endif 59 60 /* 61 * Handles and references 62 */ 63 jobject JfrJavaSupport::local_jni_handle(const oop obj, Thread* t) { 64 DEBUG_ONLY(check_java_thread_in_vm(t)); 65 return t->active_handles()->allocate_handle(obj); 66 } 67 68 jobject JfrJavaSupport::local_jni_handle(const jobject handle, Thread* t) { 69 DEBUG_ONLY(check_java_thread_in_vm(t)); 70 const oop obj = JNIHandles::resolve(handle); 71 return obj == NULL ? NULL : local_jni_handle(obj, t); 72 } 73 74 void JfrJavaSupport::destroy_local_jni_handle(jobject handle) { 75 JNIHandles::destroy_local(handle); 76 } 77 78 jobject JfrJavaSupport::global_jni_handle(const oop obj, Thread* t) { 79 DEBUG_ONLY(check_java_thread_in_vm(t)); 80 HandleMark hm(t); 81 return JNIHandles::make_global(Handle(t, obj)); 82 } 83 84 jobject JfrJavaSupport::global_jni_handle(const jobject handle, Thread* t) { 85 const oop obj = JNIHandles::resolve(handle); 86 return obj == NULL ? NULL : global_jni_handle(obj, t); 87 } 88 89 void JfrJavaSupport::destroy_global_jni_handle(jobject handle) { 90 JNIHandles::destroy_global(handle); 91 } 92 93 oop JfrJavaSupport::resolve_non_null(jobject obj) { 94 return JNIHandles::resolve_non_null(obj); 95 } 96 97 /* 98 * Method invocation 99 */ 100 void JfrJavaSupport::call_static(JfrJavaArguments* args, TRAPS) { 101 JfrJavaCall::call_static(args, THREAD); 102 } 103 104 void JfrJavaSupport::call_special(JfrJavaArguments* args, TRAPS) { 105 JfrJavaCall::call_special(args, THREAD); 106 } 107 108 void JfrJavaSupport::call_virtual(JfrJavaArguments* args, TRAPS) { 109 JfrJavaCall::call_virtual(args, THREAD); 110 } 111 112 void JfrJavaSupport::notify_all(jobject object, TRAPS) { 113 assert(object != NULL, "invariant"); 114 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 115 HandleMark hm(THREAD); 116 Handle h_obj(THREAD, resolve_non_null(object)); 117 assert(h_obj.not_null(), "invariant"); 118 ObjectSynchronizer::jni_enter(h_obj, THREAD); 119 ObjectSynchronizer::notifyall(h_obj, THREAD); 120 ObjectSynchronizer::jni_exit(h_obj(), THREAD); 121 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 122 } 123 124 /* 125 * Object construction 126 */ 127 static void object_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, TRAPS) { 128 assert(args != NULL, "invariant"); 129 assert(result != NULL, "invariant"); 130 assert(klass != NULL, "invariant"); 131 assert(klass->is_initialized(), "invariant"); 132 133 HandleMark hm(THREAD); 134 instanceOop obj = klass->allocate_instance(CHECK); 135 instanceHandle h_obj(THREAD, obj); 136 assert(h_obj.not_null(), "invariant"); 137 args->set_receiver(h_obj); 138 result->set_type(T_VOID); // constructor result type 139 JfrJavaSupport::call_special(args, CHECK); 140 result->set_type(T_OBJECT); // set back to original result type 141 result->set_jobject((jobject)h_obj()); 142 } 143 144 static void array_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, int array_length, TRAPS) { 145 assert(args != NULL, "invariant"); 146 assert(result != NULL, "invariant"); 147 assert(klass != NULL, "invariant"); 148 assert(klass->is_initialized(), "invariant"); 149 150 Klass* const ak = klass->array_klass(THREAD); 151 ObjArrayKlass::cast(ak)->initialize(THREAD); 152 HandleMark hm(THREAD); 153 objArrayOop arr = ObjArrayKlass::cast(ak)->allocate(array_length, CHECK); 154 result->set_jobject((jobject)arr); 155 } 156 157 static void create_object(JfrJavaArguments* args, JavaValue* result, TRAPS) { 158 assert(args != NULL, "invariant"); 159 assert(result != NULL, "invariant"); 160 assert(result->get_type() == T_OBJECT, "invariant"); 161 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); 162 163 InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass()); 164 klass->initialize(CHECK); 165 166 const int array_length = args->array_length(); 167 168 if (array_length > 0) { 169 array_construction(args, result, klass, array_length, CHECK); 170 } else { 171 object_construction(args, result, klass, THREAD); 172 } 173 } 174 175 static void handle_result(JavaValue* result, bool global_ref, Thread* t) { 176 assert(result != NULL, "invariant"); 177 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t)); 178 const oop result_oop = (const oop)result->get_jobject(); 179 if (result_oop == NULL) { 180 return; 181 } 182 result->set_jobject(global_ref ? 183 JfrJavaSupport::global_jni_handle(result_oop, t) : 184 JfrJavaSupport::local_jni_handle(result_oop, t)); 185 } 186 187 void JfrJavaSupport::new_object(JfrJavaArguments* args, TRAPS) { 188 assert(args != NULL, "invariant"); 189 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 190 create_object(args, args->result(), THREAD); 191 } 192 193 void JfrJavaSupport::new_object_local_ref(JfrJavaArguments* args, TRAPS) { 194 assert(args != NULL, "invariant"); 195 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 196 JavaValue* const result = args->result(); 197 assert(result != NULL, "invariant"); 198 create_object(args, result, CHECK); 199 handle_result(result, false, THREAD); 200 } 201 202 void JfrJavaSupport::new_object_global_ref(JfrJavaArguments* args, TRAPS) { 203 assert(args != NULL, "invariant"); 204 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 205 JavaValue* const result = args->result(); 206 assert(result != NULL, "invariant"); 207 create_object(args, result, CHECK); 208 handle_result(result, true, THREAD); 209 } 210 211 jstring JfrJavaSupport::new_string(const char* c_str, TRAPS) { 212 assert(c_str != NULL, "invariant"); 213 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 214 const oop result = java_lang_String::create_oop_from_str(c_str, THREAD); 215 return (jstring)local_jni_handle(result, THREAD); 216 } 217 218 jobjectArray JfrJavaSupport::new_string_array(int length, TRAPS) { 219 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 220 JavaValue result(T_OBJECT); 221 JfrJavaArguments args(&result, "java/lang/String", "<init>", "()V", CHECK_NULL); 222 args.set_array_length(length); 223 new_object_local_ref(&args, THREAD); 224 return (jobjectArray)args.result()->get_jobject(); 225 } 226 227 jobject JfrJavaSupport::new_java_lang_Boolean(bool value, TRAPS) { 228 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 229 JavaValue result(T_OBJECT); 230 JfrJavaArguments args(&result, "java/lang/Boolean", "<init>", "(Z)V", CHECK_NULL); 231 args.push_int(value ? (jint)JNI_TRUE : (jint)JNI_FALSE); 232 new_object_local_ref(&args, THREAD); 233 return args.result()->get_jobject(); 234 } 235 236 jobject JfrJavaSupport::new_java_lang_Integer(jint value, TRAPS) { 237 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 238 JavaValue result(T_OBJECT); 239 JfrJavaArguments args(&result, "java/lang/Integer", "<init>", "(I)V", CHECK_NULL); 240 args.push_int(value); 241 new_object_local_ref(&args, THREAD); 242 return args.result()->get_jobject(); 243 } 244 245 jobject JfrJavaSupport::new_java_lang_Long(jlong value, TRAPS) { 246 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 247 JavaValue result(T_OBJECT); 248 JfrJavaArguments args(&result, "java/lang/Long", "<init>", "(J)V", CHECK_NULL); 249 args.push_long(value); 250 new_object_local_ref(&args, THREAD); 251 return args.result()->get_jobject(); 252 } 253 254 void JfrJavaSupport::set_array_element(jobjectArray arr, jobject element, int index, Thread* t) { 255 assert(arr != NULL, "invariant"); 256 DEBUG_ONLY(check_java_thread_in_vm(t)); 257 HandleMark hm(t); 258 objArrayHandle a(t, (objArrayOop)resolve_non_null(arr)); 259 a->obj_at_put(index, resolve_non_null(element)); 260 } 261 262 /* 263 * Field access 264 */ 265 static void write_int_field(const Handle& h_oop, fieldDescriptor* fd, jint value) { 266 assert(h_oop.not_null(), "invariant"); 267 assert(fd != NULL, "invariant"); 268 h_oop->int_field_put(fd->offset(), value); 269 } 270 271 static void write_float_field(const Handle& h_oop, fieldDescriptor* fd, jfloat value) { 272 assert(h_oop.not_null(), "invariant"); 273 assert(fd != NULL, "invariant"); 274 h_oop->float_field_put(fd->offset(), value); 275 } 276 277 static void write_double_field(const Handle& h_oop, fieldDescriptor* fd, jdouble value) { 278 assert(h_oop.not_null(), "invariant"); 279 assert(fd != NULL, "invariant"); 280 h_oop->double_field_put(fd->offset(), value); 281 } 282 283 static void write_long_field(const Handle& h_oop, fieldDescriptor* fd, jlong value) { 284 assert(h_oop.not_null(), "invariant"); 285 assert(fd != NULL, "invariant"); 286 h_oop->long_field_put(fd->offset(), value); 287 } 288 289 static void write_oop_field(const Handle& h_oop, fieldDescriptor* fd, const oop value) { 290 assert(h_oop.not_null(), "invariant"); 291 assert(fd != NULL, "invariant"); 292 h_oop->obj_field_put(fd->offset(), value); 293 } 294 295 static void write_specialized_field(JfrJavaArguments* args, const Handle& h_oop, fieldDescriptor* fd, bool static_field) { 296 assert(args != NULL, "invariant"); 297 assert(h_oop.not_null(), "invariant"); 298 assert(fd != NULL, "invariant"); 299 assert(fd->offset() > 0, "invariant"); 300 assert(args->length() >= 1, "invariant"); 301 302 // attempt must set a real value 303 assert(args->param(1).get_type() != T_VOID, "invariant"); 304 305 switch(fd->field_type()) { 306 case T_BOOLEAN: 307 case T_CHAR: 308 case T_SHORT: 309 case T_INT: 310 write_int_field(h_oop, fd, args->param(1).get_jint()); 311 break; 312 case T_FLOAT: 313 write_float_field(h_oop, fd, args->param(1).get_jfloat()); 314 break; 315 case T_DOUBLE: 316 write_double_field(h_oop, fd, args->param(1).get_jdouble()); 317 break; 318 case T_LONG: 319 write_long_field(h_oop, fd, args->param(1).get_jlong()); 320 break; 321 case T_OBJECT: 322 write_oop_field(h_oop, fd, (oop)args->param(1).get_jobject()); 323 break; 324 case T_ADDRESS: 325 write_oop_field(h_oop, fd, JfrJavaSupport::resolve_non_null(args->param(1).get_jobject())); 326 break; 327 default: 328 ShouldNotReachHere(); 329 } 330 } 331 332 static void read_specialized_field(JavaValue* result, const Handle& h_oop, fieldDescriptor* fd) { 333 assert(result != NULL, "invariant"); 334 assert(h_oop.not_null(), "invariant"); 335 assert(fd != NULL, "invariant"); 336 assert(fd->offset() > 0, "invariant"); 337 338 switch(fd->field_type()) { 339 case T_BOOLEAN: 340 case T_CHAR: 341 case T_SHORT: 342 case T_INT: 343 result->set_jint(h_oop->int_field(fd->offset())); 344 break; 345 case T_FLOAT: 346 result->set_jfloat(h_oop->float_field(fd->offset())); 347 break; 348 case T_DOUBLE: 349 result->set_jdouble(h_oop->double_field(fd->offset())); 350 break; 351 case T_LONG: 352 result->set_jlong(h_oop->long_field(fd->offset())); 353 break; 354 case T_OBJECT: 355 result->set_jobject((jobject)h_oop->obj_field(fd->offset())); 356 break; 357 default: 358 ShouldNotReachHere(); 359 } 360 } 361 362 static bool find_field(InstanceKlass* ik, 363 Symbol* name_symbol, 364 Symbol* signature_symbol, 365 fieldDescriptor* fd, 366 bool is_static = false, 367 bool allow_super = false) { 368 if (allow_super || is_static) { 369 return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL; 370 } 371 return ik->find_local_field(name_symbol, signature_symbol, fd); 372 } 373 374 static void lookup_field(JfrJavaArguments* args, InstanceKlass* klass, fieldDescriptor* fd, bool static_field) { 375 assert(args != NULL, "invariant"); 376 assert(klass != NULL, "invariant"); 377 assert(klass->is_initialized(), "invariant"); 378 assert(fd != NULL, "invariant"); 379 find_field(klass, args->name(), args->signature(), fd, static_field, true); 380 } 381 382 static void read_field(JfrJavaArguments* args, JavaValue* result, TRAPS) { 383 assert(args != NULL, "invariant"); 384 assert(result != NULL, "invariant"); 385 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); 386 387 InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass()); 388 klass->initialize(CHECK); 389 const bool static_field = !args->has_receiver(); 390 fieldDescriptor fd; 391 lookup_field(args, klass, &fd, static_field); 392 assert(fd.offset() > 0, "invariant"); 393 394 HandleMark hm(THREAD); 395 Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver())); 396 read_specialized_field(result, h_oop, &fd); 397 } 398 399 static void write_field(JfrJavaArguments* args, JavaValue* result, TRAPS) { 400 assert(args != NULL, "invariant"); 401 assert(result != NULL, "invariant"); 402 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); 403 404 InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass()); 405 klass->initialize(CHECK); 406 407 const bool static_field = !args->has_receiver(); 408 fieldDescriptor fd; 409 lookup_field(args, klass, &fd, static_field); 410 assert(fd.offset() > 0, "invariant"); 411 412 HandleMark hm(THREAD); 413 Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver())); 414 write_specialized_field(args, h_oop, &fd, static_field); 415 } 416 417 void JfrJavaSupport::set_field(JfrJavaArguments* args, TRAPS) { 418 assert(args != NULL, "invariant"); 419 write_field(args, args->result(), THREAD); 420 } 421 422 void JfrJavaSupport::get_field(JfrJavaArguments* args, TRAPS) { 423 assert(args != NULL, "invariant"); 424 read_field(args, args->result(), THREAD); 425 } 426 427 void JfrJavaSupport::get_field_local_ref(JfrJavaArguments* args, TRAPS) { 428 assert(args != NULL, "invariant"); 429 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 430 431 JavaValue* const result = args->result(); 432 assert(result != NULL, "invariant"); 433 assert(result->get_type() == T_OBJECT, "invariant"); 434 435 read_field(args, result, CHECK); 436 const oop obj = (const oop)result->get_jobject(); 437 438 if (obj != NULL) { 439 result->set_jobject(local_jni_handle(obj, THREAD)); 440 } 441 } 442 443 void JfrJavaSupport::get_field_global_ref(JfrJavaArguments* args, TRAPS) { 444 assert(args != NULL, "invariant"); 445 DEBUG_ONLY(check_java_thread_in_vm(THREAD)); 446 447 JavaValue* const result = args->result(); 448 assert(result != NULL, "invariant"); 449 assert(result->get_type() == T_OBJECT, "invariant"); 450 read_field(args, result, CHECK); 451 const oop obj = (const oop)result->get_jobject(); 452 if (obj != NULL) { 453 result->set_jobject(global_jni_handle(obj, THREAD)); 454 } 455 } 456 457 /* 458 * Misc 459 */ 460 Klass* JfrJavaSupport::klass(const jobject handle) { 461 const oop obj = resolve_non_null(handle); 462 assert(obj != NULL, "invariant"); 463 return obj->klass(); 464 } 465 466 // caller needs ResourceMark 467 const char* JfrJavaSupport::c_str(jstring string, Thread* t) { 468 DEBUG_ONLY(check_java_thread_in_vm(t)); 469 if (string == NULL) { 470 return NULL; 471 } 472 const char* temp = NULL; 473 const oop java_string = resolve_non_null(string); 474 if (java_lang_String::value(java_string) != NULL) { 475 const size_t length = java_lang_String::utf8_length(java_string); 476 temp = NEW_RESOURCE_ARRAY_IN_THREAD(t, const char, (length + 1)); 477 if (temp == NULL) { 478 JfrJavaSupport::throw_out_of_memory_error("Unable to allocate thread local native memory", t); 479 return NULL; 480 } 481 assert(temp != NULL, "invariant"); 482 java_lang_String::as_utf8_string(java_string, const_cast<char*>(temp), (int) length + 1); 483 } 484 return temp; 485 } 486 487 /* 488 * Exceptions and errors 489 */ 490 static void create_and_throw(Symbol* name, const char* message, TRAPS) { 491 assert(name != NULL, "invariant"); 492 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); 493 assert(!HAS_PENDING_EXCEPTION, "invariant"); 494 THROW_MSG(name, message); 495 } 496 497 void JfrJavaSupport::throw_illegal_state_exception(const char* message, TRAPS) { 498 create_and_throw(vmSymbols::java_lang_IllegalStateException(), message, THREAD); 499 } 500 501 void JfrJavaSupport::throw_internal_error(const char* message, TRAPS) { 502 create_and_throw(vmSymbols::java_lang_InternalError(), message, THREAD); 503 } 504 505 void JfrJavaSupport::throw_illegal_argument_exception(const char* message, TRAPS) { 506 create_and_throw(vmSymbols::java_lang_IllegalArgumentException(), message, THREAD); 507 } 508 509 void JfrJavaSupport::throw_out_of_memory_error(const char* message, TRAPS) { 510 create_and_throw(vmSymbols::java_lang_OutOfMemoryError(), message, THREAD); 511 } 512 513 void JfrJavaSupport::throw_class_format_error(const char* message, TRAPS) { 514 create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD); 515 } 516 517 void JfrJavaSupport::abort(jstring errorMsg, Thread* t) { 518 DEBUG_ONLY(check_java_thread_in_vm(t)); 519 520 ResourceMark rm(t); 521 const char* const error_msg = c_str(errorMsg, t); 522 if (error_msg != NULL) { 523 log_error(jfr, system)("%s",error_msg); 524 } 525 log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM..."); 526 vm_abort(); 527 } 528 529 JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR; 530 void JfrJavaSupport::set_cause(jthrowable throwable, Thread* t) { 531 DEBUG_ONLY(check_java_thread_in_vm(t)); 532 533 HandleMark hm(t); 534 Handle ex(t, JNIHandles::resolve_external_guard(throwable)); 535 536 if (ex.is_null()) { 537 return; 538 } 539 540 if (ex->is_a(SystemDictionary::OutOfMemoryError_klass())) { 541 _cause = OUT_OF_MEMORY; 542 return; 543 } 544 if (ex->is_a(SystemDictionary::StackOverflowError_klass())) { 545 _cause = STACK_OVERFLOW; 546 return; 547 } 548 if (ex->is_a(SystemDictionary::Error_klass())) { 549 _cause = VM_ERROR; 550 return; 551 } 552 if (ex->is_a(SystemDictionary::RuntimeException_klass())) { 553 _cause = RUNTIME_EXCEPTION; 554 return; 555 } 556 if (ex->is_a(SystemDictionary::Exception_klass())) { 557 _cause = UNKNOWN; 558 return; 559 } 560 } 561 562 void JfrJavaSupport::uncaught_exception(jthrowable throwable, Thread* t) { 563 DEBUG_ONLY(check_java_thread_in_vm(t)); 564 assert(throwable != NULL, "invariant"); 565 set_cause(throwable, t); 566 } 567 568 JfrJavaSupport::CAUSE JfrJavaSupport::cause() { 569 return _cause; 570 } 571 572 const char* const JDK_JFR_MODULE_NAME = "jdk.jfr"; 573 const char* const JDK_JFR_PACKAGE_NAME = "jdk/jfr"; 574 575 jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) { 576 oop java_thread = JNIHandles::resolve_non_null(target_thread); 577 JavaThread* native_thread = java_lang_Thread::thread(java_thread); 578 return native_thread != NULL ? THREAD_TRACE_ID(native_thread) : 0; 579 }