mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
Merge
This commit is contained in:
commit
39f7049fbb
29 changed files with 270 additions and 390 deletions
|
@ -5271,7 +5271,6 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
|
||||||
//
|
//
|
||||||
|
|
||||||
static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
|
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();
|
pid_t tid = thread->osthread()->thread_id();
|
||||||
char *s;
|
char *s;
|
||||||
char stat[2048];
|
char stat[2048];
|
||||||
|
@ -5284,24 +5283,7 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
|
||||||
long ldummy;
|
long ldummy;
|
||||||
FILE *fp;
|
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);
|
snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid);
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fp = fopen(proc_name, "r");
|
fp = fopen(proc_name, "r");
|
||||||
if ( fp == NULL ) return -1;
|
if ( fp == NULL ) return -1;
|
||||||
statlen = fread(stat, 1, 2047, fp);
|
statlen = fread(stat, 1, 2047, fp);
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -89,200 +89,6 @@ char *FileBuff::get_line(void) {
|
||||||
return retval;
|
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-------------------------------------
|
//------------------------------file_error-------------------------------------
|
||||||
void FileBuff::file_error(int flag, int linenum, const char *fmt, ...)
|
void FileBuff::file_error(int flag, int linenum, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -46,7 +46,6 @@ class ArchDesc;
|
||||||
// This class defines a nicely behaved buffer of text. Entire file of text
|
// 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.
|
// is read into buffer at creation, with sentinels at start and end.
|
||||||
class FileBuff {
|
class FileBuff {
|
||||||
friend class FileBuffRegion;
|
|
||||||
private:
|
private:
|
||||||
long _bufferSize; // Size of text holding buffer.
|
long _bufferSize; // Size of text holding buffer.
|
||||||
long _offset; // Expected filepointer offset.
|
long _offset; // Expected filepointer offset.
|
||||||
|
@ -82,29 +81,4 @@ class FileBuff {
|
||||||
// when the pointer is valid (i.e. just obtained from getline()).
|
// when the pointer is valid (i.e. just obtained from getline()).
|
||||||
long getoff(const char* s) { return _bufoff + (long)(s - _buf); }
|
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
|
#endif // SHARE_VM_ADLC_FILEBUFF_HPP
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -32,12 +32,13 @@
|
||||||
|
|
||||||
// add new entry to the table
|
// add new entry to the table
|
||||||
void ResolutionErrorTable::add_entry(int index, unsigned int hash,
|
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_locked_or_safepoint(SystemDictionary_lock);
|
||||||
assert(!pool.is_null() && error != NULL, "adding NULL obj");
|
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);
|
add_entry(index, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,19 +59,26 @@ ResolutionErrorEntry* ResolutionErrorTable::find_entry(int index, unsigned int h
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResolutionErrorEntry::set_error(Symbol* e) {
|
void ResolutionErrorEntry::set_error(Symbol* e) {
|
||||||
assert(e == NULL || _error == NULL, "cannot reset error");
|
assert(e != NULL, "must set a value");
|
||||||
_error = e;
|
_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
|
// create new error entry
|
||||||
ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool,
|
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);
|
ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::new_entry(hash, pool);
|
||||||
entry->set_cp_index(cp_index);
|
entry->set_cp_index(cp_index);
|
||||||
NOT_PRODUCT(entry->set_error(NULL);)
|
|
||||||
entry->set_error(error);
|
entry->set_error(error);
|
||||||
|
entry->set_message(message);
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +87,7 @@ void ResolutionErrorTable::free_entry(ResolutionErrorEntry *entry) {
|
||||||
// decrement error refcount
|
// decrement error refcount
|
||||||
assert(entry->error() != NULL, "error should be set");
|
assert(entry->error() != NULL, "error should be set");
|
||||||
entry->error()->decrement_refcount();
|
entry->error()->decrement_refcount();
|
||||||
|
entry->message()->decrement_refcount();
|
||||||
Hashtable<ConstantPool*, mtClass>::free_entry(entry);
|
Hashtable<ConstantPool*, mtClass>::free_entry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -38,7 +38,8 @@ class ResolutionErrorTable : public Hashtable<ConstantPool*, mtClass> {
|
||||||
public:
|
public:
|
||||||
ResolutionErrorTable(int table_size);
|
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);
|
void free_entry(ResolutionErrorEntry *entry);
|
||||||
|
|
||||||
ResolutionErrorEntry* bucket(int i) {
|
ResolutionErrorEntry* bucket(int i) {
|
||||||
|
@ -55,7 +56,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_entry(int index, unsigned int hash,
|
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
|
// find error given the constant pool and constant pool index
|
||||||
|
@ -79,10 +80,10 @@ class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
|
||||||
private:
|
private:
|
||||||
int _cp_index;
|
int _cp_index;
|
||||||
Symbol* _error;
|
Symbol* _error;
|
||||||
|
Symbol* _message;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConstantPool* pool() const { return (ConstantPool*)literal(); }
|
ConstantPool* pool() const { return literal(); }
|
||||||
ConstantPool** pool_addr() { return (ConstantPool**)literal_addr(); }
|
|
||||||
|
|
||||||
int cp_index() const { return _cp_index; }
|
int cp_index() const { return _cp_index; }
|
||||||
void set_cp_index(int cp_index) { _cp_index = cp_index; }
|
void set_cp_index(int cp_index) { _cp_index = cp_index; }
|
||||||
|
@ -90,6 +91,9 @@ class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
|
||||||
Symbol* error() const { return _error; }
|
Symbol* error() const { return _error; }
|
||||||
void set_error(Symbol* e);
|
void set_error(Symbol* e);
|
||||||
|
|
||||||
|
Symbol* message() const { return _message; }
|
||||||
|
void set_message(Symbol* c);
|
||||||
|
|
||||||
ResolutionErrorEntry* next() const {
|
ResolutionErrorEntry* next() const {
|
||||||
return (ResolutionErrorEntry*)HashtableEntry<ConstantPool*, mtClass>::next();
|
return (ResolutionErrorEntry*)HashtableEntry<ConstantPool*, mtClass>::next();
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,12 +172,14 @@ Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_loader
|
||||||
if (HAS_PENDING_EXCEPTION || klass == NULL) {
|
if (HAS_PENDING_EXCEPTION || klass == NULL) {
|
||||||
KlassHandle k_h(THREAD, klass);
|
KlassHandle k_h(THREAD, klass);
|
||||||
// can return a null 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;
|
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 (HAS_PENDING_EXCEPTION) {
|
||||||
// If we have a pending exception we forward it to the caller, unless throw_error is true,
|
// 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,
|
// in which case we have to check whether the pending exception is a ClassNotFoundException,
|
||||||
|
@ -385,7 +387,7 @@ Klass* SystemDictionary::resolve_super_or_fail(Symbol* child_name,
|
||||||
}
|
}
|
||||||
if (HAS_PENDING_EXCEPTION || superk_h() == NULL) {
|
if (HAS_PENDING_EXCEPTION || superk_h() == NULL) {
|
||||||
// can null superk
|
// 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();
|
return superk_h();
|
||||||
|
@ -2111,12 +2113,13 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name,
|
||||||
|
|
||||||
// Add entry to resolution error table to record the error when the first
|
// Add entry to resolution error table to record the error when the first
|
||||||
// attempt to resolve a reference to a class has failed.
|
// 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);
|
unsigned int hash = resolution_errors()->compute_hash(pool, which);
|
||||||
int index = resolution_errors()->hash_to_index(hash);
|
int index = resolution_errors()->hash_to_index(hash);
|
||||||
{
|
{
|
||||||
MutexLocker ml(SystemDictionary_lock, Thread::current());
|
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 @@ void SystemDictionary::delete_resolution_error(ConstantPool* pool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup resolution error table. Returns error if found, otherwise NULL.
|
// 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);
|
unsigned int hash = resolution_errors()->compute_hash(pool, which);
|
||||||
int index = resolution_errors()->hash_to_index(hash);
|
int index = resolution_errors()->hash_to_index(hash);
|
||||||
{
|
{
|
||||||
MutexLocker ml(SystemDictionary_lock, Thread::current());
|
MutexLocker ml(SystemDictionary_lock, Thread::current());
|
||||||
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ class SystemDictionary : AllStatic {
|
||||||
static Klass* resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS);
|
static Klass* resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS);
|
||||||
private:
|
private:
|
||||||
// handle error translation for resolve_or_null results
|
// 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:
|
public:
|
||||||
|
|
||||||
|
@ -529,9 +529,11 @@ public:
|
||||||
|
|
||||||
// Record the error when the first attempt to resolve a reference from a constant
|
// Record the error when the first attempt to resolve a reference from a constant
|
||||||
// pool entry to a class fails.
|
// 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 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:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -223,12 +223,6 @@ void ConcurrentMarkSweepThread::threads_do(ThreadClosure* tc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConcurrentMarkSweepThread::print_on(outputStream* st) const {
|
|
||||||
st->print("\"%s\" ", name());
|
|
||||||
Thread::print_on(st);
|
|
||||||
st->cr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConcurrentMarkSweepThread::print_all_on(outputStream* st) {
|
void ConcurrentMarkSweepThread::print_all_on(outputStream* st) {
|
||||||
if (_cmst != NULL) {
|
if (_cmst != NULL) {
|
||||||
_cmst->print_on(st);
|
_cmst->print_on(st);
|
||||||
|
|
|
@ -94,8 +94,6 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
|
||||||
static void threads_do(ThreadClosure* tc);
|
static void threads_do(ThreadClosure* tc);
|
||||||
|
|
||||||
// Printing
|
// Printing
|
||||||
void print_on(outputStream* st) const;
|
|
||||||
void print() const { print_on(tty); }
|
|
||||||
static void print_all_on(outputStream* st);
|
static void print_all_on(outputStream* st);
|
||||||
static void print_all() { print_all_on(tty); }
|
static void print_all() { print_all_on(tty); }
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,9 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex
|
||||||
}
|
}
|
||||||
initialize();
|
initialize();
|
||||||
create_and_start();
|
create_and_start();
|
||||||
|
|
||||||
|
// set name
|
||||||
|
set_name("G1 Concurrent Refinement Thread#%d", worker_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConcurrentG1RefineThread::initialize() {
|
void ConcurrentG1RefineThread::initialize() {
|
||||||
|
@ -247,12 +250,3 @@ void ConcurrentG1RefineThread::stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -77,10 +77,6 @@ public:
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
// Printing
|
|
||||||
void print() const;
|
|
||||||
void print_on(outputStream* st) const;
|
|
||||||
|
|
||||||
// Total virtual time so far.
|
// Total virtual time so far.
|
||||||
double vtime_accum() { return _vtime_accum; }
|
double vtime_accum() { return _vtime_accum; }
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
|
||||||
_in_progress(false),
|
_in_progress(false),
|
||||||
_vtime_accum(0.0),
|
_vtime_accum(0.0),
|
||||||
_vtime_mark_accum(0.0) {
|
_vtime_mark_accum(0.0) {
|
||||||
|
|
||||||
|
set_name("G1 Main Concurrent Mark GC Thread");
|
||||||
create_and_start();
|
create_and_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,16 +324,6 @@ void ConcurrentMarkThread::stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
void ConcurrentMarkThread::sleepBeforeNextCycle() {
|
||||||
// We join here because we don't want to do the "shouldConcurrentMark()"
|
// We join here because we don't want to do the "shouldConcurrentMark()"
|
||||||
// below while the world is otherwise stopped.
|
// below while the world is otherwise stopped.
|
||||||
|
|
|
@ -60,10 +60,6 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
|
||||||
static void makeSurrogateLockerThread(TRAPS);
|
static void makeSurrogateLockerThread(TRAPS);
|
||||||
static SurrogateLockerThread* slt() { return _slt; }
|
static SurrogateLockerThread* slt() { return _slt; }
|
||||||
|
|
||||||
// Printing
|
|
||||||
void print_on(outputStream* st) const;
|
|
||||||
void print() const;
|
|
||||||
|
|
||||||
// Total virtual time so far.
|
// Total virtual time so far.
|
||||||
double vtime_accum();
|
double vtime_accum();
|
||||||
// Marking virtual time so far
|
// Marking virtual time so far
|
||||||
|
|
|
@ -53,12 +53,6 @@ G1StringDedupThread* G1StringDedupThread::thread() {
|
||||||
return _thread;
|
return _thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1StringDedupThread::print_on(outputStream* st) const {
|
|
||||||
st->print("\"%s\" ", name());
|
|
||||||
Thread::print_on(st);
|
|
||||||
st->cr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1StringDedupThread::run() {
|
void G1StringDedupThread::run() {
|
||||||
G1StringDedupStat total_stat;
|
G1StringDedupStat total_stat;
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ public:
|
||||||
static G1StringDedupThread* thread();
|
static G1StringDedupThread* thread();
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
virtual void print_on(outputStream* st) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
|
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
|
||||||
|
|
|
@ -87,12 +87,6 @@ void GCTaskThread::print_task_time_stamps() {
|
||||||
_time_stamp_index = 0;
|
_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
|
// GC workers get tasks from the GCTaskManager and execute
|
||||||
// them in this method. If there are no tasks to execute,
|
// them in this method. If there are no tasks to execute,
|
||||||
// the GC workers wait in the GCTaskManager's get_task()
|
// the GC workers wait in the GCTaskManager's get_task()
|
||||||
|
|
|
@ -69,8 +69,6 @@ private:
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
void print_task_time_stamps();
|
void print_task_time_stamps();
|
||||||
void print_on(outputStream* st) const;
|
|
||||||
void print() const { print_on(tty); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Constructor. Clients use factory, but there could be subclasses.
|
// Constructor. Clients use factory, but there could be subclasses.
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -120,7 +120,7 @@ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
|
||||||
// chunk.
|
// chunk.
|
||||||
|
|
||||||
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
|
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. */
|
/* Use the hint to find a size with a surplus, and reset the hint. */
|
||||||
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
|
TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
|
||||||
while (hintTL->hint() != 0) {
|
while (hintTL->hint() != 0) {
|
||||||
|
|
|
@ -223,14 +223,14 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS)
|
||||||
|
|
||||||
|
|
||||||
// The original attempt to resolve this constant pool entry failed so find the
|
// 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) {
|
if (in_error) {
|
||||||
Symbol* error = SystemDictionary::find_resolution_error(this_cp, which);
|
throw_resolution_error(this_cp, which, CHECK_0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_resolve) {
|
if (do_resolve) {
|
||||||
|
@ -250,11 +250,6 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS)
|
||||||
// Failed to resolve class. We must record the errors so that subsequent attempts
|
// 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).
|
// to resolve this constant pool entry fail with the same error (JVMS 5.4.3).
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
ResourceMark rm;
|
|
||||||
Symbol* error = PENDING_EXCEPTION->klass()->name();
|
|
||||||
|
|
||||||
bool throw_orig_error = false;
|
|
||||||
{
|
|
||||||
MonitorLockerEx ml(this_cp->lock());
|
MonitorLockerEx ml(this_cp->lock());
|
||||||
|
|
||||||
// some other thread has beaten us and has resolved the class.
|
// some other thread has beaten us and has resolved the class.
|
||||||
|
@ -264,32 +259,9 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS)
|
||||||
return entry.get_klass();
|
return entry.get_klass();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PENDING_EXCEPTION->
|
// The tag could have changed to in-error before the lock but we have to
|
||||||
is_a(SystemDictionary::LinkageError_klass())) {
|
// handle that here for the class case.
|
||||||
// Just throw the exception and don't prevent these classes from
|
save_and_throw_exception(this_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_0);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TraceClassResolution && !k()->oop_is_array()) {
|
if (TraceClassResolution && !k()->oop_is_array()) {
|
||||||
|
@ -587,16 +559,55 @@ bool ConstantPool::resolve_class_constants(TRAPS) {
|
||||||
return true;
|
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.
|
// in the resolution error table, so that the same exception is thrown again.
|
||||||
void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int which,
|
void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int which,
|
||||||
int tag, TRAPS) {
|
constantTag tag, TRAPS) {
|
||||||
ResourceMark rm;
|
assert(this_cp->lock()->is_locked(), "constant pool lock should be held");
|
||||||
Symbol* error = PENDING_EXCEPTION->klass()->name();
|
Symbol* error = PENDING_EXCEPTION->klass()->name();
|
||||||
MonitorLockerEx ml(this_cp->lock()); // lock cpool to change tag.
|
|
||||||
|
|
||||||
int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
|
int error_tag = tag.error_value();
|
||||||
JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
|
|
||||||
|
|
||||||
if (!PENDING_EXCEPTION->
|
if (!PENDING_EXCEPTION->
|
||||||
is_a(SystemDictionary::LinkageError_klass())) {
|
is_a(SystemDictionary::LinkageError_klass())) {
|
||||||
|
@ -604,20 +615,21 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int whic
|
||||||
// being loaded due to virtual machine errors like StackOverflow
|
// being loaded due to virtual machine errors like StackOverflow
|
||||||
// and OutOfMemoryError, etc, or if the thread was hit by stop()
|
// and OutOfMemoryError, etc, or if the thread was hit by stop()
|
||||||
// Needs clarification to section 5.4.3 of the VM spec (see 6308271)
|
// Needs clarification to section 5.4.3 of the VM spec (see 6308271)
|
||||||
|
|
||||||
} else if (this_cp->tag_at(which).value() != error_tag) {
|
} 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);
|
this_cp->tag_at_put(which, error_tag);
|
||||||
} else {
|
} else {
|
||||||
// some other thread has put the class in error state.
|
// some other thread put this in error state
|
||||||
error = SystemDictionary::find_resolution_error(this_cp, which);
|
throw_resolution_error(this_cp, which, CHECK);
|
||||||
assert(error != NULL, "checking");
|
|
||||||
CLEAR_PENDING_EXCEPTION;
|
|
||||||
THROW_MSG(error, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
// Called to resolve constants in the constant pool and return an oop.
|
||||||
// Some constant pool entries cache their resolved oop. This is also
|
// Some constant pool entries cache their resolved oop. This is also
|
||||||
// called to create oops from constants to use in arguments for invokedynamic
|
// called to create oops from constants to use in arguments for invokedynamic
|
||||||
|
@ -645,9 +657,9 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
|
||||||
|
|
||||||
jvalue prim_value; // temp used only in a few cases below
|
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_UnresolvedClass:
|
||||||
case JVM_CONSTANT_UnresolvedClassInError:
|
case JVM_CONSTANT_UnresolvedClassInError:
|
||||||
|
@ -672,10 +684,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
|
||||||
case JVM_CONSTANT_MethodHandleInError:
|
case JVM_CONSTANT_MethodHandleInError:
|
||||||
case JVM_CONSTANT_MethodTypeInError:
|
case JVM_CONSTANT_MethodTypeInError:
|
||||||
{
|
{
|
||||||
Symbol* error = SystemDictionary::find_resolution_error(this_cp, index);
|
throw_resolution_error(this_cp, index, CHECK_NULL);
|
||||||
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
|
|
||||||
ResourceMark rm;
|
|
||||||
THROW_MSG_0(error, "");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +708,8 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
|
||||||
THREAD);
|
THREAD);
|
||||||
result_oop = value();
|
result_oop = value();
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -715,7 +725,8 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
|
||||||
Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
|
Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
|
||||||
result_oop = value();
|
result_oop = value();
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -746,7 +757,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
|
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");
|
assert(false, "unexpected constant tag");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -822,9 +822,13 @@ class ConstantPool : public Metadata {
|
||||||
static void resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS);
|
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 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);
|
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:
|
public:
|
||||||
// Merging ConstantPool* support:
|
// Merging ConstantPool* support:
|
||||||
bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
|
bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
|
||||||
|
|
|
@ -1198,6 +1198,13 @@ void NamedThread::set_name(const char* format, ...) {
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NamedThread::print_on(outputStream* st) const {
|
||||||
|
st->print("\"%s\" ", name());
|
||||||
|
Thread::print_on(st);
|
||||||
|
st->cr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ======= WatcherThread ========
|
// ======= WatcherThread ========
|
||||||
|
|
||||||
// The watcher thread exists to simulate timer interrupts. It should
|
// The watcher thread exists to simulate timer interrupts. It should
|
||||||
|
|
|
@ -566,7 +566,7 @@ public:
|
||||||
void set_lgrp_id(int value) { _lgrp_id = value; }
|
void set_lgrp_id(int value) { _lgrp_id = value; }
|
||||||
|
|
||||||
// Printing
|
// Printing
|
||||||
void print_on(outputStream* st) const;
|
virtual void print_on(outputStream* st) const;
|
||||||
void print() const { print_on(tty); }
|
void print() const { print_on(tty); }
|
||||||
virtual void print_on_error(outputStream* st, char* buf, int buflen) const;
|
virtual void print_on_error(outputStream* st, char* buf, int buflen) const;
|
||||||
|
|
||||||
|
@ -700,6 +700,7 @@ class NamedThread: public Thread {
|
||||||
virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
|
virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
|
||||||
JavaThread *processed_thread() { return _processed_thread; }
|
JavaThread *processed_thread() { return _processed_thread; }
|
||||||
void set_processed_thread(JavaThread *thread) { _processed_thread = 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.
|
// Worker threads are named and have an id of an assigned work.
|
||||||
|
@ -746,7 +747,6 @@ class WatcherThread: public Thread {
|
||||||
// Printing
|
// Printing
|
||||||
char* name() const { return (char*)"VM Periodic Task Thread"; }
|
char* name() const { return (char*)"VM Periodic Task Thread"; }
|
||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
void print() const { print_on(tty); }
|
|
||||||
void unpark();
|
void unpark();
|
||||||
|
|
||||||
// Returns the single instance of WatcherThread
|
// Returns the single instance of WatcherThread
|
||||||
|
@ -1459,7 +1459,6 @@ class JavaThread: public Thread {
|
||||||
// Misc. operations
|
// Misc. operations
|
||||||
char* name() const { return (char*)get_thread_name(); }
|
char* name() const { return (char*)get_thread_name(); }
|
||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
void print() const { print_on(tty); }
|
|
||||||
void print_value();
|
void print_value();
|
||||||
void print_thread_state_on(outputStream* ) const PRODUCT_RETURN;
|
void print_thread_state_on(outputStream* ) const PRODUCT_RETURN;
|
||||||
void print_thread_state() const PRODUCT_RETURN;
|
void print_thread_state() const PRODUCT_RETURN;
|
||||||
|
|
|
@ -339,12 +339,6 @@ void VMThread::wait_for_vm_thread_exit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMThread::print_on(outputStream* st) const {
|
|
||||||
st->print("\"%s\" ", name());
|
|
||||||
Thread::print_on(st);
|
|
||||||
st->cr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VMThread::evaluate_operation(VM_Operation* op) {
|
void VMThread::evaluate_operation(VM_Operation* op) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
|
|
||||||
|
|
|
@ -128,9 +128,6 @@ class VMThread: public NamedThread {
|
||||||
// GC support
|
// GC support
|
||||||
void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf);
|
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();
|
void verify();
|
||||||
|
|
||||||
// Performance measurement
|
// Performance measurement
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -76,6 +76,20 @@ jbyte constantTag::non_error_value() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
const char* constantTag::internal_name() const {
|
||||||
switch (_tag) {
|
switch (_tag) {
|
||||||
case JVM_CONSTANT_Invalid :
|
case JVM_CONSTANT_Invalid :
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -109,6 +109,7 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
|
||||||
}
|
}
|
||||||
|
|
||||||
jbyte value() const { return _tag; }
|
jbyte value() const { return _tag; }
|
||||||
|
jbyte error_value() const;
|
||||||
jbyte non_error_value() const;
|
jbyte non_error_value() const;
|
||||||
|
|
||||||
BasicType basic_type() const; // if used with ldc, what kind of value gets pushed?
|
BasicType basic_type() const; // if used with ldc, what kind of value gets pushed?
|
||||||
|
|
27
hotspot/test/runtime/ClassResolutionFail/Property.java
Normal file
27
hotspot/test/runtime/ClassResolutionFail/Property.java
Normal file
|
@ -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 {
|
||||||
|
}
|
28
hotspot/test/runtime/ClassResolutionFail/PropertySuper.java
Normal file
28
hotspot/test/runtime/ClassResolutionFail/PropertySuper.java
Normal file
|
@ -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"); }
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue