Tue, 27 Mar 2012 15:28:52 -0400
Merge
1.1 --- a/make/bsd/makefiles/wb.make Fri Mar 23 22:34:22 2012 -0700 1.2 +++ b/make/bsd/makefiles/wb.make Tue Mar 27 15:28:52 2012 -0400 1.3 @@ -36,7 +36,7 @@ 1.4 $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) 1.5 1.6 $(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) 1.7 - $(REMOTE) $(COMPILE.JAVAC) -nowarn -d $(WB_JAVA_CLASSDIR) $< 1.8 + $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< 1.9 1.10 $(WB_JAR): $(WB_JAVA_CLASSES) 1.11 $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ .
2.1 --- a/make/linux/makefiles/wb.make Fri Mar 23 22:34:22 2012 -0700 2.2 +++ b/make/linux/makefiles/wb.make Tue Mar 27 15:28:52 2012 -0400 2.3 @@ -36,7 +36,7 @@ 2.4 $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) 2.5 2.6 $(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) 2.7 - $(REMOTE) $(COMPILE.JAVAC) -nowarn -d $(WB_JAVA_CLASSDIR) $< 2.8 + $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< 2.9 2.10 $(WB_JAR): $(WB_JAVA_CLASSES) 2.11 $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ .
3.1 --- a/make/solaris/makefiles/wb.make Fri Mar 23 22:34:22 2012 -0700 3.2 +++ b/make/solaris/makefiles/wb.make Tue Mar 27 15:28:52 2012 -0400 3.3 @@ -36,7 +36,7 @@ 3.4 $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) 3.5 3.6 $(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) 3.7 - $(REMOTE) $(COMPILE.JAVAC) -nowarn -d $(WB_JAVA_CLASSDIR) $< 3.8 + $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< 3.9 3.10 $(WB_JAR): $(WB_JAVA_CLASSES) 3.11 $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ .
4.1 --- a/make/windows/create_obj_files.sh Fri Mar 23 22:34:22 2012 -0700 4.2 +++ b/make/windows/create_obj_files.sh Tue Mar 27 15:28:52 2012 -0400 4.3 @@ -80,6 +80,8 @@ 4.4 BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr" 4.5 fi 4.6 4.7 +BASE_PATHS="${BASE_PATHS} ${COMMONSRC}/share/vm/prims/wbtestmethods" 4.8 + 4.9 CORE_PATHS="${BASE_PATHS}" 4.10 # shared is already in BASE_PATHS. Should add vm/memory but that one is also in BASE_PATHS. 4.11 if [ -d "${ALTSRC}/share/vm/gc_implementation" ]; then
5.1 --- a/make/windows/makefiles/projectcreator.make Fri Mar 23 22:34:22 2012 -0700 5.2 +++ b/make/windows/makefiles/projectcreator.make Tue Mar 27 15:28:52 2012 -0400 5.3 @@ -51,6 +51,7 @@ 5.4 -relativeInclude src\closed\cpu\$(Platform_arch)\vm \ 5.5 -relativeInclude src\share\vm \ 5.6 -relativeInclude src\share\vm\precompiled \ 5.7 + -relativeInclude src\share\vm\prims\wbtestmethods \ 5.8 -relativeInclude src\share\vm\prims \ 5.9 -relativeInclude src\os\windows\vm \ 5.10 -relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \
6.1 --- a/make/windows/makefiles/vm.make Fri Mar 23 22:34:22 2012 -0700 6.2 +++ b/make/windows/makefiles/vm.make Tue Mar 27 15:28:52 2012 -0400 6.3 @@ -172,6 +172,7 @@ 6.4 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/memory 6.5 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/oops 6.6 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims 6.7 +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims/wbtestmethods 6.8 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/runtime 6.9 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/services 6.10 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/trace 6.11 @@ -269,6 +270,9 @@ 6.12 {$(COMMONSRC)\share\vm\prims}.cpp.obj:: 6.13 $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< 6.14 6.15 +{$(COMMONSRC)\share\vm\prims\wbtestmethods}.cpp.obj:: 6.16 + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< 6.17 + 6.18 {$(COMMONSRC)\share\vm\runtime}.cpp.obj:: 6.19 $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< 6.20 6.21 @@ -349,6 +353,9 @@ 6.22 {$(ALTSRC)\share\vm\prims}.cpp.obj:: 6.23 $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< 6.24 6.25 +{$(ALTSRC)\share\vm\prims\wbtestmethods}.cpp.obj:: 6.26 + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< 6.27 + 6.28 {$(ALTSRC)\share\vm\runtime}.cpp.obj:: 6.29 $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< 6.30
7.1 --- a/make/windows/makefiles/wb.make Fri Mar 23 22:34:22 2012 -0700 7.2 +++ b/make/windows/makefiles/wb.make Tue Mar 27 15:28:52 2012 -0400 7.3 @@ -40,7 +40,7 @@ 7.4 7.5 7.6 {$(WorkSpace)\src\share\tools\whitebox\sun\hotspot}.java.class:: 7.7 - $(COMPILE_JAVAC) -d $(WB_CLASSES) $< 7.8 + $(COMPILE_JAVAC) -sourcepath $(WBSRCDIR) -d $(WB_CLASSES) $< 7.9 7.10 $(WB_JAR): wb_java_srcs 7.11 $(RUN_JAR) cf $@ -C $(WB_CLASSES) .
8.1 --- a/src/share/tools/whitebox/sun/hotspot/WhiteBox.java Fri Mar 23 22:34:22 2012 -0700 8.2 +++ b/src/share/tools/whitebox/sun/hotspot/WhiteBox.java Tue Mar 27 15:28:52 2012 -0400 8.3 @@ -24,6 +24,7 @@ 8.4 8.5 package sun.hotspot; 8.6 import java.security.BasicPermission; 8.7 +import sun.hotspot.parser.DiagnosticCommand; 8.8 8.9 public class WhiteBox { 8.10 8.11 @@ -67,4 +68,5 @@ 8.12 public native boolean g1IsHumongous(Object o); 8.13 public native long g1NumFreeRegions(); 8.14 public native int g1RegionSize(); 8.15 + public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); 8.16 }
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/share/tools/whitebox/sun/hotspot/parser/DiagnosticCommand.java Tue Mar 27 15:28:52 2012 -0400 9.3 @@ -0,0 +1,43 @@ 9.4 +package sun.hotspot.parser; 9.5 + 9.6 +public class DiagnosticCommand { 9.7 + 9.8 + public enum DiagnosticArgumentType { 9.9 + JLONG, BOOLEAN, STRING, NANOTIME, STRINGARRAY, MEMORYSIZE 9.10 + } 9.11 + 9.12 + private String name; 9.13 + private String desc; 9.14 + private DiagnosticArgumentType type; 9.15 + private boolean mandatory; 9.16 + private String defaultValue; 9.17 + 9.18 + public DiagnosticCommand(String name, String desc, DiagnosticArgumentType type, 9.19 + boolean mandatory, String defaultValue) { 9.20 + this.name = name; 9.21 + this.desc = desc; 9.22 + this.type = type; 9.23 + this.mandatory = mandatory; 9.24 + this.defaultValue = defaultValue; 9.25 + } 9.26 + 9.27 + public String getName() { 9.28 + return name; 9.29 + } 9.30 + 9.31 + public String getDesc() { 9.32 + return desc; 9.33 + } 9.34 + 9.35 + public DiagnosticArgumentType getType() { 9.36 + return type; 9.37 + } 9.38 + 9.39 + public boolean isMandatory() { 9.40 + return mandatory; 9.41 + } 9.42 + 9.43 + public String getDefaultValue() { 9.44 + return defaultValue; 9.45 + } 9.46 +}
10.1 --- a/src/share/vm/classfile/classFileParser.cpp Fri Mar 23 22:34:22 2012 -0700 10.2 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Mar 27 15:28:52 2012 -0400 10.3 @@ -1,5 +1,5 @@ 10.4 /* 10.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 10.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 10.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10.8 * 10.9 * This code is free software; you can redistribute it and/or modify it 10.10 @@ -81,7 +81,7 @@ 10.11 #define JAVA_7_VERSION 51 10.12 10.13 10.14 -void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int length, TRAPS) { 10.15 +void ClassFileParser::parse_constant_pool_entries(Handle class_loader, constantPoolHandle cp, int length, TRAPS) { 10.16 // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize 10.17 // this function (_current can be allocated in a register, with scalar 10.18 // replacement of aggregates). The _current pointer is copied back to 10.19 @@ -272,7 +272,7 @@ 10.20 indices[names_count] = index; 10.21 hashValues[names_count++] = hash; 10.22 if (names_count == SymbolTable::symbol_alloc_batch_size) { 10.23 - SymbolTable::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); 10.24 + SymbolTable::new_symbols(class_loader, cp, names_count, names, lengths, indices, hashValues, CHECK); 10.25 names_count = 0; 10.26 } 10.27 } else { 10.28 @@ -289,7 +289,7 @@ 10.29 10.30 // Allocate the remaining symbols 10.31 if (names_count > 0) { 10.32 - SymbolTable::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); 10.33 + SymbolTable::new_symbols(class_loader, cp, names_count, names, lengths, indices, hashValues, CHECK); 10.34 } 10.35 10.36 // Copy _current pointer of local copy back to stream(). 10.37 @@ -318,7 +318,7 @@ 10.38 10.39 bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } 10.40 10.41 -constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { 10.42 +constantPoolHandle ClassFileParser::parse_constant_pool(Handle class_loader, TRAPS) { 10.43 ClassFileStream* cfs = stream(); 10.44 constantPoolHandle nullHandle; 10.45 10.46 @@ -337,7 +337,7 @@ 10.47 ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. 10.48 10.49 // parsing constant pool entries 10.50 - parse_constant_pool_entries(cp, length, CHECK_(nullHandle)); 10.51 + parse_constant_pool_entries(class_loader, cp, length, CHECK_(nullHandle)); 10.52 10.53 int index = 1; // declared outside of loops for portability 10.54 10.55 @@ -2758,7 +2758,7 @@ 10.56 _relax_verify = Verifier::relax_verify_for(class_loader()); 10.57 10.58 // Constant pool 10.59 - constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle)); 10.60 + constantPoolHandle cp = parse_constant_pool(class_loader, CHECK_(nullHandle)); 10.61 ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. 10.62 10.63 int cp_size = cp->length();
11.1 --- a/src/share/vm/classfile/classFileParser.hpp Fri Mar 23 22:34:22 2012 -0700 11.2 +++ b/src/share/vm/classfile/classFileParser.hpp Tue Mar 27 15:28:52 2012 -0400 11.3 @@ -1,5 +1,5 @@ 11.4 /* 11.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 11.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 11.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.8 * 11.9 * This code is free software; you can redistribute it and/or modify it 11.10 @@ -68,9 +68,10 @@ 11.11 void set_stream(ClassFileStream* st) { _stream = st; } 11.12 11.13 // Constant pool parsing 11.14 - void parse_constant_pool_entries(constantPoolHandle cp, int length, TRAPS); 11.15 + void parse_constant_pool_entries(Handle class_loader, 11.16 + constantPoolHandle cp, int length, TRAPS); 11.17 11.18 - constantPoolHandle parse_constant_pool(TRAPS); 11.19 + constantPoolHandle parse_constant_pool(Handle class_loader, TRAPS); 11.20 11.21 // Interface parsing 11.22 objArrayHandle parse_interfaces(constantPoolHandle cp,
12.1 --- a/src/share/vm/classfile/symbolTable.cpp Fri Mar 23 22:34:22 2012 -0700 12.2 +++ b/src/share/vm/classfile/symbolTable.cpp Tue Mar 27 15:28:52 2012 -0400 12.3 @@ -1,5 +1,5 @@ 12.4 /* 12.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 12.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 12.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.8 * 12.9 * This code is free software; you can redistribute it and/or modify it 12.10 @@ -27,6 +27,7 @@ 12.11 #include "classfile/symbolTable.hpp" 12.12 #include "classfile/systemDictionary.hpp" 12.13 #include "gc_interface/collectedHeap.inline.hpp" 12.14 +#include "memory/allocation.inline.hpp" 12.15 #include "memory/filemap.hpp" 12.16 #include "memory/gcLocker.inline.hpp" 12.17 #include "oops/oop.inline.hpp" 12.18 @@ -37,34 +38,35 @@ 12.19 // -------------------------------------------------------------------------- 12.20 12.21 SymbolTable* SymbolTable::_the_table = NULL; 12.22 +// Static arena for symbols that are not deallocated 12.23 +Arena* SymbolTable::_arena = NULL; 12.24 12.25 -Symbol* SymbolTable::allocate_symbol(const u1* name, int len, TRAPS) { 12.26 +Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) { 12.27 // Don't allow symbols to be created which cannot fit in a Symbol*. 12.28 if (len > Symbol::max_length()) { 12.29 THROW_MSG_0(vmSymbols::java_lang_InternalError(), 12.30 "name is too long to represent"); 12.31 } 12.32 - Symbol* sym = new (len) Symbol(name, len); 12.33 + Symbol* sym; 12.34 + // Allocate symbols in the C heap when dumping shared spaces in case there 12.35 + // are temporary symbols we can remove. 12.36 + if (c_heap || DumpSharedSpaces) { 12.37 + // refcount starts as 1 12.38 + sym = new (len, THREAD) Symbol(name, len, 1); 12.39 + } else { 12.40 + sym = new (len, arena(), THREAD) Symbol(name, len, -1); 12.41 + } 12.42 assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted"); 12.43 return sym; 12.44 } 12.45 12.46 -bool SymbolTable::allocate_symbols(int names_count, const u1** names, 12.47 - int* lengths, Symbol** syms, TRAPS) { 12.48 - for (int i = 0; i< names_count; i++) { 12.49 - if (lengths[i] > Symbol::max_length()) { 12.50 - THROW_MSG_0(vmSymbols::java_lang_InternalError(), 12.51 - "name is too long to represent"); 12.52 - } 12.53 +void SymbolTable::initialize_symbols(int arena_alloc_size) { 12.54 + // Initialize the arena for global symbols, size passed in depends on CDS. 12.55 + if (arena_alloc_size == 0) { 12.56 + _arena = new Arena(); 12.57 + } else { 12.58 + _arena = new Arena(arena_alloc_size); 12.59 } 12.60 - 12.61 - for (int i = 0; i< names_count; i++) { 12.62 - int len = lengths[i]; 12.63 - syms[i] = new (len) Symbol(names[i], len); 12.64 - assert(syms[i] != NULL, "new should call vm_exit_out_of_memory if " 12.65 - "C_HEAP is exhausted"); 12.66 - } 12.67 - return true; 12.68 } 12.69 12.70 // Call function for all symbols in the symbol table. 12.71 @@ -83,8 +85,7 @@ 12.72 int SymbolTable::symbols_counted = 0; 12.73 12.74 // Remove unreferenced symbols from the symbol table 12.75 -// This is done late during GC. This doesn't use the hash table unlink because 12.76 -// it assumes that the literals are oops. 12.77 +// This is done late during GC. 12.78 void SymbolTable::unlink() { 12.79 int removed = 0; 12.80 int total = 0; 12.81 @@ -156,7 +157,7 @@ 12.82 if (s != NULL) return s; 12.83 12.84 // Otherwise, add to symbol to table 12.85 - return the_table()->basic_add(index, (u1*)name, len, hashValue, CHECK_NULL); 12.86 + return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL); 12.87 } 12.88 12.89 Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) { 12.90 @@ -192,7 +193,7 @@ 12.91 // We can't include the code in No_Safepoint_Verifier because of the 12.92 // ResourceMark. 12.93 12.94 - return the_table()->basic_add(index, (u1*)buffer, len, hashValue, CHECK_NULL); 12.95 + return the_table()->basic_add(index, (u1*)buffer, len, hashValue, true, CHECK_NULL); 12.96 } 12.97 12.98 Symbol* SymbolTable::lookup_only(const char* name, int len, 12.99 @@ -256,71 +257,81 @@ 12.100 } 12.101 } 12.102 12.103 -void SymbolTable::add(constantPoolHandle cp, int names_count, 12.104 +void SymbolTable::add(Handle class_loader, constantPoolHandle cp, 12.105 + int names_count, 12.106 const char** names, int* lengths, int* cp_indices, 12.107 unsigned int* hashValues, TRAPS) { 12.108 SymbolTable* table = the_table(); 12.109 - bool added = table->basic_add(cp, names_count, names, lengths, 12.110 + bool added = table->basic_add(class_loader, cp, names_count, names, lengths, 12.111 cp_indices, hashValues, CHECK); 12.112 if (!added) { 12.113 // do it the hard way 12.114 for (int i=0; i<names_count; i++) { 12.115 int index = table->hash_to_index(hashValues[i]); 12.116 - Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], 12.117 - hashValues[i], CHECK); 12.118 + bool c_heap = class_loader() != NULL; 12.119 + Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], hashValues[i], c_heap, CHECK); 12.120 cp->symbol_at_put(cp_indices[i], sym); 12.121 } 12.122 } 12.123 } 12.124 12.125 +Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) { 12.126 + unsigned int hash; 12.127 + Symbol* result = SymbolTable::lookup_only((char*)name, (int)strlen(name), hash); 12.128 + if (result != NULL) { 12.129 + return result; 12.130 + } 12.131 + SymbolTable* table = the_table(); 12.132 + int index = table->hash_to_index(hash); 12.133 + return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD); 12.134 +} 12.135 + 12.136 Symbol* SymbolTable::basic_add(int index, u1 *name, int len, 12.137 - unsigned int hashValue, TRAPS) { 12.138 + unsigned int hashValue, bool c_heap, TRAPS) { 12.139 assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), 12.140 "proposed name of symbol must be stable"); 12.141 12.142 - // We assume that lookup() has been called already, that it failed, 12.143 - // and symbol was not found. We create the symbol here. 12.144 - Symbol* sym = allocate_symbol(name, len, CHECK_NULL); 12.145 - 12.146 - // Allocation must be done before grabbing the SymbolTable_lock lock 12.147 + // Grab SymbolTable_lock first. 12.148 MutexLocker ml(SymbolTable_lock, THREAD); 12.149 12.150 - assert(sym->equals((char*)name, len), "symbol must be properly initialized"); 12.151 - 12.152 // Since look-up was done lock-free, we need to check if another 12.153 // thread beat us in the race to insert the symbol. 12.154 - 12.155 Symbol* test = lookup(index, (char*)name, len, hashValue); 12.156 if (test != NULL) { 12.157 - // A race occurred and another thread introduced the symbol, this one 12.158 - // will be dropped and collected. 12.159 - delete sym; 12.160 + // A race occurred and another thread introduced the symbol. 12.161 assert(test->refcount() != 0, "lookup should have incremented the count"); 12.162 return test; 12.163 } 12.164 12.165 + // Create a new symbol. 12.166 + Symbol* sym = allocate_symbol(name, len, c_heap, CHECK_NULL); 12.167 + assert(sym->equals((char*)name, len), "symbol must be properly initialized"); 12.168 + 12.169 HashtableEntry<Symbol*>* entry = new_entry(hashValue, sym); 12.170 - sym->increment_refcount(); 12.171 add_entry(index, entry); 12.172 return sym; 12.173 } 12.174 12.175 -bool SymbolTable::basic_add(constantPoolHandle cp, int names_count, 12.176 +// This version of basic_add adds symbols in batch from the constant pool 12.177 +// parsing. 12.178 +bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp, 12.179 + int names_count, 12.180 const char** names, int* lengths, 12.181 int* cp_indices, unsigned int* hashValues, 12.182 TRAPS) { 12.183 - Symbol* syms[symbol_alloc_batch_size]; 12.184 - bool allocated = allocate_symbols(names_count, (const u1**)names, lengths, 12.185 - syms, CHECK_false); 12.186 - if (!allocated) { 12.187 - return false; 12.188 + 12.189 + // Check symbol names are not too long. If any are too long, don't add any. 12.190 + for (int i = 0; i< names_count; i++) { 12.191 + if (lengths[i] > Symbol::max_length()) { 12.192 + THROW_MSG_0(vmSymbols::java_lang_InternalError(), 12.193 + "name is too long to represent"); 12.194 + } 12.195 } 12.196 12.197 - // Allocation must be done before grabbing the SymbolTable_lock lock 12.198 + // Hold SymbolTable_lock through the symbol creation 12.199 MutexLocker ml(SymbolTable_lock, THREAD); 12.200 12.201 for (int i=0; i<names_count; i++) { 12.202 - assert(syms[i]->equals(names[i], lengths[i]), "symbol must be properly initialized"); 12.203 // Since look-up was done lock-free, we need to check if another 12.204 // thread beat us in the race to insert the symbol. 12.205 int index = hash_to_index(hashValues[i]); 12.206 @@ -330,16 +341,17 @@ 12.207 // will be dropped and collected. Use test instead. 12.208 cp->symbol_at_put(cp_indices[i], test); 12.209 assert(test->refcount() != 0, "lookup should have incremented the count"); 12.210 - delete syms[i]; 12.211 } else { 12.212 - Symbol* sym = syms[i]; 12.213 + // Create a new symbol. The null class loader is never unloaded so these 12.214 + // are allocated specially in a permanent arena. 12.215 + bool c_heap = class_loader() != NULL; 12.216 + Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false)); 12.217 + assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be??? 12.218 HashtableEntry<Symbol*>* entry = new_entry(hashValues[i], sym); 12.219 - sym->increment_refcount(); // increment refcount in external hashtable 12.220 add_entry(index, entry); 12.221 cp->symbol_at_put(cp_indices[i], sym); 12.222 } 12.223 } 12.224 - 12.225 return true; 12.226 } 12.227 12.228 @@ -406,6 +418,8 @@ 12.229 ((float)symbols_removed/(float)symbols_counted)* 100); 12.230 } 12.231 tty->print_cr("Reference counts %5d", Symbol::_total_count); 12.232 + tty->print_cr("Symbol arena size %5d used %5d", 12.233 + arena()->size_in_bytes(), arena()->used()); 12.234 tty->print_cr("Histogram of symbol length:"); 12.235 tty->print_cr("%8s %5d", "Total ", total); 12.236 tty->print_cr("%8s %5d", "Maximum", max_symbols);
13.1 --- a/src/share/vm/classfile/symbolTable.hpp Fri Mar 23 22:34:22 2012 -0700 13.2 +++ b/src/share/vm/classfile/symbolTable.hpp Tue Mar 27 15:28:52 2012 -0400 13.3 @@ -1,5 +1,5 @@ 13.4 /* 13.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 13.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 13.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.8 * 13.9 * This code is free software; you can redistribute it and/or modify it 13.10 @@ -82,24 +82,24 @@ 13.11 static int symbols_removed; 13.12 static int symbols_counted; 13.13 13.14 - Symbol* allocate_symbol(const u1* name, int len, TRAPS); // Assumes no characters larger than 0x7F 13.15 - bool allocate_symbols(int names_count, const u1** names, int* lengths, Symbol** syms, TRAPS); 13.16 + Symbol* allocate_symbol(const u1* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F 13.17 13.18 // Adding elements 13.19 - Symbol* basic_add(int index, u1* name, int len, 13.20 - unsigned int hashValue, TRAPS); 13.21 - bool basic_add(constantPoolHandle cp, int names_count, 13.22 + Symbol* basic_add(int index, u1* name, int len, unsigned int hashValue, 13.23 + bool c_heap, TRAPS); 13.24 + 13.25 + bool basic_add(Handle class_loader, constantPoolHandle cp, int names_count, 13.26 const char** names, int* lengths, int* cp_indices, 13.27 unsigned int* hashValues, TRAPS); 13.28 13.29 - static void new_symbols(constantPoolHandle cp, int names_count, 13.30 + static void new_symbols(Handle class_loader, constantPoolHandle cp, 13.31 + int names_count, 13.32 const char** name, int* lengths, 13.33 int* cp_indices, unsigned int* hashValues, 13.34 TRAPS) { 13.35 - add(cp, names_count, name, lengths, cp_indices, hashValues, THREAD); 13.36 + add(class_loader, cp, names_count, name, lengths, cp_indices, hashValues, THREAD); 13.37 } 13.38 13.39 - 13.40 // Table size 13.41 enum { 13.42 symbol_table_size = 20011 13.43 @@ -114,10 +114,16 @@ 13.44 : Hashtable<Symbol*>(symbol_table_size, sizeof (HashtableEntry<Symbol*>), t, 13.45 number_of_entries) {} 13.46 13.47 + // Arena for permanent symbols (null class loader) that are never unloaded 13.48 + static Arena* _arena; 13.49 + static Arena* arena() { return _arena; } // called for statistics 13.50 13.51 + static void initialize_symbols(int arena_alloc_size = 0); 13.52 public: 13.53 enum { 13.54 - symbol_alloc_batch_size = 8 13.55 + symbol_alloc_batch_size = 8, 13.56 + // Pick initial size based on java -version size measurements 13.57 + symbol_alloc_arena_size = 360*K 13.58 }; 13.59 13.60 // The symbol table 13.61 @@ -126,6 +132,7 @@ 13.62 static void create_table() { 13.63 assert(_the_table == NULL, "One symbol table allowed."); 13.64 _the_table = new SymbolTable(); 13.65 + initialize_symbols(symbol_alloc_arena_size); 13.66 } 13.67 13.68 static void create_table(HashtableBucket* t, int length, 13.69 @@ -134,6 +141,9 @@ 13.70 assert(length == symbol_table_size * sizeof(HashtableBucket), 13.71 "bad shared symbol size."); 13.72 _the_table = new SymbolTable(t, number_of_entries); 13.73 + // if CDS give symbol table a default arena size since most symbols 13.74 + // are already allocated in the shared misc section. 13.75 + initialize_symbols(); 13.76 } 13.77 13.78 static Symbol* lookup(const char* name, int len, TRAPS); 13.79 @@ -151,7 +161,7 @@ 13.80 static Symbol* lookup_unicode(const jchar* name, int len, TRAPS); 13.81 static Symbol* lookup_only_unicode(const jchar* name, int len, unsigned int& hash); 13.82 13.83 - static void add(constantPoolHandle cp, int names_count, 13.84 + static void add(Handle class_loader, constantPoolHandle cp, int names_count, 13.85 const char** names, int* lengths, int* cp_indices, 13.86 unsigned int* hashValues, TRAPS); 13.87 13.88 @@ -174,6 +184,9 @@ 13.89 return lookup(sym, begin, end, THREAD); 13.90 } 13.91 13.92 + // Create a symbol in the arena for symbols that are not deleted 13.93 + static Symbol* new_permanent_symbol(const char* name, TRAPS); 13.94 + 13.95 // Symbol lookup 13.96 static Symbol* lookup(int index, const char* name, int len, TRAPS); 13.97
14.1 --- a/src/share/vm/classfile/vmSymbols.cpp Fri Mar 23 22:34:22 2012 -0700 14.2 +++ b/src/share/vm/classfile/vmSymbols.cpp Tue Mar 27 15:28:52 2012 -0400 14.3 @@ -1,5 +1,5 @@ 14.4 /* 14.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 14.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 14.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.8 * 14.9 * This code is free software; you can redistribute it and/or modify it 14.10 @@ -79,7 +79,7 @@ 14.11 if (!UseSharedSpaces) { 14.12 const char* string = &vm_symbol_bodies[0]; 14.13 for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { 14.14 - Symbol* sym = SymbolTable::new_symbol(string, CHECK); 14.15 + Symbol* sym = SymbolTable::new_permanent_symbol(string, CHECK); 14.16 _symbols[index] = sym; 14.17 string += strlen(string); // skip string body 14.18 string += 1; // skip trailing null 14.19 @@ -128,7 +128,7 @@ 14.20 // Spot-check correspondence between strings, symbols, and enums: 14.21 assert(_symbols[NO_SID] == NULL, "must be"); 14.22 const char* str = "java/lang/Object"; 14.23 - TempNewSymbol jlo = SymbolTable::new_symbol(str, CHECK); 14.24 + TempNewSymbol jlo = SymbolTable::new_permanent_symbol(str, CHECK); 14.25 assert(strncmp(str, (char*)jlo->base(), jlo->utf8_length()) == 0, ""); 14.26 assert(jlo == java_lang_Object(), ""); 14.27 SID sid = VM_SYMBOL_ENUM_NAME(java_lang_Object); 14.28 @@ -147,7 +147,7 @@ 14.29 // The string "format" happens (at the moment) not to be a vmSymbol, 14.30 // though it is a method name in java.lang.String. 14.31 str = "format"; 14.32 - TempNewSymbol fmt = SymbolTable::new_symbol(str, CHECK); 14.33 + TempNewSymbol fmt = SymbolTable::new_permanent_symbol(str, CHECK); 14.34 sid = find_sid(fmt); 14.35 assert(sid == NO_SID, "symbol index works (negative test)"); 14.36 }
15.1 --- a/src/share/vm/memory/dump.cpp Fri Mar 23 22:34:22 2012 -0700 15.2 +++ b/src/share/vm/memory/dump.cpp Tue Mar 27 15:28:52 2012 -0400 15.3 @@ -1,5 +1,5 @@ 15.4 /* 15.5 - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 15.6 + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 15.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.8 * 15.9 * This code is free software; you can redistribute it and/or modify it 15.10 @@ -1490,12 +1490,11 @@ 15.11 15.12 // sun.io.Converters 15.13 static const char obj_array_sig[] = "[[Ljava/lang/Object;"; 15.14 - SymbolTable::lookup(obj_array_sig, (int)strlen(obj_array_sig), THREAD); 15.15 + (void)SymbolTable::new_permanent_symbol(obj_array_sig, THREAD); 15.16 15.17 // java.util.HashMap 15.18 static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;"; 15.19 - SymbolTable::lookup(map_entry_array_sig, (int)strlen(map_entry_array_sig), 15.20 - THREAD); 15.21 + (void)SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD); 15.22 15.23 tty->print("Loading classes to share ... "); 15.24 while ((fgets(class_name, sizeof class_name, file)) != NULL) { 15.25 @@ -1514,7 +1513,7 @@ 15.26 computed_jsum = jsum(computed_jsum, class_name, (const int)name_len - 1); 15.27 15.28 // Got a class name - load it. 15.29 - TempNewSymbol class_name_symbol = SymbolTable::new_symbol(class_name, THREAD); 15.30 + Symbol* class_name_symbol = SymbolTable::new_permanent_symbol(class_name, THREAD); 15.31 guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol."); 15.32 klassOop klass = SystemDictionary::resolve_or_null(class_name_symbol, 15.33 THREAD);
16.1 --- a/src/share/vm/oops/objArrayKlassKlass.cpp Fri Mar 23 22:34:22 2012 -0700 16.2 +++ b/src/share/vm/oops/objArrayKlassKlass.cpp Tue Mar 27 15:28:52 2012 -0400 16.3 @@ -1,5 +1,5 @@ 16.4 /* 16.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 16.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 16.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 16.8 * 16.9 * This code is free software; you can redistribute it and/or modify it 16.10 @@ -137,7 +137,7 @@ 16.11 new_str[idx++] = ';'; 16.12 } 16.13 new_str[idx++] = '\0'; 16.14 - name = SymbolTable::new_symbol(new_str, CHECK_0); 16.15 + name = SymbolTable::new_permanent_symbol(new_str, CHECK_0); 16.16 if (element_klass->oop_is_instance()) { 16.17 instanceKlass* ik = instanceKlass::cast(element_klass()); 16.18 ik->set_array_name(name);
17.1 --- a/src/share/vm/oops/symbol.cpp Fri Mar 23 22:34:22 2012 -0700 17.2 +++ b/src/share/vm/oops/symbol.cpp Tue Mar 27 15:28:52 2012 -0400 17.3 @@ -1,5 +1,5 @@ 17.4 /* 17.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 17.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 17.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.8 * 17.9 * This code is free software; you can redistribute it and/or modify it 17.10 @@ -29,15 +29,25 @@ 17.11 #include "runtime/os.hpp" 17.12 #include "memory/allocation.inline.hpp" 17.13 17.14 -Symbol::Symbol(const u1* name, int length) : _refcount(0), _length(length) { 17.15 +Symbol::Symbol(const u1* name, int length, int refcount) : _refcount(refcount), _length(length) { 17.16 _identity_hash = os::random(); 17.17 for (int i = 0; i < _length; i++) { 17.18 byte_at_put(i, name[i]); 17.19 } 17.20 } 17.21 17.22 -void* Symbol::operator new(size_t size, int len) { 17.23 - return (void *) AllocateHeap(object_size(len) * HeapWordSize, "symbol"); 17.24 +void* Symbol::operator new(size_t sz, int len, TRAPS) { 17.25 + int alloc_size = object_size(len)*HeapWordSize; 17.26 + address res = (address) AllocateHeap(alloc_size, "symbol"); 17.27 + DEBUG_ONLY(set_allocation_type(res, ResourceObj::C_HEAP);) 17.28 + return res; 17.29 +} 17.30 + 17.31 +void* Symbol::operator new(size_t sz, int len, Arena* arena, TRAPS) { 17.32 + int alloc_size = object_size(len)*HeapWordSize; 17.33 + address res = (address)arena->Amalloc(alloc_size); 17.34 + DEBUG_ONLY(set_allocation_type(res, ResourceObj::ARENA);) 17.35 + return res; 17.36 } 17.37 17.38 // ------------------------------------------------------------------ 17.39 @@ -206,26 +216,5 @@ 17.40 } 17.41 } 17.42 17.43 -void Symbol::increment_refcount() { 17.44 - // Only increment the refcount if positive. If negative either 17.45 - // overflow has occurred or it is a permanent symbol in a read only 17.46 - // shared archive. 17.47 - if (_refcount >= 0) { 17.48 - Atomic::inc(&_refcount); 17.49 - NOT_PRODUCT(Atomic::inc(&_total_count);) 17.50 - } 17.51 -} 17.52 - 17.53 -void Symbol::decrement_refcount() { 17.54 - if (_refcount >= 0) { 17.55 - Atomic::dec(&_refcount); 17.56 -#ifdef ASSERT 17.57 - if (_refcount < 0) { 17.58 - print(); 17.59 - assert(false, "reference count underflow for symbol"); 17.60 - } 17.61 -#endif 17.62 - } 17.63 -} 17.64 - 17.65 +// SymbolTable prints this in its statistics 17.66 NOT_PRODUCT(int Symbol::_total_count = 0;)
18.1 --- a/src/share/vm/oops/symbol.hpp Fri Mar 23 22:34:22 2012 -0700 18.2 +++ b/src/share/vm/oops/symbol.hpp Tue Mar 27 15:28:52 2012 -0400 18.3 @@ -1,5 +1,5 @@ 18.4 /* 18.5 - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 18.6 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 18.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.8 * 18.9 * This code is free software; you can redistribute it and/or modify it 18.10 @@ -27,6 +27,7 @@ 18.11 18.12 #include "utilities/utf8.hpp" 18.13 #include "memory/allocation.hpp" 18.14 +#include "runtime/atomic.hpp" 18.15 18.16 // A Symbol is a canonicalized string. 18.17 // All Symbols reside in global SymbolTable and are reference counted. 18.18 @@ -95,7 +96,7 @@ 18.19 // TempNewSymbol (passed in as a parameter) so the reference count on its symbol 18.20 // will be decremented when it goes out of scope. 18.21 18.22 -class Symbol : public CHeapObj { 18.23 +class Symbol : public ResourceObj { 18.24 friend class VMStructs; 18.25 friend class SymbolTable; 18.26 friend class MoveSymbols; 18.27 @@ -111,7 +112,7 @@ 18.28 }; 18.29 18.30 static int object_size(int length) { 18.31 - size_t size = heap_word_size(sizeof(Symbol) + length); 18.32 + size_t size = heap_word_size(sizeof(Symbol) + (length > 0 ? length - 1 : 0)); 18.33 return align_object_size(size); 18.34 } 18.35 18.36 @@ -120,28 +121,25 @@ 18.37 _body[index] = value; 18.38 } 18.39 18.40 - Symbol(const u1* name, int length); 18.41 - void* operator new(size_t size, int len); 18.42 + Symbol(const u1* name, int length, int refcount); 18.43 + void* operator new(size_t size, int len, TRAPS); 18.44 + void* operator new(size_t size, int len, Arena* arena, TRAPS); 18.45 18.46 public: 18.47 // Low-level access (used with care, since not GC-safe) 18.48 const jbyte* base() const { return &_body[0]; } 18.49 18.50 - int object_size() { return object_size(utf8_length()); } 18.51 + int object_size() { return object_size(utf8_length()); } 18.52 18.53 // Returns the largest size symbol we can safely hold. 18.54 - static int max_length() { 18.55 - return max_symbol_length; 18.56 - } 18.57 + static int max_length() { return max_symbol_length; } 18.58 18.59 - int identity_hash() { 18.60 - return _identity_hash; 18.61 - } 18.62 + int identity_hash() { return _identity_hash; } 18.63 18.64 // Reference counting. See comments above this class for when to use. 18.65 - int refcount() const { return _refcount; } 18.66 - void increment_refcount(); 18.67 - void decrement_refcount(); 18.68 + int refcount() const { return _refcount; } 18.69 + inline void increment_refcount(); 18.70 + inline void decrement_refcount(); 18.71 18.72 int byte_at(int index) const { 18.73 assert(index >=0 && index < _length, "symbol index overflow"); 18.74 @@ -220,4 +218,26 @@ 18.75 return (((uintptr_t)this < (uintptr_t)other) ? -1 18.76 : ((uintptr_t)this == (uintptr_t) other) ? 0 : 1); 18.77 } 18.78 + 18.79 +inline void Symbol::increment_refcount() { 18.80 + // Only increment the refcount if positive. If negative either 18.81 + // overflow has occurred or it is a permanent symbol in a read only 18.82 + // shared archive. 18.83 + if (_refcount >= 0) { 18.84 + Atomic::inc(&_refcount); 18.85 + NOT_PRODUCT(Atomic::inc(&_total_count);) 18.86 + } 18.87 +} 18.88 + 18.89 +inline void Symbol::decrement_refcount() { 18.90 + if (_refcount >= 0) { 18.91 + Atomic::dec(&_refcount); 18.92 +#ifdef ASSERT 18.93 + if (_refcount < 0) { 18.94 + print(); 18.95 + assert(false, "reference count underflow for symbol"); 18.96 + } 18.97 +#endif 18.98 + } 18.99 +} 18.100 #endif // SHARE_VM_OOPS_SYMBOL_HPP
19.1 --- a/src/share/vm/oops/typeArrayKlass.cpp Fri Mar 23 22:34:22 2012 -0700 19.2 +++ b/src/share/vm/oops/typeArrayKlass.cpp Tue Mar 27 15:28:52 2012 -0400 19.3 @@ -55,7 +55,7 @@ 19.4 19.5 Symbol* sym = NULL; 19.6 if (name_str != NULL) { 19.7 - sym = SymbolTable::new_symbol(name_str, CHECK_NULL); 19.8 + sym = SymbolTable::new_permanent_symbol(name_str, CHECK_NULL); 19.9 } 19.10 KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj()); 19.11
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/src/share/vm/prims/wbtestmethods/parserTests.cpp Tue Mar 27 15:28:52 2012 -0400 20.3 @@ -0,0 +1,148 @@ 20.4 +/* 20.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 20.7 + * 20.8 + * This code is free software; you can redistribute it and/or modify it 20.9 + * under the terms of the GNU General Public License version 2 only, as 20.10 + * published by the Free Software Foundation. 20.11 + * 20.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 20.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 20.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20.15 + * version 2 for more details (a copy is included in the LICENSE file that 20.16 + * accompanied this code). 20.17 + * 20.18 + * You should have received a copy of the GNU General Public License version 20.19 + * 2 along with this work; if not, write to the Free Software Foundation, 20.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20.21 + * 20.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20.23 + * or visit www.oracle.com if you need additional information or have any 20.24 + * questions. 20.25 + * 20.26 + */ 20.27 + 20.28 +#include "precompiled.hpp" 20.29 + 20.30 +#include "classfile/symbolTable.hpp" 20.31 + 20.32 +#include "prims/jni.h" 20.33 +#include "prims/whitebox.hpp" 20.34 +#include "prims/wbtestmethods/parserTests.hpp" 20.35 +#include "runtime/interfaceSupport.hpp" 20.36 + 20.37 +#include "memory/oopFactory.hpp" 20.38 + 20.39 +#include "services/diagnosticArgument.hpp" 20.40 +#include "services/diagnosticFramework.hpp" 20.41 + 20.42 +//There's no way of beforeahnd knowing an upper size 20.43 +//Of the length of a string representation of 20.44 +//the value of an argument. 20.45 +#define VALUE_MAXLEN 256 20.46 + 20.47 +// DiagnosticFramework test utility methods 20.48 + 20.49 +/* 20.50 + * The DiagnosticArgumentType class contains an enum that says which type 20.51 + * this argument represents. (JLONG, BOOLEAN etc). 20.52 + * This method Returns a char* representation of that enum value. 20.53 + */ 20.54 +static const char* lookup_diagnosticArgumentEnum(const char* field_name, oop object) { 20.55 + Thread* THREAD = Thread::current(); 20.56 + const char* enum_sig = "Lsun/hotspot/parser/DiagnosticCommand$DiagnosticArgumentType;"; 20.57 + TempNewSymbol enumSigSymbol = SymbolTable::lookup(enum_sig, (int) strlen(enum_sig), THREAD); 20.58 + int offset = WhiteBox::offset_for_field(field_name, object, enumSigSymbol); 20.59 + oop enumOop = object->obj_field(offset); 20.60 + 20.61 + const char* ret = WhiteBox::lookup_jstring("name", enumOop); 20.62 + return ret; 20.63 +} 20.64 + 20.65 +/* 20.66 + * Takes an oop to a DiagnosticArgumentType-instance and 20.67 + * reads the fields from it. Fills an native DCmdParser with 20.68 + * this info. 20.69 + */ 20.70 +static void fill_in_parser(DCmdParser* parser, oop argument) 20.71 +{ 20.72 + const char* name = WhiteBox::lookup_jstring("name", argument); 20.73 + const char* desc = WhiteBox::lookup_jstring("desc", argument); 20.74 + const char* default_value = WhiteBox::lookup_jstring("defaultValue", argument); 20.75 + bool mandatory = WhiteBox::lookup_bool("mandatory", argument); 20.76 + const char* type = lookup_diagnosticArgumentEnum("type", argument); 20.77 + 20.78 + if (strcmp(type, "STRING") == 0) { 20.79 + DCmdArgument<char*>* argument = new DCmdArgument<char*>( 20.80 + name, desc, 20.81 + "STRING", mandatory, default_value); 20.82 + parser->add_dcmd_option(argument); 20.83 + } else if (strcmp(type, "NANOTIME") == 0) { 20.84 + DCmdArgument<NanoTimeArgument>* argument = new DCmdArgument<NanoTimeArgument>( 20.85 + name, desc, 20.86 + "NANOTIME", mandatory, default_value); 20.87 + parser->add_dcmd_option(argument); 20.88 + } else if (strcmp(type, "JLONG") == 0) { 20.89 + DCmdArgument<jlong>* argument = new DCmdArgument<jlong>( 20.90 + name, desc, 20.91 + "JLONG", mandatory, default_value); 20.92 + parser->add_dcmd_option(argument); 20.93 + } else if (strcmp(type, "BOOLEAN") == 0) { 20.94 + DCmdArgument<bool>* argument = new DCmdArgument<bool>( 20.95 + name, desc, 20.96 + "BOOLEAN", mandatory, default_value); 20.97 + parser->add_dcmd_option(argument); 20.98 + } else if (strcmp(type, "MEMORYSIZE") == 0) { 20.99 + DCmdArgument<MemorySizeArgument>* argument = new DCmdArgument<MemorySizeArgument>( 20.100 + name, desc, 20.101 + "MEMORY SIZE", mandatory, default_value); 20.102 + parser->add_dcmd_option(argument); 20.103 + } else if (strcmp(type, "STRINGARRAY") == 0) { 20.104 + DCmdArgument<StringArrayArgument*>* argument = new DCmdArgument<StringArrayArgument*>( 20.105 + name, desc, 20.106 + "STRING SET", mandatory); 20.107 + parser->add_dcmd_option(argument); 20.108 + } 20.109 +} 20.110 + 20.111 +/* 20.112 + * Will Fill in a java object array with alternating names of parsed command line options and 20.113 + * the value that has been parsed for it: 20.114 + * { name, value, name, value ... } 20.115 + * This can then be checked from java. 20.116 + */ 20.117 +WB_ENTRY(jobjectArray, WB_ParseCommandLine(JNIEnv* env, jobject o, jstring j_cmdline, jobjectArray arguments)) 20.118 + ResourceMark rm; 20.119 + DCmdParser parser; 20.120 + 20.121 + const char* c_cmdline = java_lang_String::as_utf8_string(JNIHandles::resolve(j_cmdline)); 20.122 + objArrayOop argumentArray = objArrayOop(JNIHandles::resolve_non_null(arguments)); 20.123 + 20.124 + int length = argumentArray->length(); 20.125 + 20.126 + for (int i = 0; i < length; i++) { 20.127 + oop argument_oop = argumentArray->obj_at(i); 20.128 + fill_in_parser(&parser, argument_oop); 20.129 + } 20.130 + 20.131 + CmdLine cmdline(c_cmdline, strlen(c_cmdline), true); 20.132 + parser.parse(&cmdline,',',CHECK_NULL); 20.133 + 20.134 + klassOop k = SystemDictionary::Object_klass(); 20.135 + objArrayOop returnvalue_array = oopFactory::new_objArray(k, parser.num_arguments() * 2, CHECK_NULL); 20.136 + 20.137 + GrowableArray<const char *>*parsedArgNames = parser.argument_name_array(); 20.138 + 20.139 + for (int i = 0; i < parser.num_arguments(); i++) { 20.140 + oop parsedName = java_lang_String::create_oop_from_str(parsedArgNames->at(i), CHECK_NULL); 20.141 + returnvalue_array->obj_at_put(i*2, parsedName); 20.142 + GenDCmdArgument* arg = parser.lookup_dcmd_option(parsedArgNames->at(i), strlen(parsedArgNames->at(i))); 20.143 + char buf[VALUE_MAXLEN]; 20.144 + arg->value_as_str(buf, sizeof(buf)); 20.145 + oop parsedValue = java_lang_String::create_oop_from_str(buf, CHECK_NULL); 20.146 + returnvalue_array->obj_at_put(i*2+1, parsedValue); 20.147 + } 20.148 + 20.149 + return (jobjectArray) JNIHandles::make_local(returnvalue_array); 20.150 + 20.151 +WB_END
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/src/share/vm/prims/wbtestmethods/parserTests.hpp Tue Mar 27 15:28:52 2012 -0400 21.3 @@ -0,0 +1,32 @@ 21.4 +/* 21.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 21.7 + * 21.8 + * This code is free software; you can redistribute it and/or modify it 21.9 + * under the terms of the GNU General Public License version 2 only, as 21.10 + * published by the Free Software Foundation. 21.11 + * 21.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 21.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 21.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21.15 + * version 2 for more details (a copy is included in the LICENSE file that 21.16 + * accompanied this code). 21.17 + * 21.18 + * You should have received a copy of the GNU General Public License version 21.19 + * 2 along with this work; if not, write to the Free Software Foundation, 21.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21.21 + * 21.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21.23 + * or visit www.oracle.com if you need additional information or have any 21.24 + * questions. 21.25 + */ 21.26 + 21.27 +#ifndef SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H 21.28 +#define SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H 21.29 + 21.30 +#include "prims/jni.h" 21.31 +#include "prims/whitebox.hpp" 21.32 + 21.33 +WB_METHOD_DECLARE WB_ParseCommandLine(JNIEnv* env, jobject o, jstring args, jobjectArray arguments); 21.34 + 21.35 +#endif //SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H
22.1 --- a/src/share/vm/prims/whitebox.cpp Fri Mar 23 22:34:22 2012 -0700 22.2 +++ b/src/share/vm/prims/whitebox.cpp Tue Mar 27 15:28:52 2012 -0400 22.3 @@ -24,11 +24,14 @@ 22.4 22.5 #include "precompiled.hpp" 22.6 22.7 -#include "jni.h" 22.8 - 22.9 #include "memory/universe.hpp" 22.10 #include "oops/oop.inline.hpp" 22.11 + 22.12 +#include "classfile/symbolTable.hpp" 22.13 + 22.14 #include "prims/whitebox.hpp" 22.15 +#include "prims/wbtestmethods/parserTests.hpp" 22.16 + 22.17 #include "runtime/interfaceSupport.hpp" 22.18 #include "runtime/os.hpp" 22.19 #include "utilities/debug.hpp" 22.20 @@ -41,13 +44,6 @@ 22.21 22.22 bool WhiteBox::_used = false; 22.23 22.24 -// Entry macro to transition from JNI to VM state. 22.25 - 22.26 -#define WB_ENTRY(result_type, header) JNI_ENTRY(result_type, header) 22.27 -#define WB_END JNI_END 22.28 - 22.29 -// Definitions of functions exposed via Whitebox API 22.30 - 22.31 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) 22.32 return (jlong)(void*)JNIHandles::resolve(obj); 22.33 WB_END 22.34 @@ -81,11 +77,63 @@ 22.35 WB_END 22.36 #endif // !SERIALGC 22.37 22.38 +//Some convenience methods to deal with objects from java 22.39 +int WhiteBox::offset_for_field(const char* field_name, oop object, 22.40 + Symbol* signature_symbol) { 22.41 + assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid"); 22.42 + Thread* THREAD = Thread::current(); 22.43 + 22.44 + //Get the class of our object 22.45 + klassOop arg_klass = object->klass(); 22.46 + //Turn it into an instance-klass 22.47 + instanceKlass* ik = instanceKlass::cast(arg_klass); 22.48 + 22.49 + //Create symbols to look for in the class 22.50 + TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name), 22.51 + THREAD); 22.52 + 22.53 + //To be filled in with an offset of the field we're looking for 22.54 + fieldDescriptor fd; 22.55 + 22.56 + klassOop res = ik->find_field(name_symbol, signature_symbol, &fd); 22.57 + if (res == NULL) { 22.58 + tty->print_cr("Invalid layout of %s at %s", ik->external_name(), 22.59 + name_symbol->as_C_string()); 22.60 + fatal("Invalid layout of preloaded class"); 22.61 + } 22.62 + 22.63 + //fetch the field at the offset we've found 22.64 + int dest_offset = fd.offset(); 22.65 + 22.66 + return dest_offset; 22.67 +} 22.68 + 22.69 + 22.70 +const char* WhiteBox::lookup_jstring(const char* field_name, oop object) { 22.71 + int offset = offset_for_field(field_name, object, 22.72 + vmSymbols::string_signature()); 22.73 + oop string = object->obj_field(offset); 22.74 + const char* ret = java_lang_String::as_utf8_string(string); 22.75 + return ret; 22.76 +} 22.77 + 22.78 +bool WhiteBox::lookup_bool(const char* field_name, oop object) { 22.79 + int offset = 22.80 + offset_for_field(field_name, object, vmSymbols::bool_signature()); 22.81 + bool ret = (object->bool_field(offset) == JNI_TRUE); 22.82 + return ret; 22.83 +} 22.84 + 22.85 + 22.86 #define CC (char*) 22.87 22.88 static JNINativeMethod methods[] = { 22.89 {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, 22.90 {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, 22.91 + {CC "parseCommandLine", 22.92 + CC "(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", 22.93 + (void*) &WB_ParseCommandLine 22.94 + }, 22.95 #ifndef SERIALGC 22.96 {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, 22.97 {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous },
23.1 --- a/src/share/vm/prims/whitebox.hpp Fri Mar 23 22:34:22 2012 -0700 23.2 +++ b/src/share/vm/prims/whitebox.hpp Tue Mar 27 15:28:52 2012 -0400 23.3 @@ -25,12 +25,29 @@ 23.4 #ifndef SHARE_VM_PRIMS_WHITEBOX_HPP 23.5 #define SHARE_VM_PRIMS_WHITEBOX_HPP 23.6 23.7 +#include "prims/jni.h" 23.8 + 23.9 +#include "memory/allocation.hpp" 23.10 +#include "oops/oopsHierarchy.hpp" 23.11 + 23.12 +// Entry macro to transition from JNI to VM state. 23.13 + 23.14 +#define WB_ENTRY(result_type, header) JNI_ENTRY(result_type, header) 23.15 +#define WB_END JNI_END 23.16 +#define WB_METHOD_DECLARE extern "C" jobjectArray JNICALL 23.17 + 23.18 class WhiteBox : public AllStatic { 23.19 private: 23.20 static bool _used; 23.21 public: 23.22 static bool used() { return _used; } 23.23 static void set_used() { _used = true; } 23.24 + static int offset_for_field(const char* field_name, oop object, 23.25 + Symbol* signature_symbol); 23.26 + static const char* lookup_jstring(const char* field_name, oop object); 23.27 + static bool lookup_bool(const char* field_name, oop object); 23.28 }; 23.29 23.30 + 23.31 + 23.32 #endif // SHARE_VM_PRIMS_WHITEBOX_HPP
24.1 --- a/src/share/vm/runtime/globals.hpp Fri Mar 23 22:34:22 2012 -0700 24.2 +++ b/src/share/vm/runtime/globals.hpp Tue Mar 27 15:28:52 2012 -0400 24.3 @@ -3807,7 +3807,7 @@ 24.4 product(uintx, SharedReadOnlySize, 10*M, \ 24.5 "Size of read-only space in permanent generation (in bytes)") \ 24.6 \ 24.7 - product(uintx, SharedMiscDataSize, NOT_LP64(4*M) LP64_ONLY(5*M), \ 24.8 + product(uintx, SharedMiscDataSize, NOT_LP64(4*M) LP64_ONLY(5*M) NOT_PRODUCT(+1*M), \ 24.9 "Size of the shared data area adjacent to the heap (in bytes)") \ 24.10 \ 24.11 product(uintx, SharedMiscCodeSize, 4*M, \
25.1 --- a/src/share/vm/services/diagnosticArgument.cpp Fri Mar 23 22:34:22 2012 -0700 25.2 +++ b/src/share/vm/services/diagnosticArgument.cpp Tue Mar 27 15:28:52 2012 -0400 25.3 @@ -43,6 +43,47 @@ 25.4 set_is_set(true); 25.5 } 25.6 25.7 +void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) { 25.8 + jio_snprintf(buf, len, INT64_FORMAT, l); 25.9 +} 25.10 + 25.11 +void GenDCmdArgument::to_string(bool b, char* buf, size_t len) { 25.12 + jio_snprintf(buf, len, b ? "true" : "false"); 25.13 +} 25.14 + 25.15 +void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) { 25.16 + jio_snprintf(buf, len, INT64_FORMAT, n._nanotime); 25.17 +} 25.18 + 25.19 +void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) { 25.20 + jio_snprintf(buf, len, INT64_FORMAT, m._size); 25.21 +} 25.22 + 25.23 +void GenDCmdArgument::to_string(char* c, char* buf, size_t len) { 25.24 + jio_snprintf(buf, len, "%s", c); 25.25 +} 25.26 + 25.27 +void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) { 25.28 + int length = f->array()->length(); 25.29 + size_t written = 0; 25.30 + buf[0] = 0; 25.31 + for (int i = 0; i < length; i++) { 25.32 + char* next_str = f->array()->at(i); 25.33 + size_t next_size = strlen(next_str); 25.34 + //Check if there's room left to write next element 25.35 + if (written + next_size > len) { 25.36 + return; 25.37 + } 25.38 + //Actually write element 25.39 + strcat(buf, next_str); 25.40 + written += next_size; 25.41 + //Check if there's room left for the comma 25.42 + if (i < length-1 && len - written > 0) { 25.43 + strcat(buf, ","); 25.44 + } 25.45 + } 25.46 +} 25.47 + 25.48 template <> void DCmdArgument<jlong>::parse_value(const char* str, 25.49 size_t len, TRAPS) { 25.50 if (str == NULL || sscanf(str, INT64_FORMAT, &_value) != 1) {
26.1 --- a/src/share/vm/services/diagnosticArgument.hpp Fri Mar 23 22:34:22 2012 -0700 26.2 +++ b/src/share/vm/services/diagnosticArgument.hpp Tue Mar 27 15:28:52 2012 -0400 26.3 @@ -110,12 +110,20 @@ 26.4 virtual void init_value(TRAPS) = 0; 26.5 virtual void reset(TRAPS) = 0; 26.6 virtual void cleanup() = 0; 26.7 + virtual void value_as_str(char* buf, size_t len) = 0; 26.8 void set_next(GenDCmdArgument* arg) { 26.9 _next = arg; 26.10 } 26.11 GenDCmdArgument* next() { 26.12 return _next; 26.13 } 26.14 + 26.15 + void to_string(jlong l, char* buf, size_t len); 26.16 + void to_string(bool b, char* buf, size_t len); 26.17 + void to_string(char* c, char* buf, size_t len); 26.18 + void to_string(NanoTimeArgument n, char* buf, size_t len); 26.19 + void to_string(MemorySizeArgument f, char* buf, size_t len); 26.20 + void to_string(StringArrayArgument* s, char* buf, size_t len); 26.21 }; 26.22 26.23 template <class ArgType> class DCmdArgument: public GenDCmdArgument { 26.24 @@ -143,6 +151,7 @@ 26.25 void parse_value(const char* str, size_t len, TRAPS); 26.26 void init_value(TRAPS); 26.27 void destroy_value(); 26.28 + void value_as_str(char *buf, size_t len) { return to_string(_value, buf, len);} 26.29 }; 26.30 26.31 #endif /* SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP */
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/test/serviceability/ParserTest.java Tue Mar 27 15:28:52 2012 -0400 27.3 @@ -0,0 +1,152 @@ 27.4 +/* 27.5 + * @test ParserTest 27.6 + * @summary verify that whitebox functions can be linked and executed 27.7 + * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI ParserTest.java 27.8 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ParserTest 27.9 + */ 27.10 + 27.11 +import java.math.BigInteger; 27.12 + 27.13 +import sun.hotspot.parser.DiagnosticCommand; 27.14 +import sun.hotspot.parser.DiagnosticCommand.DiagnosticArgumentType; 27.15 +import sun.hotspot.WhiteBox; 27.16 + 27.17 +public class ParserTest { 27.18 + WhiteBox wb; 27.19 + 27.20 + public ParserTest() throws Exception { 27.21 + wb = WhiteBox.getWhiteBox(); 27.22 + 27.23 + testNanoTime(); 27.24 + testJLong(); 27.25 + testBool(); 27.26 + testMemorySize(); 27.27 + } 27.28 + 27.29 + public static void main(String... args) throws Exception { 27.30 + new ParserTest(); 27.31 + } 27.32 + 27.33 + public void testNanoTime() throws Exception { 27.34 + String name = "name"; 27.35 + DiagnosticCommand arg = new DiagnosticCommand(name, 27.36 + "desc", DiagnosticArgumentType.NANOTIME, 27.37 + false, "0"); 27.38 + DiagnosticCommand[] args = {arg}; 27.39 + 27.40 + BigInteger bi = new BigInteger("7"); 27.41 + //These should work 27.42 + parse(name, bi.toString(), name + "=7ns", args); 27.43 + 27.44 + bi = bi.multiply(BigInteger.valueOf(1000)); 27.45 + parse(name, bi.toString(), name + "=7us", args); 27.46 + 27.47 + bi = bi.multiply(BigInteger.valueOf(1000)); 27.48 + parse(name, bi.toString(), name + "=7ms", args); 27.49 + 27.50 + bi = bi.multiply(BigInteger.valueOf(1000)); 27.51 + parse(name, bi.toString(), name + "=7s", args); 27.52 + 27.53 + bi = bi.multiply(BigInteger.valueOf(60)); 27.54 + parse(name, bi.toString() , name + "=7m", args); 27.55 + 27.56 + bi = bi.multiply(BigInteger.valueOf(60)); 27.57 + parse(name, bi.toString() , name + "=7h", args); 27.58 + 27.59 + bi = bi.multiply(BigInteger.valueOf(24)); 27.60 + parse(name, bi.toString() , name + "=7d", args); 27.61 + 27.62 + parse(name, "0", name + "=0", args); 27.63 + 27.64 + shouldFail(name + "=7xs", args); 27.65 + shouldFail(name + "=7mms", args); 27.66 + shouldFail(name + "=7f", args); 27.67 + //Currently, only value 0 is allowed without unit 27.68 + shouldFail(name + "=7", args); 27.69 + } 27.70 + 27.71 + public void testJLong() throws Exception { 27.72 + String name = "name"; 27.73 + DiagnosticCommand arg = new DiagnosticCommand(name, 27.74 + "desc", DiagnosticArgumentType.JLONG, 27.75 + false, "0"); 27.76 + DiagnosticCommand[] args = {arg}; 27.77 + 27.78 + wb.parseCommandLine(name + "=10", args); 27.79 + parse(name, "10", name + "=10", args); 27.80 + parse(name, "-5", name + "=-5", args); 27.81 + 27.82 + //shouldFail(name + "=12m", args); <-- should fail, doesn't 27.83 + } 27.84 + 27.85 + public void testBool() throws Exception { 27.86 + String name = "name"; 27.87 + DiagnosticCommand arg = new DiagnosticCommand(name, 27.88 + "desc", DiagnosticArgumentType.BOOLEAN, 27.89 + false, "false"); 27.90 + DiagnosticCommand[] args = {arg}; 27.91 + 27.92 + parse(name, "true", name + "=true", args); 27.93 + parse(name, "false", name + "=false", args); 27.94 + parse(name, "true", name, args); 27.95 + 27.96 + //Empty commandline to parse, tests default value 27.97 + //of the parameter "name" 27.98 + parse(name, "false", "", args); 27.99 + } 27.100 + 27.101 + public void testMemorySize() throws Exception { 27.102 + String name = "name"; 27.103 + String defaultValue = "1024"; 27.104 + DiagnosticCommand arg = new DiagnosticCommand(name, 27.105 + "desc", DiagnosticArgumentType.MEMORYSIZE, 27.106 + false, defaultValue); 27.107 + DiagnosticCommand[] args = {arg}; 27.108 + 27.109 + BigInteger bi = new BigInteger("7"); 27.110 + parse(name, bi.toString(), name + "=7b", args); 27.111 + 27.112 + bi = bi.multiply(BigInteger.valueOf(1024)); 27.113 + parse(name, bi.toString(), name + "=7k", args); 27.114 + 27.115 + bi = bi.multiply(BigInteger.valueOf(1024)); 27.116 + parse(name, bi.toString(), name + "=7m", args); 27.117 + 27.118 + bi = bi.multiply(BigInteger.valueOf(1024)); 27.119 + parse(name, bi.toString(), name + "=7g", args); 27.120 + parse(name, defaultValue, "", args); 27.121 + 27.122 + //shouldFail(name + "=7gg", args); <---- should fail, doesn't 27.123 + //shouldFail(name + "=7t", args); <----- should fail, doesn't 27.124 + } 27.125 + 27.126 + public void parse(String searchName, String expectedValue, 27.127 + String cmdLine, DiagnosticCommand[] argumentTypes) throws Exception { 27.128 + //parseCommandLine will return an object array that looks like 27.129 + //{<name of parsed object>, <of parsed object> ... } 27.130 + Object[] res = wb.parseCommandLine(cmdLine, argumentTypes); 27.131 + for (int i = 0; i < res.length-1; i+=2) { 27.132 + String parsedName = (String) res[i]; 27.133 + if (searchName.equals(parsedName)) { 27.134 + String parsedValue = (String) res[i+1]; 27.135 + if (expectedValue.equals(parsedValue)) { 27.136 + return; 27.137 + } else { 27.138 + throw new Exception("Parsing of cmdline '" + cmdLine + "' failed!\n" 27.139 + + searchName + " parsed as " + parsedValue 27.140 + + "! Expected: " + expectedValue); 27.141 + } 27.142 + } 27.143 + } 27.144 + throw new Exception(searchName + " not found as a parsed Argument!"); 27.145 + } 27.146 + 27.147 + private void shouldFail(String argument, DiagnosticCommand[] argumentTypes) throws Exception { 27.148 + try { 27.149 + wb.parseCommandLine(argument, argumentTypes); 27.150 + throw new Exception("Parser accepted argument: " + argument); 27.151 + } catch (IllegalArgumentException e) { 27.152 + //expected 27.153 + } 27.154 + } 27.155 +}