Merge
authorrottenha
Mon, 28 Feb 2011 15:35:45 -0800
changeset 8478 d89e2f60ba40
parent 8341 7553bce69380 (current diff)
parent 8476 7e34c2d4cf9b (diff)
child 8479 8bcc94fcb7f7
Merge
hotspot/src/os/solaris/vm/os_solaris.cpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/java.cpp
hotspot/src/share/vm/runtime/os.hpp
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -2213,7 +2213,7 @@
   if (rp == NULL)
     return;
 
-  if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
+  if (Arguments::created_by_gamma_launcher()) {
     // Support for the gamma launcher.  Typical value for buf is
     // "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so".  If "/jre/lib/" appears at
     // the right place in the string, then assume we are installed in a JDK and
--- a/hotspot/src/os/posix/vm/os_posix.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/os/posix/vm/os_posix.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -59,3 +59,12 @@
   VMError::report_coredump_status(buffer, success);
 }
 
+bool os::is_debugger_attached() {
+  // not implemented
+  return false;
+}
+
+void os::wait_for_keypress_at_exit(void) {
+  // don't do anything on posix platforms
+  return;
+}
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -2511,7 +2511,7 @@
   assert(ret != 0, "cannot locate libjvm");
   realpath((char *)dlinfo.dli_fname, buf);
 
-  if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
+  if (Arguments::created_by_gamma_launcher()) {
     // Support for the gamma launcher.  Typical value for buf is
     // "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so".  If "/jre/lib/" appears at
     // the right place in the string, then assume we are installed in a JDK and
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -1788,7 +1788,7 @@
   }
 
   buf[0] = '\0';
-  if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
+  if (Arguments::created_by_gamma_launcher()) {
      // Support for the gamma launcher. Check for an
      // JAVA_HOME environment variable
      // and fix up the path so it looks like
@@ -3418,6 +3418,19 @@
 }
 
 
+bool os::is_debugger_attached() {
+  return IsDebuggerPresent() ? true : false;
+}
+
+
+void os::wait_for_keypress_at_exit(void) {
+  if (PauseAtExit) {
+    fprintf(stderr, "Press any key to continue...\n");
+    fgetc(stdin);
+  }
+}
+
+
 int os::message_box(const char* title, const char* message) {
   int result = MessageBox(NULL, message, title,
                           MB_YESNO | MB_ICONERROR | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY);
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -1805,6 +1805,10 @@
 
 void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) {
   JavaThread* thread = JavaThread::current();
+  // In theory everyone coming thru here is in_vm but we need to be certain
+  // because a callee will do a vm->native transition
+  ThreadInVMfromUnknown __tiv;
+
   EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED,
                  ("JVMTI [%s] method dynamic code generated event triggered",
                  JvmtiTrace::safe_get_thread_name(thread)));
@@ -1826,19 +1830,18 @@
 }
 
 void JvmtiExport::post_dynamic_code_generated(const char *name, const void *code_begin, const void *code_end) {
-  // In theory everyone coming thru here is in_vm but we need to be certain
-  // because a callee will do a vm->native transition
-  ThreadInVMfromUnknown __tiv;
   jvmtiPhase phase = JvmtiEnv::get_phase();
   if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) {
     post_dynamic_code_generated_internal(name, code_begin, code_end);
-    return;
+  } else {
+    // It may not be safe to post the event from this thread.  Defer all
+    // postings to the service thread so that it can perform them in a safe
+    // context and in-order.
+    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
+    JvmtiDeferredEvent event = JvmtiDeferredEvent::dynamic_code_generated_event(
+        name, code_begin, code_end);
+    JvmtiDeferredEventQueue::enqueue(event);
   }
-
-  // Blocks until everything now in the queue has been posted
-  JvmtiDeferredEventQueue::flush_queue(Thread::current());
-
-  post_dynamic_code_generated_internal(name, code_begin, code_end);
 }
 
 
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp	Mon Feb 28 15:35:45 2011 -0800
@@ -140,12 +140,12 @@
                                       char sig_type, jvalue *value);
 
 
- private:
   // posts a DynamicCodeGenerated event (internal/private implementation).
   // The public post_dynamic_code_generated* functions make use of the
-  // internal implementation.
+  // internal implementation.  Also called from JvmtiDeferredEvent::post()
   static void post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) KERNEL_RETURN;
 
