changeset 6409:dd10307aad9d

Merge
author coleenp
date Wed, 07 May 2014 18:19:31 -0400
parents 5edc16b659dd 21130eb5768d
children 97356e139532
files src/share/vm/classfile/systemDictionary.cpp src/share/vm/classfile/systemDictionary.hpp src/share/vm/oops/constantPool.cpp src/share/vm/oops/constantPool.hpp src/share/vm/runtime/thread.cpp
diffstat 29 files changed, 270 insertions(+), 390 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/linux/vm/os_linux.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/os/linux/vm/os_linux.cpp	Wed May 07 18:19:31 2014 -0400
@@ -5271,7 +5271,6 @@
 //
 
 static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
-  static bool proc_task_unchecked = true;
   pid_t  tid = thread->osthread()->thread_id();
   char *s;
   char stat[2048];
@@ -5284,24 +5283,7 @@
   long ldummy;
   FILE *fp;
 
-  snprintf(proc_name, 64, "/proc/%d/stat", tid);
-
-  // The /proc/<tid>/stat aggregates per-process usage on
-  // new Linux kernels 2.6+ where NPTL is supported.
-  // The /proc/self/task/<tid>/stat still has the per-thread usage.
-  // See bug 6328462.
-  // There possibly can be cases where there is no directory
-  // /proc/self/task, so we check its availability.
-  if (proc_task_unchecked && os::Linux::is_NPTL()) {
-    // This is executed only once
-    proc_task_unchecked = false;
-    fp = fopen("/proc/self/task", "r");
-    if (fp != NULL) {
-      snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid);
-      fclose(fp);
-    }
-  }
-
+  snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid);
   fp = fopen(proc_name, "r");
   if ( fp == NULL ) return -1;
   statlen = fread(stat, 1, 2047, fp);
--- a/src/share/vm/adlc/filebuff.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/adlc/filebuff.cpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -89,200 +89,6 @@
   return retval;
 }
 
