# HG changeset patch # User never # Date 1333663684 25200 # Node ID e2d49b982f2812ef6b46d1b78f99ec044e10ee31 # Parent f7897aacb9ce082c6b126ead143a2e1406696322# Parent a43041fec3436366d52f4bca93328da5005b8cca Merge diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BranchData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BranchData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BranchData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CounterData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CounterData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CounterData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DataLayout.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DataLayout.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DataLayout.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JumpData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JumpData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JumpData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java Thu Apr 05 15:08:04 2012 -0700 @@ -1,24 +1,24 @@ /* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * + * 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. * */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/bsd/makefiles/wb.make --- a/hotspot/make/bsd/makefiles/wb.make Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/bsd/makefiles/wb.make Thu Apr 05 15:08:04 2012 -0700 @@ -36,7 +36,7 @@ $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) $(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) - $(REMOTE) $(COMPILE.JAVAC) -nowarn -d $(WB_JAVA_CLASSDIR) $< + $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< $(WB_JAR): $(WB_JAVA_CLASSES) $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ . diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/linux/makefiles/wb.make --- a/hotspot/make/linux/makefiles/wb.make Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/linux/makefiles/wb.make Thu Apr 05 15:08:04 2012 -0700 @@ -36,7 +36,7 @@ $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) $(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) - $(REMOTE) $(COMPILE.JAVAC) -nowarn -d $(WB_JAVA_CLASSDIR) $< + $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< $(WB_JAR): $(WB_JAVA_CLASSES) $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ . diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/solaris/makefiles/wb.make --- a/hotspot/make/solaris/makefiles/wb.make Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/solaris/makefiles/wb.make Thu Apr 05 15:08:04 2012 -0700 @@ -36,7 +36,7 @@ $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) $(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) - $(REMOTE) $(COMPILE.JAVAC) -nowarn -d $(WB_JAVA_CLASSDIR) $< + $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< $(WB_JAR): $(WB_JAVA_CLASSES) $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ . diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/windows/create_obj_files.sh --- a/hotspot/make/windows/create_obj_files.sh Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/windows/create_obj_files.sh Thu Apr 05 15:08:04 2012 -0700 @@ -80,6 +80,8 @@ BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr" fi +BASE_PATHS="${BASE_PATHS} ${COMMONSRC}/share/vm/prims/wbtestmethods" + CORE_PATHS="${BASE_PATHS}" # shared is already in BASE_PATHS. Should add vm/memory but that one is also in BASE_PATHS. if [ -d "${ALTSRC}/share/vm/gc_implementation" ]; then diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/windows/makefiles/projectcreator.make --- a/hotspot/make/windows/makefiles/projectcreator.make Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/windows/makefiles/projectcreator.make Thu Apr 05 15:08:04 2012 -0700 @@ -51,6 +51,7 @@ -relativeInclude src\closed\cpu\$(Platform_arch)\vm \ -relativeInclude src\share\vm \ -relativeInclude src\share\vm\precompiled \ + -relativeInclude src\share\vm\prims\wbtestmethods \ -relativeInclude src\share\vm\prims \ -relativeInclude src\os\windows\vm \ -relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/windows/makefiles/vm.make --- a/hotspot/make/windows/makefiles/vm.make Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/windows/makefiles/vm.make Thu Apr 05 15:08:04 2012 -0700 @@ -172,6 +172,7 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/memory VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/oops VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims/wbtestmethods VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/runtime VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/services VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/trace @@ -269,6 +270,9 @@ {$(COMMONSRC)\share\vm\prims}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\prims\wbtestmethods}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\runtime}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -349,6 +353,9 @@ {$(ALTSRC)\share\vm\prims}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(ALTSRC)\share\vm\prims\wbtestmethods}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(ALTSRC)\share\vm\runtime}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< diff -r f7897aacb9ce -r e2d49b982f28 hotspot/make/windows/makefiles/wb.make --- a/hotspot/make/windows/makefiles/wb.make Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/make/windows/makefiles/wb.make Thu Apr 05 15:08:04 2012 -0700 @@ -40,7 +40,7 @@ {$(WorkSpace)\src\share\tools\whitebox\sun\hotspot}.java.class:: - $(COMPILE_JAVAC) -d $(WB_CLASSES) $< + $(COMPILE_JAVAC) -sourcepath $(WBSRCDIR) -d $(WB_CLASSES) $< $(WB_JAR): wb_java_srcs $(RUN_JAR) cf $@ -C $(WB_CLASSES) . diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java --- a/hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java Thu Apr 05 15:08:04 2012 -0700 @@ -24,6 +24,7 @@ package sun.hotspot; import java.security.BasicPermission; +import sun.hotspot.parser.DiagnosticCommand; public class WhiteBox { @@ -67,4 +68,5 @@ public native boolean g1IsHumongous(Object o); public native long g1NumFreeRegions(); public native int g1RegionSize(); + public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); } diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/tools/whitebox/sun/hotspot/parser/DiagnosticCommand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/tools/whitebox/sun/hotspot/parser/DiagnosticCommand.java Thu Apr 05 15:08:04 2012 -0700 @@ -0,0 +1,43 @@ +package sun.hotspot.parser; + +public class DiagnosticCommand { + + public enum DiagnosticArgumentType { + JLONG, BOOLEAN, STRING, NANOTIME, STRINGARRAY, MEMORYSIZE + } + + private String name; + private String desc; + private DiagnosticArgumentType type; + private boolean mandatory; + private String defaultValue; + + public DiagnosticCommand(String name, String desc, DiagnosticArgumentType type, + boolean mandatory, String defaultValue) { + this.name = name; + this.desc = desc; + this.type = type; + this.mandatory = mandatory; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public DiagnosticArgumentType getType() { + return type; + } + + public boolean isMandatory() { + return mandatory; + } + + public String getDefaultValue() { + return defaultValue; + } +} diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -81,7 +81,7 @@ #define JAVA_7_VERSION 51 -void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int length, TRAPS) { +void ClassFileParser::parse_constant_pool_entries(Handle class_loader, constantPoolHandle cp, int length, TRAPS) { // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to @@ -272,7 +272,7 @@ indices[names_count] = index; hashValues[names_count++] = hash; if (names_count == SymbolTable::symbol_alloc_batch_size) { - SymbolTable::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(class_loader, cp, names_count, names, lengths, indices, hashValues, CHECK); names_count = 0; } } else { @@ -289,7 +289,7 @@ // Allocate the remaining symbols if (names_count > 0) { - SymbolTable::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(class_loader, cp, names_count, names, lengths, indices, hashValues, CHECK); } // Copy _current pointer of local copy back to stream(). @@ -318,7 +318,7 @@ bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } -constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { +constantPoolHandle ClassFileParser::parse_constant_pool(Handle class_loader, TRAPS) { ClassFileStream* cfs = stream(); constantPoolHandle nullHandle; @@ -337,7 +337,7 @@ ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. // parsing constant pool entries - parse_constant_pool_entries(cp, length, CHECK_(nullHandle)); + parse_constant_pool_entries(class_loader, cp, length, CHECK_(nullHandle)); int index = 1; // declared outside of loops for portability @@ -2803,7 +2803,7 @@ _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool - constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle)); + constantPoolHandle cp = parse_constant_pool(class_loader, CHECK_(nullHandle)); ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. int cp_size = cp->length(); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/classfile/classFileParser.hpp --- a/hotspot/src/share/vm/classfile/classFileParser.hpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -68,9 +68,10 @@ void set_stream(ClassFileStream* st) { _stream = st; } // Constant pool parsing - void parse_constant_pool_entries(constantPoolHandle cp, int length, TRAPS); + void parse_constant_pool_entries(Handle class_loader, + constantPoolHandle cp, int length, TRAPS); - constantPoolHandle parse_constant_pool(TRAPS); + constantPoolHandle parse_constant_pool(Handle class_loader, TRAPS); // Interface parsing objArrayHandle parse_interfaces(constantPoolHandle cp, diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/classfile/symbolTable.cpp --- a/hotspot/src/share/vm/classfile/symbolTable.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -27,6 +27,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/gcLocker.inline.hpp" #include "oops/oop.inline.hpp" @@ -37,34 +38,35 @@ // -------------------------------------------------------------------------- SymbolTable* SymbolTable::_the_table = NULL; +// Static arena for symbols that are not deallocated +Arena* SymbolTable::_arena = NULL; -Symbol* SymbolTable::allocate_symbol(const u1* name, int len, TRAPS) { +Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) { // Don't allow symbols to be created which cannot fit in a Symbol*. if (len > Symbol::max_length()) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "name is too long to represent"); } - Symbol* sym = new (len) Symbol(name, len); + Symbol* sym; + // Allocate symbols in the C heap when dumping shared spaces in case there + // are temporary symbols we can remove. + if (c_heap || DumpSharedSpaces) { + // refcount starts as 1 + sym = new (len, THREAD) Symbol(name, len, 1); + } else { + sym = new (len, arena(), THREAD) Symbol(name, len, -1); + } assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted"); return sym; } -bool SymbolTable::allocate_symbols(int names_count, const u1** names, - int* lengths, Symbol** syms, TRAPS) { - for (int i = 0; i< names_count; i++) { - if (lengths[i] > Symbol::max_length()) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), - "name is too long to represent"); - } +void SymbolTable::initialize_symbols(int arena_alloc_size) { + // Initialize the arena for global symbols, size passed in depends on CDS. + if (arena_alloc_size == 0) { + _arena = new Arena(); + } else { + _arena = new Arena(arena_alloc_size); } - - for (int i = 0; i< names_count; i++) { - int len = lengths[i]; - syms[i] = new (len) Symbol(names[i], len); - assert(syms[i] != NULL, "new should call vm_exit_out_of_memory if " - "C_HEAP is exhausted"); - } - return true; } // Call function for all symbols in the symbol table. @@ -83,8 +85,7 @@ int SymbolTable::symbols_counted = 0; // Remove unreferenced symbols from the symbol table -// This is done late during GC. This doesn't use the hash table unlink because -// it assumes that the literals are oops. +// This is done late during GC. void SymbolTable::unlink() { int removed = 0; int total = 0; @@ -156,7 +157,7 @@ if (s != NULL) return s; // Otherwise, add to symbol to table - return the_table()->basic_add(index, (u1*)name, len, hashValue, CHECK_NULL); + return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL); } Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) { @@ -192,7 +193,7 @@ // We can't include the code in No_Safepoint_Verifier because of the // ResourceMark. - return the_table()->basic_add(index, (u1*)buffer, len, hashValue, CHECK_NULL); + return the_table()->basic_add(index, (u1*)buffer, len, hashValue, true, CHECK_NULL); } Symbol* SymbolTable::lookup_only(const char* name, int len, @@ -256,71 +257,81 @@ } } -void SymbolTable::add(constantPoolHandle cp, int names_count, +void SymbolTable::add(Handle class_loader, constantPoolHandle cp, + int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS) { SymbolTable* table = the_table(); - bool added = table->basic_add(cp, names_count, names, lengths, + bool added = table->basic_add(class_loader, cp, names_count, names, lengths, cp_indices, hashValues, CHECK); if (!added) { // do it the hard way for (int i=0; ihash_to_index(hashValues[i]); - Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], - hashValues[i], CHECK); + bool c_heap = class_loader() != NULL; + Symbol* sym = table->basic_add(index, (u1*)names[i], lengths[i], hashValues[i], c_heap, CHECK); cp->symbol_at_put(cp_indices[i], sym); } } } +Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) { + unsigned int hash; + Symbol* result = SymbolTable::lookup_only((char*)name, (int)strlen(name), hash); + if (result != NULL) { + return result; + } + SymbolTable* table = the_table(); + int index = table->hash_to_index(hash); + return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD); +} + Symbol* SymbolTable::basic_add(int index, u1 *name, int len, - unsigned int hashValue, TRAPS) { + unsigned int hashValue, bool c_heap, TRAPS) { assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), "proposed name of symbol must be stable"); - // We assume that lookup() has been called already, that it failed, - // and symbol was not found. We create the symbol here. - Symbol* sym = allocate_symbol(name, len, CHECK_NULL); - - // Allocation must be done before grabbing the SymbolTable_lock lock + // Grab SymbolTable_lock first. MutexLocker ml(SymbolTable_lock, THREAD); - assert(sym->equals((char*)name, len), "symbol must be properly initialized"); - // Since look-up was done lock-free, we need to check if another // thread beat us in the race to insert the symbol. - Symbol* test = lookup(index, (char*)name, len, hashValue); if (test != NULL) { - // A race occurred and another thread introduced the symbol, this one - // will be dropped and collected. - delete sym; + // A race occurred and another thread introduced the symbol. assert(test->refcount() != 0, "lookup should have incremented the count"); return test; } + // Create a new symbol. + Symbol* sym = allocate_symbol(name, len, c_heap, CHECK_NULL); + assert(sym->equals((char*)name, len), "symbol must be properly initialized"); + HashtableEntry* entry = new_entry(hashValue, sym); - sym->increment_refcount(); add_entry(index, entry); return sym; } -bool SymbolTable::basic_add(constantPoolHandle cp, int names_count, +// This version of basic_add adds symbols in batch from the constant pool +// parsing. +bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp, + int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS) { - Symbol* syms[symbol_alloc_batch_size]; - bool allocated = allocate_symbols(names_count, (const u1**)names, lengths, - syms, CHECK_false); - if (!allocated) { - return false; + + // Check symbol names are not too long. If any are too long, don't add any. + for (int i = 0; i< names_count; i++) { + if (lengths[i] > Symbol::max_length()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), + "name is too long to represent"); + } } - // Allocation must be done before grabbing the SymbolTable_lock lock + // Hold SymbolTable_lock through the symbol creation MutexLocker ml(SymbolTable_lock, THREAD); for (int i=0; iequals(names[i], lengths[i]), "symbol must be properly initialized"); // Since look-up was done lock-free, we need to check if another // thread beat us in the race to insert the symbol. int index = hash_to_index(hashValues[i]); @@ -330,16 +341,17 @@ // will be dropped and collected. Use test instead. cp->symbol_at_put(cp_indices[i], test); assert(test->refcount() != 0, "lookup should have incremented the count"); - delete syms[i]; } else { - Symbol* sym = syms[i]; + // Create a new symbol. The null class loader is never unloaded so these + // are allocated specially in a permanent arena. + bool c_heap = class_loader() != NULL; + Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false)); + assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be??? HashtableEntry* entry = new_entry(hashValues[i], sym); - sym->increment_refcount(); // increment refcount in external hashtable add_entry(index, entry); cp->symbol_at_put(cp_indices[i], sym); } } - return true; } @@ -406,6 +418,8 @@ ((float)symbols_removed/(float)symbols_counted)* 100); } tty->print_cr("Reference counts %5d", Symbol::_total_count); + tty->print_cr("Symbol arena size %5d used %5d", + arena()->size_in_bytes(), arena()->used()); tty->print_cr("Histogram of symbol length:"); tty->print_cr("%8s %5d", "Total ", total); tty->print_cr("%8s %5d", "Maximum", max_symbols); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/classfile/symbolTable.hpp --- a/hotspot/src/share/vm/classfile/symbolTable.hpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -82,24 +82,24 @@ static int symbols_removed; static int symbols_counted; - Symbol* allocate_symbol(const u1* name, int len, TRAPS); // Assumes no characters larger than 0x7F - bool allocate_symbols(int names_count, const u1** names, int* lengths, Symbol** syms, TRAPS); + Symbol* allocate_symbol(const u1* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F // Adding elements - Symbol* basic_add(int index, u1* name, int len, - unsigned int hashValue, TRAPS); - bool basic_add(constantPoolHandle cp, int names_count, + Symbol* basic_add(int index, u1* name, int len, unsigned int hashValue, + bool c_heap, TRAPS); + + bool basic_add(Handle class_loader, constantPoolHandle cp, int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS); - static void new_symbols(constantPoolHandle cp, int names_count, + static void new_symbols(Handle class_loader, constantPoolHandle cp, + int names_count, const char** name, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS) { - add(cp, names_count, name, lengths, cp_indices, hashValues, THREAD); + add(class_loader, cp, names_count, name, lengths, cp_indices, hashValues, THREAD); } - // Table size enum { symbol_table_size = 20011 @@ -114,10 +114,16 @@ : Hashtable(symbol_table_size, sizeof (HashtableEntry), t, number_of_entries) {} + // Arena for permanent symbols (null class loader) that are never unloaded + static Arena* _arena; + static Arena* arena() { return _arena; } // called for statistics + static void initialize_symbols(int arena_alloc_size = 0); public: enum { - symbol_alloc_batch_size = 8 + symbol_alloc_batch_size = 8, + // Pick initial size based on java -version size measurements + symbol_alloc_arena_size = 360*K }; // The symbol table @@ -126,6 +132,7 @@ static void create_table() { assert(_the_table == NULL, "One symbol table allowed."); _the_table = new SymbolTable(); + initialize_symbols(symbol_alloc_arena_size); } static void create_table(HashtableBucket* t, int length, @@ -134,6 +141,9 @@ assert(length == symbol_table_size * sizeof(HashtableBucket), "bad shared symbol size."); _the_table = new SymbolTable(t, number_of_entries); + // if CDS give symbol table a default arena size since most symbols + // are already allocated in the shared misc section. + initialize_symbols(); } static Symbol* lookup(const char* name, int len, TRAPS); @@ -151,7 +161,7 @@ static Symbol* lookup_unicode(const jchar* name, int len, TRAPS); static Symbol* lookup_only_unicode(const jchar* name, int len, unsigned int& hash); - static void add(constantPoolHandle cp, int names_count, + static void add(Handle class_loader, constantPoolHandle cp, int names_count, const char** names, int* lengths, int* cp_indices, unsigned int* hashValues, TRAPS); @@ -174,6 +184,9 @@ return lookup(sym, begin, end, THREAD); } + // Create a symbol in the arena for symbols that are not deleted + static Symbol* new_permanent_symbol(const char* name, TRAPS); + // Symbol lookup static Symbol* lookup(int index, const char* name, int len, TRAPS); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/classfile/vmSymbols.cpp --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -79,7 +79,7 @@ if (!UseSharedSpaces) { const char* string = &vm_symbol_bodies[0]; for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { - Symbol* sym = SymbolTable::new_symbol(string, CHECK); + Symbol* sym = SymbolTable::new_permanent_symbol(string, CHECK); _symbols[index] = sym; string += strlen(string); // skip string body string += 1; // skip trailing null @@ -128,7 +128,7 @@ // Spot-check correspondence between strings, symbols, and enums: assert(_symbols[NO_SID] == NULL, "must be"); const char* str = "java/lang/Object"; - TempNewSymbol jlo = SymbolTable::new_symbol(str, CHECK); + TempNewSymbol jlo = SymbolTable::new_permanent_symbol(str, CHECK); assert(strncmp(str, (char*)jlo->base(), jlo->utf8_length()) == 0, ""); assert(jlo == java_lang_Object(), ""); SID sid = VM_SYMBOL_ENUM_NAME(java_lang_Object); @@ -147,7 +147,7 @@ // The string "format" happens (at the moment) not to be a vmSymbol, // though it is a method name in java.lang.String. str = "format"; - TempNewSymbol fmt = SymbolTable::new_symbol(str, CHECK); + TempNewSymbol fmt = SymbolTable::new_permanent_symbol(str, CHECK); sid = find_sid(fmt); assert(sid == NO_SID, "symbol index works (negative test)"); } diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/memory/dump.cpp --- a/hotspot/src/share/vm/memory/dump.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/memory/dump.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, 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 @@ -1488,12 +1488,11 @@ // sun.io.Converters static const char obj_array_sig[] = "[[Ljava/lang/Object;"; - SymbolTable::lookup(obj_array_sig, (int)strlen(obj_array_sig), THREAD); + (void)SymbolTable::new_permanent_symbol(obj_array_sig, THREAD); // java.util.HashMap static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;"; - SymbolTable::lookup(map_entry_array_sig, (int)strlen(map_entry_array_sig), - THREAD); + (void)SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD); tty->print("Loading classes to share ... "); while ((fgets(class_name, sizeof class_name, file)) != NULL) { @@ -1512,7 +1511,7 @@ computed_jsum = jsum(computed_jsum, class_name, (const int)name_len - 1); // Got a class name - load it. - TempNewSymbol class_name_symbol = SymbolTable::new_symbol(class_name, THREAD); + Symbol* class_name_symbol = SymbolTable::new_permanent_symbol(class_name, THREAD); guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol."); klassOop klass = SystemDictionary::resolve_or_null(class_name_symbol, THREAD); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/oops/objArrayKlassKlass.cpp --- a/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -137,7 +137,7 @@ new_str[idx++] = ';'; } new_str[idx++] = '\0'; - name = SymbolTable::new_symbol(new_str, CHECK_0); + name = SymbolTable::new_permanent_symbol(new_str, CHECK_0); if (element_klass->oop_is_instance()) { instanceKlass* ik = instanceKlass::cast(element_klass()); ik->set_array_name(name); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/oops/symbol.cpp --- a/hotspot/src/share/vm/oops/symbol.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/oops/symbol.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -29,15 +29,25 @@ #include "runtime/os.hpp" #include "memory/allocation.inline.hpp" -Symbol::Symbol(const u1* name, int length) : _refcount(0), _length(length) { +Symbol::Symbol(const u1* name, int length, int refcount) : _refcount(refcount), _length(length) { _identity_hash = os::random(); for (int i = 0; i < _length; i++) { byte_at_put(i, name[i]); } } -void* Symbol::operator new(size_t size, int len) { - return (void *) AllocateHeap(object_size(len) * HeapWordSize, "symbol"); +void* Symbol::operator new(size_t sz, int len, TRAPS) { + int alloc_size = object_size(len)*HeapWordSize; + address res = (address) AllocateHeap(alloc_size, "symbol"); + DEBUG_ONLY(set_allocation_type(res, ResourceObj::C_HEAP);) + return res; +} + +void* Symbol::operator new(size_t sz, int len, Arena* arena, TRAPS) { + int alloc_size = object_size(len)*HeapWordSize; + address res = (address)arena->Amalloc(alloc_size); + DEBUG_ONLY(set_allocation_type(res, ResourceObj::ARENA);) + return res; } // ------------------------------------------------------------------ @@ -206,26 +216,5 @@ } } -void Symbol::increment_refcount() { - // Only increment the refcount if positive. If negative either - // overflow has occurred or it is a permanent symbol in a read only - // shared archive. - if (_refcount >= 0) { - Atomic::inc(&_refcount); - NOT_PRODUCT(Atomic::inc(&_total_count);) - } -} - -void Symbol::decrement_refcount() { - if (_refcount >= 0) { - Atomic::dec(&_refcount); -#ifdef ASSERT - if (_refcount < 0) { - print(); - assert(false, "reference count underflow for symbol"); - } -#endif - } -} - +// SymbolTable prints this in its statistics NOT_PRODUCT(int Symbol::_total_count = 0;) diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/oops/symbol.hpp --- a/hotspot/src/share/vm/oops/symbol.hpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/oops/symbol.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -27,6 +27,7 @@ #include "utilities/utf8.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" // A Symbol is a canonicalized string. // All Symbols reside in global SymbolTable and are reference counted. @@ -95,7 +96,7 @@ // TempNewSymbol (passed in as a parameter) so the reference count on its symbol // will be decremented when it goes out of scope. -class Symbol : public CHeapObj { +class Symbol : public ResourceObj { friend class VMStructs; friend class SymbolTable; friend class MoveSymbols; @@ -111,7 +112,7 @@ }; static int object_size(int length) { - size_t size = heap_word_size(sizeof(Symbol) + length); + size_t size = heap_word_size(sizeof(Symbol) + (length > 0 ? length - 1 : 0)); return align_object_size(size); } @@ -120,28 +121,25 @@ _body[index] = value; } - Symbol(const u1* name, int length); - void* operator new(size_t size, int len); + Symbol(const u1* name, int length, int refcount); + void* operator new(size_t size, int len, TRAPS); + void* operator new(size_t size, int len, Arena* arena, TRAPS); public: // Low-level access (used with care, since not GC-safe) const jbyte* base() const { return &_body[0]; } - int object_size() { return object_size(utf8_length()); } + int object_size() { return object_size(utf8_length()); } // Returns the largest size symbol we can safely hold. - static int max_length() { - return max_symbol_length; - } + static int max_length() { return max_symbol_length; } - int identity_hash() { - return _identity_hash; - } + int identity_hash() { return _identity_hash; } // Reference counting. See comments above this class for when to use. - int refcount() const { return _refcount; } - void increment_refcount(); - void decrement_refcount(); + int refcount() const { return _refcount; } + inline void increment_refcount(); + inline void decrement_refcount(); int byte_at(int index) const { assert(index >=0 && index < _length, "symbol index overflow"); @@ -220,4 +218,26 @@ return (((uintptr_t)this < (uintptr_t)other) ? -1 : ((uintptr_t)this == (uintptr_t) other) ? 0 : 1); } + +inline void Symbol::increment_refcount() { + // Only increment the refcount if positive. If negative either + // overflow has occurred or it is a permanent symbol in a read only + // shared archive. + if (_refcount >= 0) { + Atomic::inc(&_refcount); + NOT_PRODUCT(Atomic::inc(&_total_count);) + } +} + +inline void Symbol::decrement_refcount() { + if (_refcount >= 0) { + Atomic::dec(&_refcount); +#ifdef ASSERT + if (_refcount < 0) { + print(); + assert(false, "reference count underflow for symbol"); + } +#endif + } +} #endif // SHARE_VM_OOPS_SYMBOL_HPP diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/oops/typeArrayKlass.cpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -55,7 +55,7 @@ Symbol* sym = NULL; if (name_str != NULL) { - sym = SymbolTable::new_symbol(name_str, CHECK_NULL); + sym = SymbolTable::new_permanent_symbol(name_str, CHECK_NULL); } KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj()); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/prims/wbtestmethods/parserTests.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/prims/wbtestmethods/parserTests.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + * + */ + +#include "precompiled.hpp" + +#include "classfile/symbolTable.hpp" + +#include "prims/jni.h" +#include "prims/whitebox.hpp" +#include "prims/wbtestmethods/parserTests.hpp" +#include "runtime/interfaceSupport.hpp" + +#include "memory/oopFactory.hpp" + +#include "services/diagnosticArgument.hpp" +#include "services/diagnosticFramework.hpp" + +//There's no way of beforeahnd knowing an upper size +//Of the length of a string representation of +//the value of an argument. +#define VALUE_MAXLEN 256 + +// DiagnosticFramework test utility methods + +/* + * The DiagnosticArgumentType class contains an enum that says which type + * this argument represents. (JLONG, BOOLEAN etc). + * This method Returns a char* representation of that enum value. + */ +static const char* lookup_diagnosticArgumentEnum(const char* field_name, oop object) { + Thread* THREAD = Thread::current(); + const char* enum_sig = "Lsun/hotspot/parser/DiagnosticCommand$DiagnosticArgumentType;"; + TempNewSymbol enumSigSymbol = SymbolTable::lookup(enum_sig, (int) strlen(enum_sig), THREAD); + int offset = WhiteBox::offset_for_field(field_name, object, enumSigSymbol); + oop enumOop = object->obj_field(offset); + + const char* ret = WhiteBox::lookup_jstring("name", enumOop); + return ret; +} + +/* + * Takes an oop to a DiagnosticArgumentType-instance and + * reads the fields from it. Fills an native DCmdParser with + * this info. + */ +static void fill_in_parser(DCmdParser* parser, oop argument) +{ + const char* name = WhiteBox::lookup_jstring("name", argument); + const char* desc = WhiteBox::lookup_jstring("desc", argument); + const char* default_value = WhiteBox::lookup_jstring("defaultValue", argument); + bool mandatory = WhiteBox::lookup_bool("mandatory", argument); + const char* type = lookup_diagnosticArgumentEnum("type", argument); + + if (strcmp(type, "STRING") == 0) { + DCmdArgument* argument = new DCmdArgument( + name, desc, + "STRING", mandatory, default_value); + parser->add_dcmd_option(argument); + } else if (strcmp(type, "NANOTIME") == 0) { + DCmdArgument* argument = new DCmdArgument( + name, desc, + "NANOTIME", mandatory, default_value); + parser->add_dcmd_option(argument); + } else if (strcmp(type, "JLONG") == 0) { + DCmdArgument* argument = new DCmdArgument( + name, desc, + "JLONG", mandatory, default_value); + parser->add_dcmd_option(argument); + } else if (strcmp(type, "BOOLEAN") == 0) { + DCmdArgument* argument = new DCmdArgument( + name, desc, + "BOOLEAN", mandatory, default_value); + parser->add_dcmd_option(argument); + } else if (strcmp(type, "MEMORYSIZE") == 0) { + DCmdArgument* argument = new DCmdArgument( + name, desc, + "MEMORY SIZE", mandatory, default_value); + parser->add_dcmd_option(argument); + } else if (strcmp(type, "STRINGARRAY") == 0) { + DCmdArgument* argument = new DCmdArgument( + name, desc, + "STRING SET", mandatory); + parser->add_dcmd_option(argument); + } +} + +/* + * Will Fill in a java object array with alternating names of parsed command line options and + * the value that has been parsed for it: + * { name, value, name, value ... } + * This can then be checked from java. + */ +WB_ENTRY(jobjectArray, WB_ParseCommandLine(JNIEnv* env, jobject o, jstring j_cmdline, jobjectArray arguments)) + ResourceMark rm; + DCmdParser parser; + + const char* c_cmdline = java_lang_String::as_utf8_string(JNIHandles::resolve(j_cmdline)); + objArrayOop argumentArray = objArrayOop(JNIHandles::resolve_non_null(arguments)); + + int length = argumentArray->length(); + + for (int i = 0; i < length; i++) { + oop argument_oop = argumentArray->obj_at(i); + fill_in_parser(&parser, argument_oop); + } + + CmdLine cmdline(c_cmdline, strlen(c_cmdline), true); + parser.parse(&cmdline,',',CHECK_NULL); + + klassOop k = SystemDictionary::Object_klass(); + objArrayOop returnvalue_array = oopFactory::new_objArray(k, parser.num_arguments() * 2, CHECK_NULL); + + GrowableArray*parsedArgNames = parser.argument_name_array(); + + for (int i = 0; i < parser.num_arguments(); i++) { + oop parsedName = java_lang_String::create_oop_from_str(parsedArgNames->at(i), CHECK_NULL); + returnvalue_array->obj_at_put(i*2, parsedName); + GenDCmdArgument* arg = parser.lookup_dcmd_option(parsedArgNames->at(i), strlen(parsedArgNames->at(i))); + char buf[VALUE_MAXLEN]; + arg->value_as_str(buf, sizeof(buf)); + oop parsedValue = java_lang_String::create_oop_from_str(buf, CHECK_NULL); + returnvalue_array->obj_at_put(i*2+1, parsedValue); + } + + return (jobjectArray) JNIHandles::make_local(returnvalue_array); + +WB_END diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/prims/wbtestmethods/parserTests.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/prims/wbtestmethods/parserTests.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, 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. + */ + +#ifndef SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H +#define SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H + +#include "prims/jni.h" +#include "prims/whitebox.hpp" + +WB_METHOD_DECLARE WB_ParseCommandLine(JNIEnv* env, jobject o, jstring args, jobjectArray arguments); + +#endif //SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -24,11 +24,14 @@ #include "precompiled.hpp" -#include "jni.h" - #include "memory/universe.hpp" #include "oops/oop.inline.hpp" + +#include "classfile/symbolTable.hpp" + #include "prims/whitebox.hpp" +#include "prims/wbtestmethods/parserTests.hpp" + #include "runtime/interfaceSupport.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" @@ -41,13 +44,6 @@ bool WhiteBox::_used = false; -// Entry macro to transition from JNI to VM state. - -#define WB_ENTRY(result_type, header) JNI_ENTRY(result_type, header) -#define WB_END JNI_END - -// Definitions of functions exposed via Whitebox API - WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) return (jlong)(void*)JNIHandles::resolve(obj); WB_END @@ -81,11 +77,63 @@ WB_END #endif // !SERIALGC +//Some convenience methods to deal with objects from java +int WhiteBox::offset_for_field(const char* field_name, oop object, + Symbol* signature_symbol) { + assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid"); + Thread* THREAD = Thread::current(); + + //Get the class of our object + klassOop arg_klass = object->klass(); + //Turn it into an instance-klass + instanceKlass* ik = instanceKlass::cast(arg_klass); + + //Create symbols to look for in the class + TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name), + THREAD); + + //To be filled in with an offset of the field we're looking for + fieldDescriptor fd; + + klassOop res = ik->find_field(name_symbol, signature_symbol, &fd); + if (res == NULL) { + tty->print_cr("Invalid layout of %s at %s", ik->external_name(), + name_symbol->as_C_string()); + fatal("Invalid layout of preloaded class"); + } + + //fetch the field at the offset we've found + int dest_offset = fd.offset(); + + return dest_offset; +} + + +const char* WhiteBox::lookup_jstring(const char* field_name, oop object) { + int offset = offset_for_field(field_name, object, + vmSymbols::string_signature()); + oop string = object->obj_field(offset); + const char* ret = java_lang_String::as_utf8_string(string); + return ret; +} + +bool WhiteBox::lookup_bool(const char* field_name, oop object) { + int offset = + offset_for_field(field_name, object, vmSymbols::bool_signature()); + bool ret = (object->bool_field(offset) == JNI_TRUE); + return ret; +} + + #define CC (char*) static JNINativeMethod methods[] = { {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, + {CC "parseCommandLine", + CC "(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", + (void*) &WB_ParseCommandLine + }, #ifndef SERIALGC {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/prims/whitebox.hpp --- a/hotspot/src/share/vm/prims/whitebox.hpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/prims/whitebox.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -25,12 +25,29 @@ #ifndef SHARE_VM_PRIMS_WHITEBOX_HPP #define SHARE_VM_PRIMS_WHITEBOX_HPP +#include "prims/jni.h" + +#include "memory/allocation.hpp" +#include "oops/oopsHierarchy.hpp" + +// Entry macro to transition from JNI to VM state. + +#define WB_ENTRY(result_type, header) JNI_ENTRY(result_type, header) +#define WB_END JNI_END +#define WB_METHOD_DECLARE extern "C" jobjectArray JNICALL + class WhiteBox : public AllStatic { private: static bool _used; public: static bool used() { return _used; } static void set_used() { _used = true; } + static int offset_for_field(const char* field_name, oop object, + Symbol* signature_symbol); + static const char* lookup_jstring(const char* field_name, oop object); + static bool lookup_bool(const char* field_name, oop object); }; + + #endif // SHARE_VM_PRIMS_WHITEBOX_HPP diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -3807,7 +3807,7 @@ product(uintx, SharedReadOnlySize, 10*M, \ "Size of read-only space in permanent generation (in bytes)") \ \ - product(uintx, SharedMiscDataSize, NOT_LP64(4*M) LP64_ONLY(5*M), \ + product(uintx, SharedMiscDataSize, NOT_LP64(4*M) LP64_ONLY(5*M) NOT_PRODUCT(+1*M), \ "Size of the shared data area adjacent to the heap (in bytes)") \ \ product(uintx, SharedMiscCodeSize, 4*M, \ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/services/diagnosticArgument.cpp --- a/hotspot/src/share/vm/services/diagnosticArgument.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/services/diagnosticArgument.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -43,6 +43,47 @@ set_is_set(true); } +void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) { + jio_snprintf(buf, len, INT64_FORMAT, l); +} + +void GenDCmdArgument::to_string(bool b, char* buf, size_t len) { + jio_snprintf(buf, len, b ? "true" : "false"); +} + +void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) { + jio_snprintf(buf, len, INT64_FORMAT, n._nanotime); +} + +void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) { + jio_snprintf(buf, len, INT64_FORMAT, m._size); +} + +void GenDCmdArgument::to_string(char* c, char* buf, size_t len) { + jio_snprintf(buf, len, "%s", c); +} + +void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) { + int length = f->array()->length(); + size_t written = 0; + buf[0] = 0; + for (int i = 0; i < length; i++) { + char* next_str = f->array()->at(i); + size_t next_size = strlen(next_str); + //Check if there's room left to write next element + if (written + next_size > len) { + return; + } + //Actually write element + strcat(buf, next_str); + written += next_size; + //Check if there's room left for the comma + if (i < length-1 && len - written > 0) { + strcat(buf, ","); + } + } +} + template <> void DCmdArgument::parse_value(const char* str, size_t len, TRAPS) { if (str == NULL || sscanf(str, INT64_FORMAT, &_value) != 1) { diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/services/diagnosticArgument.hpp --- a/hotspot/src/share/vm/services/diagnosticArgument.hpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/services/diagnosticArgument.hpp Thu Apr 05 15:08:04 2012 -0700 @@ -110,12 +110,20 @@ virtual void init_value(TRAPS) = 0; virtual void reset(TRAPS) = 0; virtual void cleanup() = 0; + virtual void value_as_str(char* buf, size_t len) = 0; void set_next(GenDCmdArgument* arg) { _next = arg; } GenDCmdArgument* next() { return _next; } + + void to_string(jlong l, char* buf, size_t len); + void to_string(bool b, char* buf, size_t len); + void to_string(char* c, char* buf, size_t len); + void to_string(NanoTimeArgument n, char* buf, size_t len); + void to_string(MemorySizeArgument f, char* buf, size_t len); + void to_string(StringArrayArgument* s, char* buf, size_t len); }; template class DCmdArgument: public GenDCmdArgument { @@ -143,6 +151,7 @@ void parse_value(const char* str, size_t len, TRAPS); void init_value(TRAPS); void destroy_value(); + void value_as_str(char *buf, size_t len) { return to_string(_value, buf, len);} }; #endif /* SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP */ diff -r f7897aacb9ce -r e2d49b982f28 hotspot/src/share/vm/services/gcNotifier.cpp --- a/hotspot/src/share/vm/services/gcNotifier.cpp Mon Apr 02 16:05:56 2012 -0700 +++ b/hotspot/src/share/vm/services/gcNotifier.cpp Thu Apr 05 15:08:04 2012 -0700 @@ -163,8 +163,8 @@ constructor_args.push_oop(gcInfo_instance); constructor_args.push_oop(getGcInfoBuilder(gcManager,THREAD)); constructor_args.push_long(gcStatInfo->gc_index()); - constructor_args.push_long(gcStatInfo->start_time()); - constructor_args.push_long(gcStatInfo->end_time()); + constructor_args.push_long(Management::ticks_to_ms(gcStatInfo->start_time())); + constructor_args.push_long(Management::ticks_to_ms(gcStatInfo->end_time())); constructor_args.push_oop(usage_before_gc_ah); constructor_args.push_oop(usage_after_gc_ah); constructor_args.push_oop(extra_array); diff -r f7897aacb9ce -r e2d49b982f28 hotspot/test/serviceability/ParserTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/ParserTest.java Thu Apr 05 15:08:04 2012 -0700 @@ -0,0 +1,152 @@ +/* + * @test ParserTest + * @summary verify that whitebox functions can be linked and executed + * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI ParserTest.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ParserTest + */ + +import java.math.BigInteger; + +import sun.hotspot.parser.DiagnosticCommand; +import sun.hotspot.parser.DiagnosticCommand.DiagnosticArgumentType; +import sun.hotspot.WhiteBox; + +public class ParserTest { + WhiteBox wb; + + public ParserTest() throws Exception { + wb = WhiteBox.getWhiteBox(); + + testNanoTime(); + testJLong(); + testBool(); + testMemorySize(); + } + + public static void main(String... args) throws Exception { + new ParserTest(); + } + + public void testNanoTime() throws Exception { + String name = "name"; + DiagnosticCommand arg = new DiagnosticCommand(name, + "desc", DiagnosticArgumentType.NANOTIME, + false, "0"); + DiagnosticCommand[] args = {arg}; + + BigInteger bi = new BigInteger("7"); + //These should work + parse(name, bi.toString(), name + "=7ns", args); + + bi = bi.multiply(BigInteger.valueOf(1000)); + parse(name, bi.toString(), name + "=7us", args); + + bi = bi.multiply(BigInteger.valueOf(1000)); + parse(name, bi.toString(), name + "=7ms", args); + + bi = bi.multiply(BigInteger.valueOf(1000)); + parse(name, bi.toString(), name + "=7s", args); + + bi = bi.multiply(BigInteger.valueOf(60)); + parse(name, bi.toString() , name + "=7m", args); + + bi = bi.multiply(BigInteger.valueOf(60)); + parse(name, bi.toString() , name + "=7h", args); + + bi = bi.multiply(BigInteger.valueOf(24)); + parse(name, bi.toString() , name + "=7d", args); + + parse(name, "0", name + "=0", args); + + shouldFail(name + "=7xs", args); + shouldFail(name + "=7mms", args); + shouldFail(name + "=7f", args); + //Currently, only value 0 is allowed without unit + shouldFail(name + "=7", args); + } + + public void testJLong() throws Exception { + String name = "name"; + DiagnosticCommand arg = new DiagnosticCommand(name, + "desc", DiagnosticArgumentType.JLONG, + false, "0"); + DiagnosticCommand[] args = {arg}; + + wb.parseCommandLine(name + "=10", args); + parse(name, "10", name + "=10", args); + parse(name, "-5", name + "=-5", args); + + //shouldFail(name + "=12m", args); <-- should fail, doesn't + } + + public void testBool() throws Exception { + String name = "name"; + DiagnosticCommand arg = new DiagnosticCommand(name, + "desc", DiagnosticArgumentType.BOOLEAN, + false, "false"); + DiagnosticCommand[] args = {arg}; + + parse(name, "true", name + "=true", args); + parse(name, "false", name + "=false", args); + parse(name, "true", name, args); + + //Empty commandline to parse, tests default value + //of the parameter "name" + parse(name, "false", "", args); + } + + public void testMemorySize() throws Exception { + String name = "name"; + String defaultValue = "1024"; + DiagnosticCommand arg = new DiagnosticCommand(name, + "desc", DiagnosticArgumentType.MEMORYSIZE, + false, defaultValue); + DiagnosticCommand[] args = {arg}; + + BigInteger bi = new BigInteger("7"); + parse(name, bi.toString(), name + "=7b", args); + + bi = bi.multiply(BigInteger.valueOf(1024)); + parse(name, bi.toString(), name + "=7k", args); + + bi = bi.multiply(BigInteger.valueOf(1024)); + parse(name, bi.toString(), name + "=7m", args); + + bi = bi.multiply(BigInteger.valueOf(1024)); + parse(name, bi.toString(), name + "=7g", args); + parse(name, defaultValue, "", args); + + //shouldFail(name + "=7gg", args); <---- should fail, doesn't + //shouldFail(name + "=7t", args); <----- should fail, doesn't + } + + public void parse(String searchName, String expectedValue, + String cmdLine, DiagnosticCommand[] argumentTypes) throws Exception { + //parseCommandLine will return an object array that looks like + //{, ... } + Object[] res = wb.parseCommandLine(cmdLine, argumentTypes); + for (int i = 0; i < res.length-1; i+=2) { + String parsedName = (String) res[i]; + if (searchName.equals(parsedName)) { + String parsedValue = (String) res[i+1]; + if (expectedValue.equals(parsedValue)) { + return; + } else { + throw new Exception("Parsing of cmdline '" + cmdLine + "' failed!\n" + + searchName + " parsed as " + parsedValue + + "! Expected: " + expectedValue); + } + } + } + throw new Exception(searchName + " not found as a parsed Argument!"); + } + + private void shouldFail(String argument, DiagnosticCommand[] argumentTypes) throws Exception { + try { + wb.parseCommandLine(argument, argumentTypes); + throw new Exception("Parser accepted argument: " + argument); + } catch (IllegalArgumentException e) { + //expected + } + } +}