+ private:
 
   // GenerateEvents support to allow posting of CompiledMethodLoad and
   // DynamicCodeGenerated events for a given environment.
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -918,7 +918,7 @@
 JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
     nmethod* nm) {
   JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD);
-  event.set_compiled_method_load(nm);
+  event._event_data.compiled_method_load = nm;
   nmethodLocker::lock_nmethod(nm); // will be unlocked when posted
   return event;
 }
@@ -926,23 +926,39 @@
 JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event(
     jmethodID id, const void* code) {
   JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_UNLOAD);
-  event.set_compiled_method_unload(id, code);
+  event._event_data.compiled_method_unload.method_id = id;
+  event._event_data.compiled_method_unload.code_begin = code;
+  return event;
+}
+JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event(
+      const char* name, const void* code_begin, const void* code_end) {
+  JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_DYNAMIC_CODE_GENERATED);
+  event._event_data.dynamic_code_generated.name = name;
+  event._event_data.dynamic_code_generated.code_begin = code_begin;
+  event._event_data.dynamic_code_generated.code_end = code_end;
   return event;
 }
 
 void JvmtiDeferredEvent::post() {
+  assert(ServiceThread::is_service_thread(Thread::current()),
+         "Service thread must post enqueued events");
   switch(_type) {
-    case TYPE_COMPILED_METHOD_LOAD:
-      JvmtiExport::post_compiled_method_load(compiled_method_load());
-      nmethodLocker::unlock_nmethod(compiled_method_load());
+    case TYPE_COMPILED_METHOD_LOAD: {
+      nmethod* nm = _event_data.compiled_method_load;
+      JvmtiExport::post_compiled_method_load(nm);
+      nmethodLocker::unlock_nmethod(nm);
       break;
+    }
     case TYPE_COMPILED_METHOD_UNLOAD:
       JvmtiExport::post_compiled_method_unload(
-        compiled_method_unload_method_id(),
-        compiled_method_unload_code_begin());
+        _event_data.compiled_method_unload.method_id,
+        _event_data.compiled_method_unload.code_begin);
       break;
-    case TYPE_FLUSH:
-      JvmtiDeferredEventQueue::flush_complete(flush_state_addr());
+    case TYPE_DYNAMIC_CODE_GENERATED:
+      JvmtiExport::post_dynamic_code_generated_internal(
+        _event_data.dynamic_code_generated.name,
+        _event_data.dynamic_code_generated.code_begin,
+        _event_data.dynamic_code_generated.code_end);
       break;
     default:
       ShouldNotReachHere();
@@ -1065,54 +1081,4 @@
   }
 }
 
-enum {
-  // Random - used for debugging
-  FLUSHING  = 0x50403020,
-  FLUSHED   = 0x09080706
-};
-
-void JvmtiDeferredEventQueue::flush_queue(Thread* thread) {
-
-  volatile int flush_state = FLUSHING;
-
-  JvmtiDeferredEvent flush(JvmtiDeferredEvent::TYPE_FLUSH);
-  flush.set_flush_state_addr((int*)&flush_state);
-
-  if (ServiceThread::is_service_thread(thread)) {
-    // If we are the service thread we have to post all preceding events
-    // Use the flush event as a token to indicate when we can stop
-    JvmtiDeferredEvent event;
-    {
-      MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
-      enqueue(flush);
-      event = dequeue();
-    }
-    while (!event.is_flush_event() ||
-           event.flush_state_addr() != &flush_state) {
-      event.post();
-      {
-        MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
-        event = dequeue();
-      }
-    }
-  } else {
-    // Wake up the service thread so it will process events.  When it gets
-    // to the flush event it will set 'flush_complete' and notify us.
-    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
-    enqueue(flush);
-    while (flush_state != FLUSHED) {
-      assert(flush_state == FLUSHING || flush_state == FLUSHED,
-             "only valid values for this");
-      Service_lock->wait(Mutex::_no_safepoint_check_flag);
-    }
-  }
-}
-
-void JvmtiDeferredEventQueue::flush_complete(int* state_addr) {
-  assert(state_addr != NULL && *state_addr == FLUSHING, "must be");
-  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
-  *state_addr = FLUSHED;
-  Service_lock->notify_all();
-}
-
 #endif // ndef KERNEL
--- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp	Mon Feb 28 15:35:45 2011 -0800
@@ -451,7 +451,7 @@
     TYPE_NONE,
     TYPE_COMPILED_METHOD_LOAD,
     TYPE_COMPILED_METHOD_UNLOAD,