-//------------------------------FileBuffRegion---------------------------------
-// Create a new region in a FileBuff.
-FileBuffRegion::FileBuffRegion( FileBuff* bufr, int soln, int ln,
-                                int off, int len)
-: _bfr(bufr), _sol(soln), _line(ln), _offset(off), _length(len) {
-  _next = NULL;                 // No chained regions
-}
-
-//------------------------------~FileBuffRegion--------------------------------
-// Delete the entire linked list of buffer regions.
-FileBuffRegion::~FileBuffRegion() {
-  if( _next ) delete _next;
-}
-
-//------------------------------copy-------------------------------------------
-// Deep copy a FileBuffRegion
-FileBuffRegion *FileBuffRegion::copy() {
-  if( !this ) return NULL;      // The empty buffer region
-  FileBuffRegion *br = new FileBuffRegion(_bfr,_sol,_line,_offset,_length);
-  if( _next ) br->_next = _next->copy();
-  return br;
-}
-
-//------------------------------merge------------------------------------------
-// Merge another buffer region into this buffer region.  Make overlapping areas
-// become a single region.  Remove (delete) the input FileBuffRegion.
-// Since the buffer regions are sorted by file offset, this is a varient of a
-// "sorted-merge" running in linear time.
-FileBuffRegion *FileBuffRegion::merge( FileBuffRegion *br ) {
-  if( !br ) return this;        // Merging nothing
-  if( !this ) return br;        // Merging into nothing
-
-  assert( _bfr == br->_bfr, "" );     // Check for pointer-equivalent buffers
-
-  if( _offset < br->_offset ) { // "this" starts before "br"
-    if( _offset+_length < br->_offset ) { // "this" ends before "br"
-      if( _next ) _next->merge( br );    // Merge with remainder of list
-      else _next = br;                 // No more in this list; just append.
-    } else {                           // Regions overlap.
-      int l = br->_offset + br->_length - _offset;
-      if( l > _length ) _length = l;     // Pick larger region
-      FileBuffRegion *nr = br->_next;     // Get rest of region
-      br->_next = NULL;         // Remove indication of rest of region
-      delete br;                // Delete this region (it's been subsumed).
-      if( nr ) merge( nr );     // Merge with rest of region
-    }                           // End of if regions overlap or not.
-  } else {                      // "this" starts after "br"
-    if( br->_offset+br->_length < _offset ) {    // "br" ends before "this"
-      FileBuffRegion *nr = new FileBuffRegion(_bfr,_sol,_line,_offset,_length);
-      nr->_next = _next;                // Structure copy "this" guy to "nr"
-      *this = *br;              // Structure copy "br" over "this".
-      br->_next = NULL;         // Remove indication of rest of region
-      delete br;                // Delete this region (it's been copied)
-      merge( nr );              // Finish merging
-    } else {                    // Regions overlap.
-      int l = _offset + _length - br->_offset;
-      if( l > _length ) _length = l;    // Pick larger region
-      _offset = br->_offset;            // Start with earlier region
-      _sol = br->_sol;                  // Also use earlier line start
-      _line = br->_line;                        // Also use earlier line
-      FileBuffRegion *nr = br->_next;   // Get rest of region
-      br->_next = NULL;         // Remove indication of rest of region
-      delete br;                // Delete this region (it's been subsumed).
-      if( nr ) merge( nr );     // Merge with rest of region
-    }                           // End of if regions overlap or not.
-  }
-  return this;
-}
-
-//------------------------------expandtab--------------------------------------
-static int expandtab( ostream &os, int off, char c, char fill1, char fill2 ) {
-  if( c == '\t' ) {             // Tab?
-    do os << fill1;             // Expand the tab; Output space
-    while( (++off) & 7 );       // Expand to tab stop
-  } else {                      // Normal character
-    os << fill2;                // Display normal character
-    off++;                      // Increment "cursor" offset
-  }
-  return off;
-}
-
-//------------------------------printline--------------------------------------
-// Print and highlite a region of a line.  Return the amount of highliting left
-// to do (i.e. highlite length minus length of line).
-static int printline( ostream& os, const char *fname, int line,
-                        const char *_sol, int skip, int len ) {
-
-  // Display the entire tab-expanded line
-  os << fname << ":" << line << ": ";
-  const char *t = strchr(_sol,'\n')+1; // End of line
-  int off = 0;                  // Cursor offset for tab expansion
-  const char *s = _sol;         // Nice string pointer
-  while( t-s ) {                // Display whole line
-    char c = *s++;              // Get next character to display
-    off = expandtab(os,off,c,' ',c);
-  }
-
-  // Display the tab-expanded skippings before underlining.
-  os << fname << ":" << line << ": ";
-  off = 0;                      // Cursor offset for tab expansion
-  s = _sol;                     // Restart string pointer
-
-  // Start underlining.
-  if( skip != -1 ) {            // The no-start-indicating flag
-    const char *u = _sol+skip;  // Amount to skip
-    while( u-s )                // Display skipped part
-      off = expandtab(os,off,*s++,' ',' ');
-    os << '^';                  // Start region
-    off++;                      // Moved cursor
-    len--;                      // 1 less char to do
-    if( *s++ == '\t' )          // Starting character is a tab?
-      off = expandtab(os,off,'\t','-','^');
-  }
-
-  // Long region doesn't end on this line
-  int llen = (int)(t-s);        // Length of line, minus what's already done
-  if( len > llen ) {            // Doing entire rest of line?
-    while( t-s )                // Display rest of line
-      off = expandtab(os,off,*s++,'-','-');
-    os << '\n';                 // EOL
-    return len-llen;            // Return what's not yet done.
-  }
-
-  // Region does end on this line.  This code fails subtly if the region ends
-  // in a tab character.
-  int i;
-  for( i=1; i<len; i++ )        // Underline just what's needed
-    off = expandtab(os,off,*s++,'-','-');
-  if( i == len ) os << '^';     // Mark end of region
-  os << '\n';                   // End of marked line
-  return 0;                     // All done
-}
-
-//------------------------------print------------------------------------------
-//std::ostream& operator<< ( std::ostream& os, FileBuffRegion &br ) {
-ostream& operator<< ( ostream& os, FileBuffRegion &br ) {
-  if( &br == NULL ) return os;  // The empty buffer region
-  FileBuffRegion *brp = &br;    // Pointer to region
-  while( brp ) {                // While have chained regions
-    brp->print(os);             // Print region
-    brp = brp->_next;           // Chain to next
-  }
-  return os;                    // Return final stream
-}
-
-//------------------------------print------------------------------------------
-// Print the FileBuffRegion to a stream. FileBuffRegions are printed with the
-// filename and line number to the left, and complete text lines to the right.
-// Selected portions (portions of a line actually in the FileBuffRegion are
-// underlined.  Ellipses are used for long multi-line regions.
-//void FileBuffRegion::print( std::ostream& os ) {
-void FileBuffRegion::print( ostream& os ) {
-  if( !this ) return;           // Nothing to print
-  char *s = _bfr->get_line();
-  int skip = (int)(_offset - _sol);     // Amount to skip to start of data
-  int len = printline( os, _bfr->_fp->_name, _line, s, skip, _length );
-
-  if( !len ) return;                    // All done; exit
-
-  // Here we require at least 2 lines
-  int off1 = _length - len + skip;      // Length of line 1
-  int off2 = off1 + _sol;               // Offset to start of line 2
-  char *s2 = _bfr->get_line();           // Start of line 2
-  char *s3 = strchr( s2, '\n' )+1;      // Start of line 3 (unread)
-  if( len <= (s3-s2) ) {                // It all fits on the next line
-    printline( os, _bfr->_fp->_name, _line+1, s2, -1, len ); // Print&underline
-    return;
-  }
-
-  // Here we require at least 3 lines
-  int off3 = off2 + (int)(s3-s2);       // Offset to start of line 3
-  s3 = _bfr->get_line();                // Start of line 3 (read)
-  const char *s4 = strchr( s3, '\n' )+1;// Start of line 4 (unread)
-  if( len < (s4-s3) ) {                 // It all fits on the next 2 lines
-    s2 = _bfr->get_line();
-    len = printline( os, _bfr->_fp->_name, _line+1, s2, -1, len ); // Line 2
-    s3 = _bfr->get_line();
-    printline( os, _bfr->_fp->_name, _line+2, s3, -1, len );     // Line 3
-    return;
-  }
-
-  // Here we require at least 4 lines.
-  // Print only the 1st and last line, with ellipses in middle.
-  os << "...\n";                // The ellipses
-  int cline = _line+1;          // Skipped 2 lines
-  do {                          // Do until find last line
-    len -= (int)(s3-s2);        // Remove length of line
-    cline++;                    // Next line
-    s2 = _bfr->get_line();      // Get next line from end of this line
-    s3 = strchr( s2, '\n' ) + 1;// Get end of next line
-  } while( len > (s3-s2) );     // Repeat until last line
-  printline( os, _bfr->_fp->_name, cline, s2, -1, len ); // Print & underline
-}
-
 //------------------------------file_error-------------------------------------
 void FileBuff::file_error(int flag, int linenum, const char *fmt, ...)
 {
--- a/src/share/vm/adlc/filebuff.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/adlc/filebuff.hpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -46,7 +46,6 @@
 // This class defines a nicely behaved buffer of text.  Entire file of text
 // is read into buffer at creation, with sentinels at start and end.
 class FileBuff {
-  friend class FileBuffRegion;
  private:
   long  _bufferSize;            // Size of text holding buffer.
   long  _offset;                // Expected filepointer offset.
@@ -82,29 +81,4 @@
   // when the pointer is valid (i.e. just obtained from getline()).
   long getoff(const char* s) { return _bufoff + (long)(s - _buf); }
 };
-
-//------------------------------FileBuffRegion---------------------------------
-// A buffer region is really a region of some file, specified as a linked list
-// of offsets and lengths.  These regions can be merged; overlapping regions
-// will coalesce.
-class FileBuffRegion {
- public:                        // Workaround dev-studio friend/private bug
-  FileBuffRegion *_next;        // Linked list of regions sorted by offset.
- private:
-  FileBuff       *_bfr;         // The Buffer of the file
-  int _offset, _length;         // The file area
-  int             _sol;         // Start of line where the file area starts
-  int             _line;        // First line of region
-
- public:
-  FileBuffRegion(FileBuff*, int sol, int line, int offset, int len);
-  ~FileBuffRegion();
-
-  FileBuffRegion *copy();                   // Deep copy
-  FileBuffRegion *merge(FileBuffRegion*); // Merge 2 regions; delete input
-
-  void print(ostream&);
-  friend ostream& operator<< (ostream&, FileBuffRegion&);
-};
-
 #endif // SHARE_VM_ADLC_FILEBUFF_HPP
--- a/src/share/vm/classfile/resolutionErrors.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/classfile/resolutionErrors.cpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2014, 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
@@ -32,12 +32,13 @@
 
 // add new entry to the table
 void ResolutionErrorTable::add_entry(int index, unsigned int hash,
-                                     constantPoolHandle pool, int cp_index, Symbol* error)
+                                     constantPoolHandle pool, int cp_index,
+                                     Symbol* error, Symbol* message)
 {
   assert_locked_or_safepoint(SystemDictionary_lock);
   assert(!pool.is_null() && error != NULL, "adding NULL obj");
 
-  ResolutionErrorEntry* entry = new_entry(hash, pool(), cp_index, error);
+  ResolutionErrorEntry* entry = new_entry(hash, pool(), cp_index, error, message);
   add_entry(index, entry);
 }
 
@@ -58,19 +59,26 @@
 }
 
 void ResolutionErrorEntry::set_error(Symbol* e) {
-  assert(e == NULL || _error == NULL, "cannot reset error");
+  assert(e != NULL, "must set a value");
   _error = e;
-  if (_error != NULL) _error->increment_refcount();
+  _error->increment_refcount();
+}
+
+void ResolutionErrorEntry::set_message(Symbol* c) {
+  assert(c != NULL, "must set a value");
+  _message = c;
+  _message->increment_refcount();
 }
 
 // create new error entry
 ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool,
-                                                      int cp_index, Symbol* error)
+                                                      int cp_index, Symbol* error,
+                                                      Symbol* message)
 {
   ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::new_entry(hash, pool);
   entry->set_cp_index(cp_index);
-  NOT_PRODUCT(entry->set_error(NULL);)
   entry->set_error(error);
+  entry->set_message(message);
 
   return entry;
 }
@@ -79,6 +87,7 @@
   // decrement error refcount
   assert(entry->error() != NULL, "error should be set");
   entry->error()->decrement_refcount();
+  entry->message()->decrement_refcount();
   Hashtable<ConstantPool*, mtClass>::free_entry(entry);
 }
 
--- a/src/share/vm/classfile/resolutionErrors.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/classfile/resolutionErrors.hpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2014, 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
@@ -38,7 +38,8 @@
 public:
   ResolutionErrorTable(int table_size);
 
