< prev index next >

src/hotspot/share/runtime/sharedRuntime.cpp

Print this page
@@ -74,10 +74,14 @@
  #include "utilities/macros.hpp"
  #include "utilities/xmlstream.hpp"
  #ifdef COMPILER1
  #include "c1/c1_Runtime1.hpp"
  #endif
+ #if INCLUDE_TSAN
+ #include "tsan/tsanExternalDecls.hpp"
+ #include "tsan/tsanOopMap.hpp"
+ #endif
  
  // Shared stub locations
  RuntimeStub*        SharedRuntime::_wrong_method_blob;
  RuntimeStub*        SharedRuntime::_wrong_method_abstract_blob;
  RuntimeStub*        SharedRuntime::_ic_miss_blob;

@@ -1006,10 +1010,180 @@
        (char *) name->bytes(), name->utf8_length(),
        (char *) sig->bytes(), sig->utf8_length());
    return 0;
  JRT_END
  
+ #if INCLUDE_TSAN
+ 
+ JRT_LEAF(void, SharedRuntime::verify_oop_index(oopDesc* obj, int index))
+   assert(oopDesc::is_oop(obj), "invalid oop");
+   assert(index >= 0, "index is less than 0");
+   int obj_size_in_bytes = obj->size() * HeapWordSize;
+   assert(index < obj_size_in_bytes, "index %d >= obj size %d", index, obj_size_in_bytes);
+ JRT_END
+ 
+ // TSAN: method entry callback from interpreter
+ // (1) In order to have the line numbers in the call stack, we use the caller
+ //     address instead of the method that's being called. This also matches
+ //     the entry/exit convention that TSAN uses for C++.
+ // We use JRT_ENTRY since call_VM_leaf doesn't set _last_Java_sp that we need.
+ JRT_ENTRY(void, SharedRuntime::tsan_interp_method_entry(JavaThread *thread))
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   DEBUG_ONLY(NoHandleMark nhm;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+ 
+   RegisterMap unused_reg_map(thread, false);
+ 
+   // These asserts should be removed once
+   // we support more than just the interpreter for TSAN.
+   assert(!thread->last_frame().is_compiled_frame(),
+          "Current frame should not be a compiled frame");
+   const frame sender = thread->last_frame().real_sender(&unused_reg_map);
+   assert(!sender.is_compiled_frame(), "Sender should not be a compiled frame");
+ 
+   jmethodID jmethod_id = 0;
+   u2 bci = 0;
+   // TODO: is (0, 0) really the best we can do
+   // when the sender isn't an interpreted frame?
+   if (sender.is_interpreted_frame()) {
+     jmethod_id = sender.interpreter_frame_method()->find_jmethod_id_or_null();
+     bci = sender.interpreter_frame_bci();
+   }
+   __tsan_func_entry(tsan_code_location(jmethod_id, bci));
+ JRT_END
+ 
+ // TSAN: method exit callback from interpreter
+ JRT_LEAF(void, SharedRuntime::tsan_interp_method_exit())
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   __tsan_func_exit();
+ JRT_END
+ 
+ void SharedRuntime::tsan_oop_lock(Thread* thread, oop obj) {
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(thread != NULL, "null thread");
+   assert(obj != NULL, "null oop");
+   assert(oopDesc::is_oop(obj), "invalid oop");
+ 
+   TsanOopMap::add_oop(obj);
+   __tsan_java_mutex_lock((julong)(oopDesc*)obj);
+ }
+ 
+ void SharedRuntime::tsan_oop_unlock(Thread *thread, oop obj) {
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(thread != NULL, "null thread");
+   assert(obj != NULL, "null oop");
+   assert(oopDesc::is_oop(obj), "invalid oop");
+   assert(TsanOopMap::exists(obj), "oop seen in unlock but not tracked");
+ 
+   __tsan_java_mutex_unlock((julong)(oopDesc*)obj);
+ }
+ 
+ void SharedRuntime::tsan_oop_rec_lock(Thread* thread, oop obj, int rec) {
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(thread != NULL, "null thread");
+   assert(obj != NULL, "null oop");
+   assert(oopDesc::is_oop(obj), "invalid oop");
+ 
+   TsanOopMap::add_oop(obj);
+   __tsan_java_mutex_lock_rec((julong)(oopDesc*)obj, rec);
+ }
+ 
+ int SharedRuntime::tsan_oop_rec_unlock(Thread *thread, oop obj) {
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(thread != NULL, "null thread");
+   assert(obj != NULL, "null oop");
+   assert(oopDesc::is_oop(obj), "invalid oop");
+   assert(TsanOopMap::exists(obj), "oop seen in unlock but not tracked");
+ 
+   return __tsan_java_mutex_unlock_rec((julong)(oopDesc*)obj);
+ }
+ 
+ JRT_LEAF(void, SharedRuntime::tsan_interp_lock(JavaThread* thread,
+                                                BasicObjectLock* elem))
+   DEBUG_ONLY(thread->last_frame().interpreter_frame_verify_monitor(elem);)
+   assert(elem != NULL, "null elem");
+ 
+   oop obj = elem->obj();
+   tsan_oop_lock(thread, obj);
+ 
+   assert(obj == elem->obj(), "oop changed");
+   DEBUG_ONLY(thread->last_frame().interpreter_frame_verify_monitor(elem);)
+ JRT_END
+ 
+ JRT_LEAF(void, SharedRuntime::tsan_interp_unlock(JavaThread* thread,
+                                                  BasicObjectLock* elem))
+   DEBUG_ONLY(thread->last_frame().interpreter_frame_verify_monitor(elem);)
+   assert(elem != NULL, "null elem");
+ 
+   oop obj = elem->obj();
+   tsan_oop_unlock(thread, obj);
+ 
+   assert(obj == elem->obj(), "oop changed");
+   DEBUG_ONLY(thread->last_frame().interpreter_frame_verify_monitor(elem);)
+ JRT_END
+ 
+ // Should be JRT_LEAF, but this is called very early during VM startup, so we
+ // are sometimes in '_thread_in_vm' state.
+ // NOTE: DO NOT add operations that can safepoint, enter GC, or throw an
+ // exception!
+ void SharedRuntime::tsan_track_obj_with_size(oopDesc* obj, int size) {
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(oopDesc::is_oop(obj), "Bad oopDesc passed to tsan_track_obj_with_size().");
+   TsanOopMap::add_oop_with_size(obj, size);
+ }
+ 
+ JRT_LEAF(void, SharedRuntime::tsan_track_obj(oopDesc* obj))
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(oopDesc::is_oop(obj), "Bad oopDesc passed to tsan_track_obj().");
+   TsanOopMap::add_oop(obj);
+ JRT_END
+ 
+ // TODO: Make tsan_acquire/release JRT_LEAF
+ // Currently it can't be JRT_LEAF because there are calls from the VM
+ // (instanceKlass.cpp), and JRT_LEAF only allows calls from Java/native code.
+ // We need to figure out a better way of being able to call TSAN functions from
+ // the VM.
+ void SharedRuntime::tsan_acquire(void* address) {
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(address != NULL, "Cannot acquire at address 0");
+   __tsan_java_acquire(address);
+ }
+ 
+ void SharedRuntime::tsan_release(void* address) {
+   DEBUG_ONLY(NoSafepointVerifier nsv;)
+   assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");
+   assert(address != NULL, "Cannot release at address 0");
+   __tsan_java_release(address);
+ }
+ 
+ #define TSAN_MEMORY_ACCESS(name)                                               \
+   JRT_LEAF(void, SharedRuntime::tsan_##name(                                   \
+       void* addr,                                                              \
+       Method* method,                                                          \
+       address bcp))                                                            \
+     assert(ThreadSanitizer, "Need -XX:+ThreadSanitizer");                      \
+     assert(ThreadSanitizerJavaMemory, "Need -XX:+ThreadSanitizerJavaMemory");  \
+     jmethodID mid = method->find_jmethod_id_or_null();                         \
+     int bci = method->bci_from(bcp);                                           \
+     __tsan_##name##_pc(addr, tsan_code_location(mid, bci));                    \
+   JRT_END
+ 
+ TSAN_MEMORY_ACCESS(read1)
+ TSAN_MEMORY_ACCESS(read2)
+ TSAN_MEMORY_ACCESS(read4)
+ TSAN_MEMORY_ACCESS(read8)
+ TSAN_MEMORY_ACCESS(write1)
+ TSAN_MEMORY_ACCESS(write2)
+ TSAN_MEMORY_ACCESS(write4)
+ TSAN_MEMORY_ACCESS(write8)
+ 
+ #endif // INCLUDE_TSAN
  
  // Finds receiver, CallInfo (i.e. receiver method), and calling bytecode)
  // for a call current in progress, i.e., arguments has been pushed on stack
  // put callee has not been invoked yet.  Used by: resolve virtual/static,
  // vtable updates, etc.  Caller frame must be compiled.
< prev index next >