-    TYPE_FLUSH // pseudo-event used to implement flush_queue()
+    TYPE_DYNAMIC_CODE_GENERATED
   } Type;
 
   Type _type;
@@ -461,49 +461,15 @@
       jmethodID method_id;
       const void* code_begin;
     } compiled_method_unload;
-    int* flush_state_addr;
+    struct {
+      const char* name;
+      const void* code_begin;
+      const void* code_end;
+    } dynamic_code_generated;
   } _event_data;
 
   JvmtiDeferredEvent(Type t) : _type(t) {}
 
-  void set_compiled_method_load(nmethod* nm) {
-    assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be");
-    _event_data.compiled_method_load = nm;
-  }
-
-  nmethod* compiled_method_load() const {
-    assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be");
-    return _event_data.compiled_method_load;
-  }
-
-  void set_compiled_method_unload(jmethodID id, const void* code) {
-    assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
-    _event_data.compiled_method_unload.method_id = id;
-    _event_data.compiled_method_unload.code_begin = code;
-  }
-
-  jmethodID compiled_method_unload_method_id() const {
-    assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
-    return _event_data.compiled_method_unload.method_id;
-  }
-
-  const void* compiled_method_unload_code_begin() const {
-    assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
-    return _event_data.compiled_method_unload.code_begin;
-  }
-
-  bool is_flush_event() const { return _type == TYPE_FLUSH; }
-
-  int* flush_state_addr() const {
-    assert(is_flush_event(), "must be");
-    return _event_data.flush_state_addr;
-  }
-
-  void set_flush_state_addr(int* flag) {
-    assert(is_flush_event(), "must be");
-    _event_data.flush_state_addr = flag;
-  }
-
  public:
 
   JvmtiDeferredEvent() : _type(TYPE_NONE) {}
@@ -513,6 +479,9 @@
     KERNEL_RETURN_(JvmtiDeferredEvent());
   static JvmtiDeferredEvent compiled_method_unload_event(
       jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent());
+  static JvmtiDeferredEvent dynamic_code_generated_event(
+      const char* name, const void* begin, const void* end)
+          KERNEL_RETURN_(JvmtiDeferredEvent());
 
   // Actually posts the event.
   void post() KERNEL_RETURN;
@@ -548,25 +517,12 @@
   // Transfers events from the _pending_list to the _queue.
   static void process_pending_events() KERNEL_RETURN;
 
-  static void flush_complete(int* flush_state) KERNEL_RETURN;
-
  public:
   // Must be holding Service_lock when calling these
   static bool has_events() KERNEL_RETURN_(false);
   static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN;
   static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent());
 
-  // This call blocks until all events enqueued prior to this call
-  // have been posted.  The Service_lock is acquired and waited upon.
-  //
-  // Implemented by creating a "flush" event and placing it in the queue.
-  // When the flush event is "posted" it will call flush_complete(), which
-  // will release the caller.
-  //
-  // Can be called by any thread (maybe even the service thread itself).
-  // Not necessary for the caller to be a JavaThread.
-  static void flush_queue(Thread* current) KERNEL_RETURN;
-
   // Used to enqueue events without using a lock, for times (such as during
   // safepoint) when we can't or don't want to lock the Service_lock.
   //
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -78,6 +78,7 @@
 const char*  Arguments::_java_vendor_url_bug    = DEFAULT_VENDOR_URL_BUG;
 const char*  Arguments::_sun_java_launcher      = DEFAULT_JAVA_LAUNCHER;
 int    Arguments::_sun_java_launcher_pid        = -1;
+bool   Arguments::_created_by_gamma_launcher    = false;
 
 // These parameters are reset in method parse_vm_init_args(JavaVMInitArgs*)
 bool   Arguments::_AlwaysCompileLoopMethods     = AlwaysCompileLoopMethods;
@@ -1656,6 +1657,9 @@
 
 void Arguments::process_java_launcher_argument(const char* launcher, void* extra_info) {
   _sun_java_launcher = strdup(launcher);
+  if (strcmp("gamma", _sun_java_launcher) == 0) {
+    _created_by_gamma_launcher = true;
+  }
 }
 
 bool Arguments::created_by_java_launcher() {
@@ -1663,6 +1667,10 @@
   return strcmp(DEFAULT_JAVA_LAUNCHER, _sun_java_launcher) != 0;
 }
 
+bool Arguments::created_by_gamma_launcher() {
+  return _created_by_gamma_launcher;
+}
+
 //===========================================================================================================
 // Parsing of main arguments
 