-  ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index, Symbol* error);
+  ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index,
+                                  Symbol* error, Symbol* message);
   void free_entry(ResolutionErrorEntry *entry);
 
   ResolutionErrorEntry* bucket(int i) {
@@ -55,7 +56,7 @@
   }
 
   void add_entry(int index, unsigned int hash,
-                 constantPoolHandle pool, int which, Symbol* error);
+                 constantPoolHandle pool, int which, Symbol* error, Symbol* message);
 
 
   // find error given the constant pool and constant pool index
@@ -79,10 +80,10 @@
  private:
   int               _cp_index;
   Symbol*           _error;
+  Symbol*           _message;
 
  public:
-  ConstantPool*      pool() const               { return (ConstantPool*)literal(); }
-  ConstantPool**   pool_addr()                { return (ConstantPool**)literal_addr(); }
+  ConstantPool*      pool() const               { return literal(); }
 
   int                cp_index() const           { return _cp_index; }
   void               set_cp_index(int cp_index) { _cp_index = cp_index; }
@@ -90,6 +91,9 @@
   Symbol*            error() const              { return _error; }
   void               set_error(Symbol* e);
 
+  Symbol*            message() const            { return _message; }
+  void               set_message(Symbol* c);
+
   ResolutionErrorEntry* next() const {
     return (ResolutionErrorEntry*)HashtableEntry<ConstantPool*, mtClass>::next();
   }
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed May 07 18:19:31 2014 -0400
@@ -172,12 +172,14 @@
   if (HAS_PENDING_EXCEPTION || klass == NULL) {
     KlassHandle k_h(THREAD, klass);
     // can return a null klass
-    klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
+    klass = handle_resolution_exception(class_name, throw_error, k_h, THREAD);
   }
   return klass;
 }
 
-Klass* SystemDictionary::handle_resolution_exception(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, KlassHandle klass_h, TRAPS) {
+Klass* SystemDictionary::handle_resolution_exception(Symbol* class_name,
+                                                     bool throw_error,
+                                                     KlassHandle klass_h, TRAPS) {
   if (HAS_PENDING_EXCEPTION) {
     // If we have a pending exception we forward it to the caller, unless throw_error is true,
     // in which case we have to check whether the pending exception is a ClassNotFoundException,
@@ -385,7 +387,7 @@
   }
   if (HAS_PENDING_EXCEPTION || superk_h() == NULL) {
     // can null superk
-    superk_h = KlassHandle(THREAD, handle_resolution_exception(class_name, class_loader, protection_domain, true, superk_h, THREAD));
+    superk_h = KlassHandle(THREAD, handle_resolution_exception(class_name, true, superk_h, THREAD));
   }
 
   return superk_h();
@@ -2111,12 +2113,13 @@
 
 // Add entry to resolution error table to record the error when the first
 // attempt to resolve a reference to a class has failed.
-void SystemDictionary::add_resolution_error(constantPoolHandle pool, int which, Symbol* error) {
+void SystemDictionary::add_resolution_error(constantPoolHandle pool, int which,
+                                            Symbol* error, Symbol* message) {
   unsigned int hash = resolution_errors()->compute_hash(pool, which);
   int index = resolution_errors()->hash_to_index(hash);
   {
     MutexLocker ml(SystemDictionary_lock, Thread::current());
-    resolution_errors()->add_entry(index, hash, pool, which, error);
+    resolution_errors()->add_entry(index, hash, pool, which, error, message);
   }
 }
 
@@ -2126,13 +2129,19 @@
 }
 
 // Lookup resolution error table. Returns error if found, otherwise NULL.
-Symbol* SystemDictionary::find_resolution_error(constantPoolHandle pool, int which) {
+Symbol* SystemDictionary::find_resolution_error(constantPoolHandle pool, int which,
+                                                Symbol** message) {
   unsigned int hash = resolution_errors()->compute_hash(pool, which);
   int index = resolution_errors()->hash_to_index(hash);
   {
     MutexLocker ml(SystemDictionary_lock, Thread::current());
     ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
-    return (entry != NULL) ? entry->error() : (Symbol*)NULL;
+    if (entry != NULL) {
+      *message = entry->message();
+      return entry->error();
+    } else {
+      return NULL;
+    }
   }
 }
 
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed May 07 18:19:31 2014 -0400
@@ -227,7 +227,7 @@
   static Klass* resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS);
 private:
   // handle error translation for resolve_or_null results
-  static Klass* handle_resolution_exception(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, KlassHandle klass_h, TRAPS);
+  static Klass* handle_resolution_exception(Symbol* class_name, bool throw_error, KlassHandle klass_h, TRAPS);
 
 public:
 
@@ -529,9 +529,11 @@
 
   // Record the error when the first attempt to resolve a reference from a constant
   // pool entry to a class fails.
-  static void add_resolution_error(constantPoolHandle pool, int which, Symbol* error);
+  static void add_resolution_error(constantPoolHandle pool, int which, Symbol* error,
+                                   Symbol* message);
   static void delete_resolution_error(ConstantPool* pool);
-  static Symbol* find_resolution_error(constantPoolHandle pool, int which);
+  static Symbol* find_resolution_error(constantPoolHandle pool, int which,
+                                       Symbol** message);
 
  private:
 
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -223,12 +223,6 @@
   }
 }
 
