< prev index next > src/hotspot/share/runtime/sharedRuntime.cpp
Print this page
#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;
(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 >