@@ -3155,6 +3163,16 @@
     }
   }
 
+  // set PauseAtExit if the gamma launcher was used and a debugger is attached
+  // but only if not already set on the commandline
+  if (Arguments::created_by_gamma_launcher() && os::is_debugger_attached()) {
+    bool set = false;
+    CommandLineFlags::wasSetOnCmdline("PauseAtExit", &set);
+    if (!set) {
+      FLAG_SET_DEFAULT(PauseAtExit, true);
+    }
+  }
+
   return JNI_OK;
 }
 
--- a/hotspot/src/share/vm/runtime/arguments.hpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Mon Feb 28 15:35:45 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -257,6 +257,9 @@
   // sun.java.launcher.pid, private property
   static int    _sun_java_launcher_pid;
 
+  // was this VM created by the gamma launcher
+  static bool   _created_by_gamma_launcher;
+
   // Option flags
   static bool   _has_profile;
   static bool   _has_alloc_profile;
@@ -444,6 +447,8 @@
   static const char* sun_java_launcher()    { return _sun_java_launcher; }
   // Was VM created by a Java launcher?
   static bool created_by_java_launcher();
+  // Was VM created by the gamma Java launcher?
+  static bool created_by_gamma_launcher();
   // -Dsun.java.launcher.pid
   static int sun_java_launcher_pid()        { return _sun_java_launcher_pid; }
 
--- a/hotspot/src/share/vm/runtime/globals.hpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Mon Feb 28 15:35:45 2011 -0800
@@ -3733,6 +3733,9 @@
           "The file to create and for whose removal to await when pausing " \
           "at startup. (default: ./vm.paused.<pid>)")                       \
                                                                             \
+  diagnostic(bool, PauseAtExit, false,                                      \
+          "Pause and wait for keypress on exit if a debugger is attached")  \
+                                                                            \
   product(bool, ExtendedDTraceProbes,    false,                             \
           "Enable performance-impacting dtrace probes")                     \
                                                                             \
--- a/hotspot/src/share/vm/runtime/java.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/runtime/java.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -551,6 +551,7 @@
 
 void vm_direct_exit(int code) {
   notify_vm_shutdown();
+  os::wait_for_keypress_at_exit();
   ::exit(code);
 }
 
@@ -577,11 +578,13 @@
 void vm_shutdown()
 {
   vm_perform_shutdown_actions();
+  os::wait_for_keypress_at_exit();
   os::shutdown();
 }
 
 void vm_abort(bool dump_core) {
   vm_perform_shutdown_actions();
+  os::wait_for_keypress_at_exit();
   os::abort(dump_core);
   ShouldNotReachHere();
 }
--- a/hotspot/src/share/vm/runtime/os.hpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/runtime/os.hpp	Mon Feb 28 15:35:45 2011 -0800
@@ -492,6 +492,12 @@
   static void print_location(outputStream* st, intptr_t x, bool verbose = false);
   static size_t lasterror(char *buf, size_t len);
 
+  // Determines whether the calling process is being debugged by a user-mode debugger.
+  static bool is_debugger_attached();
+
+  // wait for a key press if PauseAtExit is set
+  static void wait_for_keypress_at_exit(void);
+
   // The following two functions are used by fatal error handler to trace
   // native (C) frames. They are not part of frame.hpp/frame.cpp because
   // frame.hpp/cpp assume thread is JavaThread, and also because different
--- a/hotspot/src/share/vm/runtime/thread.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -3644,6 +3644,7 @@
   if (ShowMessageBoxOnError && is_error_reported()) {
     os::infinite_sleep();
   }
+  os::wait_for_keypress_at_exit();
 
   if (JDK_Version::is_jdk12x_version()) {
     // We are the last thread running, so check if finalizers should be run.
--- a/hotspot/src/share/vm/utilities/vmError.cpp	Fri Feb 25 12:46:49 2011 -0800
+++ b/hotspot/src/share/vm/utilities/vmError.cpp	Mon Feb 28 15:35:45 2011 -0800
@@ -802,7 +802,7 @@
     first_error_tid = mytid;
     set_error_reported();
 
-    if (ShowMessageBoxOnError) {
+    if (ShowMessageBoxOnError || PauseAtExit) {
       show_message_box(buffer, sizeof(buffer));
 
       // User has asked JVM to abort. Reset ShowMessageBoxOnError so the