-void ConcurrentMarkSweepThread::print_on(outputStream* st) const {
-  st->print("\"%s\" ", name());
-  Thread::print_on(st);
-  st->cr();
-}
-
 void ConcurrentMarkSweepThread::print_all_on(outputStream* st) {
   if (_cmst != NULL) {
     _cmst->print_on(st);
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -94,8 +94,6 @@
   static void threads_do(ThreadClosure* tc);
 
   // Printing
-  void print_on(outputStream* st) const;
-  void print() const                                  { print_on(tty); }
   static void print_all_on(outputStream* st);
   static void print_all()                             { print_all_on(tty); }
 
--- a/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -58,6 +58,9 @@
   }
   initialize();
   create_and_start();
+
+  // set name
+  set_name("G1 Concurrent Refinement Thread#%d", worker_id);
 }
 
 void ConcurrentG1RefineThread::initialize() {
@@ -247,12 +250,3 @@
   }
 }
 
-void ConcurrentG1RefineThread::print() const {
-  print_on(tty);
-}
-
-void ConcurrentG1RefineThread::print_on(outputStream* st) const {
-  st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id);
-  Thread::print_on(st);
-  st->cr();
-}
--- a/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -77,10 +77,6 @@
 
   void initialize();
 
-  // Printing
-  void print() const;
-  void print_on(outputStream* st) const;
-
   // Total virtual time so far.
   double vtime_accum() { return _vtime_accum; }
 
--- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -46,6 +46,8 @@
   _in_progress(false),
   _vtime_accum(0.0),
   _vtime_mark_accum(0.0) {
+
+  set_name("G1 Main Concurrent Mark GC Thread");
   create_and_start();
 }
 
@@ -322,16 +324,6 @@
   }
 }
 
-void ConcurrentMarkThread::print() const {
-  print_on(tty);
-}
-
-void ConcurrentMarkThread::print_on(outputStream* st) const {
-  st->print("\"G1 Main Concurrent Mark GC Thread\" ");
-  Thread::print_on(st);
-  st->cr();
-}
-
 void ConcurrentMarkThread::sleepBeforeNextCycle() {
   // We join here because we don't want to do the "shouldConcurrentMark()"
   // below while the world is otherwise stopped.
--- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -60,10 +60,6 @@
   static void makeSurrogateLockerThread(TRAPS);
   static SurrogateLockerThread* slt() { return _slt; }
 
-  // Printing
-  void print_on(outputStream* st) const;
-  void print() const;
-
   // Total virtual time so far.
   double vtime_accum();
   // Marking virtual time so far
--- a/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -53,12 +53,6 @@
   return _thread;
 }
 
-void G1StringDedupThread::print_on(outputStream* st) const {
-  st->print("\"%s\" ", name());
-  Thread::print_on(st);
-  st->cr();
-}
-
 void G1StringDedupThread::run() {
   G1StringDedupStat total_stat;
 
--- a/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -52,7 +52,6 @@
   static G1StringDedupThread* thread();
 
   virtual void run();
-  virtual void print_on(outputStream* st) const;
 };
 
 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
--- a/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -87,12 +87,6 @@
   _time_stamp_index = 0;
 }
 
-void GCTaskThread::print_on(outputStream* st) const {
-  st->print("\"%s\" ", name());
-  Thread::print_on(st);
-  st->cr();
-}
-
 // GC workers get tasks from the GCTaskManager and execute
 // them in this method.  If there are no tasks to execute,
 // the GC workers wait in the GCTaskManager's get_task()
--- a/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -69,8 +69,6 @@
   void start();
 
   void print_task_time_stamps();
-  void print_on(outputStream* st) const;
-  void print() const                                { print_on(tty); }
 
 protected:
   // Constructor.  Clients use factory, but there could be subclasses.
--- a/src/share/vm/memory/binaryTreeDictionary.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/memory/binaryTreeDictionary.cpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2014, 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
@@ -120,7 +120,7 @@
   // chunk.
 
   TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
-  if (surplus() <= 0) {
+  if (curTL->surplus() <= 0) {
     /* Use the hint to find a size with a surplus, and reset the hint. */
     TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
     while (hintTL->hint() != 0) {
--- a/src/share/vm/oops/constantPool.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/oops/constantPool.cpp	Wed May 07 18:19:31 2014 -0400
@@ -223,14 +223,14 @@
 
 
   // The original attempt to resolve this constant pool entry failed so find the
-  // original error and throw it again (JVMS 5.4.3).
+  // class of the original error and throw another error of the same class (JVMS 5.4.3).
+  // If there is a detail message, pass that detail message to the error constructor.
+  // The JVMS does not strictly require us to duplicate the same detail message,
+  // or any internal exception fields such as cause or stacktrace.  But since the
+  // detail message is often a class name or other literal string, we will repeat it if
+  // we can find it in the symbol table.
   if (in_error) {
-    Symbol* error = SystemDictionary::find_resolution_error(this_cp, which);
-    guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
-    ResourceMark rm;
-    // exception text will be the class name
-    const char* className = this_cp->unresolved_klass_at(which)->as_C_string();
-    THROW_MSG_0(error, className);
+    throw_resolution_error(this_cp, which, CHECK_0);
   }
 
   if (do_resolve) {
@@ -250,11 +250,6 @@
     // Failed to resolve class. We must record the errors so that subsequent attempts
     // to resolve this constant pool entry fail with the same error (JVMS 5.4.3).
     if (HAS_PENDING_EXCEPTION) {
-      ResourceMark rm;
-      Symbol* error = PENDING_EXCEPTION->klass()->name();
-
-      bool throw_orig_error = false;
-      {
         MonitorLockerEx ml(this_cp->lock());
 
         // some other thread has beaten us and has resolved the class.
@@ -264,32 +259,9 @@
           return entry.get_klass();
         }
 
-        if (!PENDING_EXCEPTION->
-              is_a(SystemDictionary::LinkageError_klass())) {
-          // Just throw the exception and don't prevent these classes from
-          // being loaded due to virtual machine errors like StackOverflow
-          // and OutOfMemoryError, etc, or if the thread was hit by stop()
-          // Needs clarification to section 5.4.3 of the VM spec (see 6308271)
-        }
-        else if (!this_cp->tag_at(which).is_unresolved_klass_in_error()) {
-          SystemDictionary::add_resolution_error(this_cp, which, error);
-          this_cp->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError);
-        } else {
-          // some other thread has put the class in error state.
-          error = SystemDictionary::find_resolution_error(this_cp, which);
-          assert(error != NULL, "checking");
-          throw_orig_error = true;
-        }
-      } // unlocked
-
-      if (throw_orig_error) {
-        CLEAR_PENDING_EXCEPTION;
-        ResourceMark rm;
-        const char* className = this_cp->unresolved_klass_at(which)->as_C_string();
-        THROW_MSG_0(error, className);
-      }
-
-      return 0;
+        // The tag could have changed to in-error before the lock but we have to
+        // handle that here for the class case.
+        save_and_throw_exception(this_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_0);
     }
 
     if (TraceClassResolution && !k()->oop_is_array()) {
@@ -587,16 +559,55 @@
   return true;
 }
 
-// If resolution for MethodHandle or MethodType fails, save the exception
+Symbol* ConstantPool::exception_message(constantPoolHandle this_cp, int which, constantTag tag, oop pending_exception) {
+  // Dig out the detailed message to reuse if possible
+  Symbol* message = NULL;
+  oop detailed_message = java_lang_Throwable::message(pending_exception);
+  if (detailed_message != NULL) {
+     message = java_lang_String::as_symbol_or_null(detailed_message);
+     if (message != NULL) {
+       return message;
+     }
+  }
+
+  // Return specific message for the tag
+  switch (tag.value()) {
+  case JVM_CONSTANT_UnresolvedClass:
+    // return the class name in the error message
+    message = this_cp->unresolved_klass_at(which);
+    break;
+  case JVM_CONSTANT_MethodHandle:
+    // return the method handle name in the error message
+    message = this_cp->method_handle_name_ref_at(which);
+    break;
+  case JVM_CONSTANT_MethodType:
+    // return the method type signature in the error message
+    message = this_cp->method_type_signature_at(which);
+    break;
+  default:
+    ShouldNotReachHere();
+  }
+
+  return message;
+}
+
+void ConstantPool::throw_resolution_error(constantPoolHandle this_cp, int which, TRAPS) {
+  Symbol* message = NULL;
+  Symbol* error = SystemDictionary::find_resolution_error(this_cp, which, &message);
+  assert(error != NULL && message != NULL, "checking");
+  CLEAR_PENDING_EXCEPTION;
+  ResourceMark rm;
+  THROW_MSG(error, message->as_C_string());
+}
+
+// If resolution for Class, MethodHandle or MethodType fails, save the exception
 // in the resolution error table, so that the same exception is thrown again.
 void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int which,
-                                     int tag, TRAPS) {
-  ResourceMark rm;
+                                            constantTag tag, TRAPS) {
+  assert(this_cp->lock()->is_locked(), "constant pool lock should be held");
   Symbol* error = PENDING_EXCEPTION->klass()->name();
-  MonitorLockerEx ml(this_cp->lock());  // lock cpool to change tag.
 
-  int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
-           JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
+  int error_tag = tag.error_value();
 
   if (!PENDING_EXCEPTION->
     is_a(SystemDictionary::LinkageError_klass())) {
@@ -604,20 +615,21 @@
     // being loaded due to virtual machine errors like StackOverflow
     // and OutOfMemoryError, etc, or if the thread was hit by stop()
     // Needs clarification to section 5.4.3 of the VM spec (see 6308271)
-
   } else if (this_cp->tag_at(which).value() != error_tag) {
-    SystemDictionary::add_resolution_error(this_cp, which, error);
+    Symbol* message = exception_message(this_cp, which, tag, PENDING_EXCEPTION);
+    SystemDictionary::add_resolution_error(this_cp, which, error, message);
     this_cp->tag_at_put(which, error_tag);
   } else {
-    // some other thread has put the class in error state.
-    error = SystemDictionary::find_resolution_error(this_cp, which);
-    assert(error != NULL, "checking");
-    CLEAR_PENDING_EXCEPTION;
-    THROW_MSG(error, "");
+    // some other thread put this in error state
+    throw_resolution_error(this_cp, which, CHECK);
   }
+
+  // This exits with some pending exception
+  assert(HAS_PENDING_EXCEPTION, "should not be cleared");
 }
 
 
+
 // Called to resolve constants in the constant pool and return an oop.
 // Some constant pool entries cache their resolved oop. This is also
 // called to create oops from constants to use in arguments for invokedynamic
@@ -645,9 +657,9 @@
 
   jvalue prim_value;  // temp used only in a few cases below
 
-  int tag_value = this_cp->tag_at(index).value();
+  constantTag tag = this_cp->tag_at(index);
 
-  switch (tag_value) {
+  switch (tag.value()) {
 
   case JVM_CONSTANT_UnresolvedClass:
   case JVM_CONSTANT_UnresolvedClassInError:
@@ -672,10 +684,7 @@
   case JVM_CONSTANT_MethodHandleInError:
   case JVM_CONSTANT_MethodTypeInError:
     {
-      Symbol* error = SystemDictionary::find_resolution_error(this_cp, index);
-      guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
-      ResourceMark rm;
-      THROW_MSG_0(error, "");
+      throw_resolution_error(this_cp, index, CHECK_NULL);
       break;
     }
 
@@ -699,7 +708,8 @@
                                                                    THREAD);
       result_oop = value();
       if (HAS_PENDING_EXCEPTION) {
-        save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL);
+        MonitorLockerEx ml(this_cp->lock());  // lock cpool to change tag.
+        save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
       }
       break;
     }
@@ -715,7 +725,8 @@
       Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
       result_oop = value();
       if (HAS_PENDING_EXCEPTION) {
-        save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL);
+        MonitorLockerEx ml(this_cp->lock());  // lock cpool to change tag.
+        save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
       }
       break;
     }
@@ -746,7 +757,7 @@
 
   default:
     DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
-                              this_cp(), index, cache_index, tag_value) );
+                              this_cp(), index, cache_index, tag.value()));
     assert(false, "unexpected constant tag");
     break;
   }
--- a/src/share/vm/oops/constantPool.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/oops/constantPool.hpp	Wed May 07 18:19:31 2014 -0400
@@ -822,9 +822,13 @@
   static void resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS);
 
   static oop resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS);
-  static void save_and_throw_exception(constantPoolHandle this_cp, int which, int tag_value, TRAPS);
   static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS);
 
+  // Exception handling
+  static void throw_resolution_error(constantPoolHandle this_cp, int which, TRAPS);
+  static Symbol* exception_message(constantPoolHandle this_cp, int which, constantTag tag, oop pending_exception);
+  static void save_and_throw_exception(constantPoolHandle this_cp, int which, constantTag tag, TRAPS);
+
  public:
   // Merging ConstantPool* support:
   bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
--- a/src/share/vm/runtime/thread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/runtime/thread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -1198,6 +1198,13 @@
   va_end(ap);
 }
 
+void NamedThread::print_on(outputStream* st) const {
+  st->print("\"%s\" ", name());
+  Thread::print_on(st);
+  st->cr();
+}
+
+
 // ======= WatcherThread ========
 
 // The watcher thread exists to simulate timer interrupts.  It should
--- a/src/share/vm/runtime/thread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/runtime/thread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -566,7 +566,7 @@
   void    set_lgrp_id(int value) { _lgrp_id = value; }
 
   // Printing
-  void print_on(outputStream* st) const;
+  virtual void print_on(outputStream* st) const;
   void print() const { print_on(tty); }
   virtual void print_on_error(outputStream* st, char* buf, int buflen) const;
 
@@ -700,6 +700,7 @@
   virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
   JavaThread *processed_thread() { return _processed_thread; }
   void set_processed_thread(JavaThread *thread) { _processed_thread = thread; }
+  virtual void print_on(outputStream* st) const;
 };
 
 // Worker threads are named and have an id of an assigned work.
@@ -746,7 +747,6 @@
   // Printing
   char* name() const { return (char*)"VM Periodic Task Thread"; }
   void print_on(outputStream* st) const;
-  void print() const { print_on(tty); }
   void unpark();
 
   // Returns the single instance of WatcherThread
@@ -1459,7 +1459,6 @@
   // Misc. operations
   char* name() const { return (char*)get_thread_name(); }
   void print_on(outputStream* st) const;
-  void print() const { print_on(tty); }
   void print_value();
   void print_thread_state_on(outputStream* ) const      PRODUCT_RETURN;
   void print_thread_state() const                       PRODUCT_RETURN;
--- a/src/share/vm/runtime/vmThread.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/runtime/vmThread.cpp	Wed May 07 18:19:31 2014 -0400
@@ -339,12 +339,6 @@
   }
 }
 
-void VMThread::print_on(outputStream* st) const {
-  st->print("\"%s\" ", name());
-  Thread::print_on(st);
-  st->cr();
-}
-
 void VMThread::evaluate_operation(VM_Operation* op) {
   ResourceMark rm;
 
--- a/src/share/vm/runtime/vmThread.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/runtime/vmThread.hpp	Wed May 07 18:19:31 2014 -0400
@@ -128,9 +128,6 @@
   // GC support
   void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf);
 
-  // Debugging
-  void print_on(outputStream* st) const;
-  void print() const                              { print_on(tty); }
   void verify();
 
   // Performance measurement
--- a/src/share/vm/utilities/constantTag.cpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/utilities/constantTag.cpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -76,6 +76,20 @@
 }
 
 
+jbyte constantTag::error_value() const {
+  switch (_tag) {
+  case JVM_CONSTANT_UnresolvedClass:
+    return JVM_CONSTANT_UnresolvedClassInError;
+  case JVM_CONSTANT_MethodHandle:
+    return JVM_CONSTANT_MethodHandleInError;
+  case JVM_CONSTANT_MethodType:
+    return JVM_CONSTANT_MethodTypeInError;
+  default:
+    ShouldNotReachHere();
+    return JVM_CONSTANT_Invalid;
+  }
+}
+
 const char* constantTag::internal_name() const {
   switch (_tag) {
     case JVM_CONSTANT_Invalid :
--- a/src/share/vm/utilities/constantTag.hpp	Fri May 02 19:00:04 2014 -0700
+++ b/src/share/vm/utilities/constantTag.hpp	Wed May 07 18:19:31 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -109,6 +109,7 @@
   }
 
   jbyte value() const                { return _tag; }
+  jbyte error_value() const;
   jbyte non_error_value() const;
 
   BasicType basic_type() const;        // if used with ldc, what kind of value gets pushed?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassResolutionFail/Property.java	Wed May 07 18:19:31 2014 -0400
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Class PropertySuper is not found.
+
+public class Property extends PropertySuper {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassResolutionFail/PropertySuper.java	Wed May 07 18:19:31 2014 -0400
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Class PropertySuper should be removed.
+
+public class PropertySuper {
+  PropertySuper() { System.out.println("remove me for NoClassDefFoundError"); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/ClassResolutionFail/TestClassResolutionFail.java	Wed May 07 18:19:31 2014 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestClassResolutionFail
+ * @bug 8023697
+ * @summary This tests that failed class resolution doesn't report different class name in detail message for the first and subsequent times
+ */
+
+import java.io.File;
+
+public class TestClassResolutionFail {
+    static String message;
+    public static void test1() throws RuntimeException {
+        try {
+            Property p = new Property();
+        } catch (LinkageError e) {
+            message = e.getMessage();
+        }
+        try {
+            Property p = new Property();
+        } catch (LinkageError e) {
+            System.out.println(e.getMessage());
+            if (!e.getMessage().equals(message)) {
+                throw new RuntimeException("Wrong message: " + message + " != " + e.getMessage());
+            }
+        }
+    }
+    public static void main(java.lang.String[] unused) throws Exception {
+        // Remove PropertySuper class
+        String testClasses = System.getProperty("test.classes", ".");
+        File f = new File(testClasses + File.separator + "PropertySuper.class");
+        f.delete();
+        test1();
+    }
+}
+