# HG changeset patch # User kvn # Date 1284680920 25200 # Node ID 18c3785135759b9af8339c1314c586cce0b2b7c0 # Parent 97fbf5beff7ba2c1b5019343e433ea6db9a139a4# Parent a8b66e00933b917e013f4047c0efdd5d7d971ce8 Merge diff -r a8b66e00933b -r 18c378513575 .hgtags --- a/.hgtags Tue Sep 14 17:19:35 2010 -0700 +++ b/.hgtags Thu Sep 16 16:48:40 2010 -0700 @@ -114,4 +114,6 @@ 1b81ca701fa5fc30adc4cfdaa4bdd153df5e6c86 jdk7-b106 cc3fdfeb54b049f18edcf3463e6ab051d0b7b609 hs19-b05 688a538aa65412178286ae2a6b0c00b6711e121b hs19-b06 +bf496cbe9b74dda5975a1559da7ecfdd313e509e jdk7-b107 0000000000000000000000000000000000000000 hs19-b06 +6c43216df13513a0f96532aa06f213066c49e27b hs19-b06 diff -r a8b66e00933b -r 18c378513575 make/hotspot_version --- a/make/hotspot_version Tue Sep 14 17:19:35 2010 -0700 +++ b/make/hotspot_version Thu Sep 16 16:48:40 2010 -0700 @@ -33,9 +33,9 @@ # Don't put quotes (fail windows build). HOTSPOT_VM_COPYRIGHT=Copyright 2010 -HS_MAJOR_VER=19 +HS_MAJOR_VER=20 HS_MINOR_VER=0 -HS_BUILD_NUMBER=06 +HS_BUILD_NUMBER=01 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r a8b66e00933b -r 18c378513575 make/jprt.properties --- a/make/jprt.properties Tue Sep 14 17:19:35 2010 -0700 +++ b/make/jprt.properties Thu Sep 16 16:48:40 2010 -0700 @@ -47,6 +47,8 @@ # Define the Solaris platforms we want for the various releases jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10 +jprt.my.solaris.sparc.jdk7b107=solaris_sparc_5.10 +jprt.my.solaris.sparc.jdk7temp=solaris_sparc_5.10 jprt.my.solaris.sparc.jdk6=solaris_sparc_5.8 jprt.my.solaris.sparc.jdk6perf=solaris_sparc_5.8 jprt.my.solaris.sparc.jdk6u10=solaris_sparc_5.8 @@ -56,6 +58,8 @@ jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}} jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 +jprt.my.solaris.sparcv9.jdk7b107=solaris_sparcv9_5.10 +jprt.my.solaris.sparcv9.jdk7temp=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk6=solaris_sparcv9_5.8 jprt.my.solaris.sparcv9.jdk6perf=solaris_sparcv9_5.8 jprt.my.solaris.sparcv9.jdk6u10=solaris_sparcv9_5.8 @@ -65,6 +69,8 @@ jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} jprt.my.solaris.i586.jdk7=solaris_i586_5.10 +jprt.my.solaris.i586.jdk7b107=solaris_i586_5.10 +jprt.my.solaris.i586.jdk7temp=solaris_i586_5.10 jprt.my.solaris.i586.jdk6=solaris_i586_5.8 jprt.my.solaris.i586.jdk6perf=solaris_i586_5.8 jprt.my.solaris.i586.jdk6u10=solaris_i586_5.8 @@ -74,6 +80,8 @@ jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}} jprt.my.solaris.x64.jdk7=solaris_x64_5.10 +jprt.my.solaris.x64.jdk7b107=solaris_x64_5.10 +jprt.my.solaris.x64.jdk7temp=solaris_x64_5.10 jprt.my.solaris.x64.jdk6=solaris_x64_5.10 jprt.my.solaris.x64.jdk6perf=solaris_x64_5.10 jprt.my.solaris.x64.jdk6u10=solaris_x64_5.10 @@ -83,6 +91,8 @@ jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} jprt.my.linux.i586.jdk7=linux_i586_2.6 +jprt.my.linux.i586.jdk7b107=linux_i586_2.6 +jprt.my.linux.i586.jdk7temp=linux_i586_2.6 jprt.my.linux.i586.jdk6=linux_i586_2.4 jprt.my.linux.i586.jdk6perf=linux_i586_2.4 jprt.my.linux.i586.jdk6u10=linux_i586_2.4 @@ -92,6 +102,8 @@ jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} jprt.my.linux.x64.jdk7=linux_x64_2.6 +jprt.my.linux.x64.jdk7b107=linux_x64_2.6 +jprt.my.linux.x64.jdk7temp=linux_x64_2.6 jprt.my.linux.x64.jdk6=linux_x64_2.4 jprt.my.linux.x64.jdk6perf=linux_x64_2.4 jprt.my.linux.x64.jdk6u10=linux_x64_2.4 @@ -100,7 +112,9 @@ jprt.my.linux.x64.jdk6u20=linux_x64_2.4 jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} -jprt.my.windows.i586.jdk7=windows_i586_5.0 +jprt.my.windows.i586.jdk7=windows_i586_5.1 +jprt.my.windows.i586.jdk7b107=windows_i586_5.0 +jprt.my.windows.i586.jdk7temp=windows_i586_5.0 jprt.my.windows.i586.jdk6=windows_i586_5.0 jprt.my.windows.i586.jdk6perf=windows_i586_5.0 jprt.my.windows.i586.jdk6u10=windows_i586_5.0 @@ -110,6 +124,8 @@ jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} jprt.my.windows.x64.jdk7=windows_x64_5.2 +jprt.my.windows.x64.jdk7b107=windows_x64_5.2 +jprt.my.windows.x64.jdk7temp=windows_x64_5.2 jprt.my.windows.x64.jdk6=windows_x64_5.2 jprt.my.windows.x64.jdk6perf=windows_x64_5.2 jprt.my.windows.x64.jdk6u10=windows_x64_5.2 diff -r a8b66e00933b -r 18c378513575 make/linux/makefiles/sa.make --- a/make/linux/makefiles/sa.make Tue Sep 14 17:19:35 2010 -0700 +++ b/make/linux/makefiles/sa.make Thu Sep 16 16:48:40 2010 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2010, 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 @@ -48,6 +48,9 @@ AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) AGENT_FILES2 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES2)) +AGENT_FILES1_LIST := $(GENERATED)/agent1.classes.list +AGENT_FILES2_LIST := $(GENERATED)/agent2.classes.list + SA_CLASSDIR = $(GENERATED)/saclasses SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" @@ -65,7 +68,7 @@ $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ fi -$(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) +$(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) agent_files_preclean $(QUIETLY) echo "Making $@" $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ @@ -79,10 +82,13 @@ $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ mkdir -p $(SA_CLASSDIR); \ fi - - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2) - + + $(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST))) + $(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST))) + + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js @@ -98,6 +104,10 @@ $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.sparc.SPARCThreadContext +agent_files_preclean: + rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST) + clean: rm -rf $(SA_CLASSDIR) rm -rf $(GENERATED)/sa-jdi.jar + rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST) diff -r a8b66e00933b -r 18c378513575 make/solaris/makefiles/sa.make --- a/make/solaris/makefiles/sa.make Tue Sep 14 17:19:35 2010 -0700 +++ b/make/solaris/makefiles/sa.make Thu Sep 16 16:48:40 2010 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2010, 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 @@ -44,6 +44,9 @@ AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) AGENT_FILES2 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES2)) +AGENT_FILES1_LIST := $(GENERATED)/agent1.classes.list +AGENT_FILES2_LIST := $(GENERATED)/agent2.classes.list + SA_CLASSDIR = $(GENERATED)/saclasses SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" @@ -56,7 +59,7 @@ $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ fi -$(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) +$(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2) agent_files_preclean $(QUIETLY) echo "Making $@"; $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ @@ -70,8 +73,12 @@ $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ mkdir -p $(SA_CLASSDIR); \ fi - $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1) - $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2) + + $(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST))) + $(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST))) + + $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST) + $(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST) $(QUIETLY) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) @@ -85,6 +92,10 @@ $(QUIETLY) $(RUN.JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector $(QUIETLY) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal +agent_files_preclean: + rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST) + clean: rm -rf $(SA_CLASSDIR) rm -rf $(GENERATED)/sa-jdi.jar + rm -rf $(AGENT_FILES1_LIST) $(AGENT_FILES2_LIST) diff -r a8b66e00933b -r 18c378513575 src/share/vm/classfile/stackMapTable.cpp --- a/src/share/vm/classfile/stackMapTable.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/classfile/stackMapTable.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -152,6 +152,7 @@ int32_t StackMapReader::chop( VerificationType* locals, int32_t length, int32_t chops) { + if (locals == NULL) return -1; int32_t pos = length - 1; for (int32_t i=0; inext(); TreeChunk* retTC; if (fc == NULL) { @@ -272,7 +272,7 @@ // those in the list for this size; potentially slow and expensive, // use with caution! TreeChunk* TreeList::largest_address() { - guarantee(head() != NULL, "The head of the list cannot be NULL"); + assert(head() != NULL, "The head of the list cannot be NULL"); FreeChunk* fc = head()->next(); TreeChunk* retTC; if (fc == NULL) { diff -r a8b66e00933b -r 18c378513575 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -1946,8 +1946,8 @@ bool CompactibleFreeListSpace::no_allocs_since_save_marks() { assert(_promoInfo.tracking(), "No preceding save_marks?"); - guarantee(SharedHeap::heap()->n_par_threads() == 0, - "Shouldn't be called (yet) during parallel part of gc."); + assert(SharedHeap::heap()->n_par_threads() == 0, + "Shouldn't be called if using parallel gc."); return _promoInfo.noPromotions(); } @@ -2569,7 +2569,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) { FreeChunk* res; - guarantee(word_sz == _cfls->adjustObjectSize(word_sz), "Error"); + assert(word_sz == _cfls->adjustObjectSize(word_sz), "Error"); if (word_sz >= CompactibleFreeListSpace::IndexSetSize) { // This locking manages sync with other large object allocations. MutexLockerEx x(_cfls->parDictionaryAllocLock(), diff -r a8b66e00933b -r 18c378513575 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -1332,7 +1332,7 @@ // ----------------------------------------------------- // FREE: klass_word & 1 == 1; mark_word holds block size // -// OBJECT: klass_word installed; klass_word != 0 && klass_word & 0 == 0; +// OBJECT: klass_word installed; klass_word != 0 && klass_word & 1 == 0; // obj->size() computes correct size // [Perm Gen objects needs to be "parsable" before they can be navigated] // diff -r a8b66e00933b -r 18c378513575 src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -165,13 +165,8 @@ "Next of tail should be NULL"); } decrement_count(); -#define TRAP_CODE 1 -#if TRAP_CODE - if (head() == NULL) { - guarantee(tail() == NULL, "INVARIANT"); - guarantee(count() == 0, "INVARIANT"); - } -#endif + assert(((head() == NULL) + (tail() == NULL) + (count() == 0)) % 3 == 0, + "H/T/C Inconsistency"); // clear next and prev fields of fc, debug only NOT_PRODUCT( fc->linkPrev(NULL); diff -r a8b66e00933b -r 18c378513575 src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -253,8 +253,8 @@ cur_spool = cur_spool->nextSpoolBlock) { // the first entry is just a self-pointer; indices 1 through // bufferSize - 1 are occupied (thus, bufferSize - 1 slots). - guarantee((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr, - "first entry of displacedHdr should be self-referential"); + assert((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr, + "first entry of displacedHdr should be self-referential"); slots += cur_spool->bufferSize - 1; blocks++; } diff -r a8b66e00933b -r 18c378513575 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -2148,7 +2148,7 @@ body_summary->get_termination_seq() }; NumberSeq calc_other_times_ms(body_summary->get_parallel_seq(), - 7, other_parts); + 6, other_parts); check_other_times(2, body_summary->get_parallel_other_seq(), &calc_other_times_ms); } @@ -2166,30 +2166,32 @@ } print_summary(1, "Other", summary->get_other_seq()); { - NumberSeq calc_other_times_ms; - if (parallel) { - // parallel - NumberSeq* other_parts[] = { - body_summary->get_satb_drain_seq(), - body_summary->get_parallel_seq(), - body_summary->get_clear_ct_seq() - }; - calc_other_times_ms = NumberSeq(summary->get_total_seq(), - 3, other_parts); - } else { - // serial - NumberSeq* other_parts[] = { - body_summary->get_satb_drain_seq(), - body_summary->get_update_rs_seq(), - body_summary->get_ext_root_scan_seq(), - body_summary->get_mark_stack_scan_seq(), - body_summary->get_scan_rs_seq(), - body_summary->get_obj_copy_seq() - }; - calc_other_times_ms = NumberSeq(summary->get_total_seq(), - 7, other_parts); + if (body_summary != NULL) { + NumberSeq calc_other_times_ms; + if (parallel) { + // parallel + NumberSeq* other_parts[] = { + body_summary->get_satb_drain_seq(), + body_summary->get_parallel_seq(), + body_summary->get_clear_ct_seq() + }; + calc_other_times_ms = NumberSeq(summary->get_total_seq(), + 3, other_parts); + } else { + // serial + NumberSeq* other_parts[] = { + body_summary->get_satb_drain_seq(), + body_summary->get_update_rs_seq(), + body_summary->get_ext_root_scan_seq(), + body_summary->get_mark_stack_scan_seq(), + body_summary->get_scan_rs_seq(), + body_summary->get_obj_copy_seq() + }; + calc_other_times_ms = NumberSeq(summary->get_total_seq(), + 6, other_parts); + } + check_other_times(1, summary->get_other_seq(), &calc_other_times_ms); } - check_other_times(1, summary->get_other_seq(), &calc_other_times_ms); } } else { print_indent(0); diff -r a8b66e00933b -r 18c378513575 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/runtime/arguments.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -2863,6 +2863,13 @@ CommandLineFlags::printFlags(); vm_exit(0); } + +#ifndef PRODUCT + if (match_option(option, "-XX:+PrintFlagsWithComments", &tail)) { + CommandLineFlags::printFlags(true); + vm_exit(0); + } +#endif } if (IgnoreUnrecognizedVMOptions) { diff -r a8b66e00933b -r 18c378513575 src/share/vm/runtime/globals.cpp --- a/src/share/vm/runtime/globals.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/runtime/globals.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -68,30 +68,38 @@ // Length of format string (e.g. "%.1234s") for printing ccstr below #define FORMAT_BUFFER_LEN 16 -void Flag::print_on(outputStream* st) { - st->print("%5s %-35s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); +void Flag::print_on(outputStream* st, bool withComments) { + st->print("%9s %-40s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false"); if (is_intx()) st->print("%-16ld", get_intx()); if (is_uintx()) st->print("%-16lu", get_uintx()); if (is_uint64_t()) st->print("%-16lu", get_uint64_t()); + if (is_double()) st->print("%-16f", get_double()); + if (is_ccstr()) { - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - char format_buffer[FORMAT_BUFFER_LEN]; - size_t llen = pointer_delta(eol, cp, sizeof(char)); - jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + char format_buffer[FORMAT_BUFFER_LEN]; + size_t llen = pointer_delta(eol, cp, sizeof(char)); + jio_snprintf(format_buffer, FORMAT_BUFFER_LEN, "%%." SIZE_FORMAT "s", llen); - st->print(format_buffer, cp); - st->cr(); - cp = eol+1; - st->print("%5s %-35s += ", "", name); - } - st->print("%-16s", cp); - } + st->print(format_buffer, cp); + st->cr(); + cp = eol+1; + st->print("%5s %-35s += ", "", name); + } + st->print("%-16s", cp); + } + else st->print("%-16s", ""); } - st->print(" %s", kind); + st->print("%-20s", kind); + if (withComments) { +#ifndef PRODUCT + st->print("%s", doc ); +#endif + } st->cr(); } @@ -131,67 +139,67 @@ // 4991491 do not "optimize out" the was_set false values: omitting them // tickles a Microsoft compiler bug causing flagTable to be malformed -#define RUNTIME_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{product}", DEFAULT }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{pd product}", DEFAULT }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{diagnostic}", DEFAULT }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{experimental}", DEFAULT }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{manageable}", DEFAULT }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{product rw}", DEFAULT }, +#define RUNTIME_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product}", DEFAULT }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{pd product}", DEFAULT }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{diagnostic}", DEFAULT }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{experimental}", DEFAULT }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{manageable}", DEFAULT }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{product rw}", DEFAULT }, #ifdef PRODUCT #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "", DEFAULT }, - #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{pd}", DEFAULT }, - #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{notproduct}", DEFAULT }, + #define RUNTIME_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "", DEFAULT }, + #define RUNTIME_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{pd}", DEFAULT }, + #define RUNTIME_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{notproduct}", DEFAULT }, #endif #ifdef _LP64 - #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{lp64_product}", DEFAULT }, + #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{lp64_product}", DEFAULT }, #else #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #endif // _LP64 -#define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C1 product}", DEFAULT }, -#define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C1 pd product}", DEFAULT }, +#define C1_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 product}", DEFAULT }, +#define C1_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C1 pd product}", DEFAULT }, #ifdef PRODUCT #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C1}", DEFAULT }, - #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C1 pd}", DEFAULT }, - #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C1 notproduct}", DEFAULT }, + #define C1_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1}", DEFAULT }, + #define C1_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C1 pd}", DEFAULT }, + #define C1_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C1 notproduct}", DEFAULT }, #endif -#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT }, -#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT }, -#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT }, -#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT }, +#define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 product}", DEFAULT }, +#define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 pd product}", DEFAULT }, +#define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 diagnostic}", DEFAULT }, +#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{C2 experimental}", DEFAULT }, #ifdef PRODUCT #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2}", DEFAULT }, - #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd}", DEFAULT }, - #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 notproduct}", DEFAULT }, + #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2}", DEFAULT }, + #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{C2 pd}", DEFAULT }, + #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{C2 notproduct}", DEFAULT }, #endif -#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark product}", DEFAULT }, -#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{Shark pd product}", DEFAULT }, -#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark diagnostic}", DEFAULT }, +#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark product}", DEFAULT }, +#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark pd product}", DEFAULT }, +#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) "{Shark diagnostic}", DEFAULT }, #ifdef PRODUCT #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) #else - #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark}", DEFAULT }, - #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{Shark pd}", DEFAULT }, - #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark notproduct}", DEFAULT }, + #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark}", DEFAULT }, + #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, doc, "{Shark pd}", DEFAULT }, + #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, doc, "{Shark notproduct}", DEFAULT }, #endif static Flag flagTable[] = { @@ -485,7 +493,7 @@ #endif // PRODUCT -void CommandLineFlags::printFlags() { +void CommandLineFlags::printFlags(bool withComments) { // Print the flags sorted by name // note: this method is called before the thread structure is in place // which means resource allocation cannot be used. @@ -505,7 +513,7 @@ tty->print_cr("[Global flags]"); for (int i = 0; i < length; i++) { if (array[i]->is_unlocked()) { - array[i]->print_on(tty); + array[i]->print_on(tty, withComments); } } FREE_C_HEAP_ARRAY(Flag*, array); diff -r a8b66e00933b -r 18c378513575 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/runtime/globals.hpp Thu Sep 16 16:48:40 2010 -0700 @@ -83,6 +83,9 @@ const char *type; const char *name; void* addr; + + NOT_PRODUCT(const char *doc;) + const char *kind; FlagValueOrigin origin; @@ -124,7 +127,7 @@ bool is_writeable() const; bool is_external() const; - void print_on(outputStream* st); + void print_on(outputStream* st, bool withComments = false ); void print_as_flag(outputStream* st); }; @@ -204,7 +207,7 @@ static bool wasSetOnCmdline(const char* name, bool* value); static void printSetFlags(); - static void printFlags(); + static void printFlags(bool withComments = false ); static void verify() PRODUCT_RETURN; }; @@ -1534,13 +1537,13 @@ "Use BinaryTreeDictionary as default in the CMS generation") \ \ product(uintx, CMSIndexedFreeListReplenish, 4, \ - "Replenish and indexed free list with this number of chunks") \ + "Replenish an indexed free list with this number of chunks") \ \ product(bool, CMSReplenishIntermediate, true, \ "Replenish all intermediate free-list caches") \ \ product(bool, CMSSplitIndexedFreeListBlocks, true, \ - "When satisfying batched demand, splot blocks from the " \ + "When satisfying batched demand, split blocks from the " \ "IndexedFreeList whose size is a multiple of requested size") \ \ product(bool, CMSLoopWarn, false, \ @@ -2396,6 +2399,9 @@ product(bool, PrintFlagsFinal, false, \ "Print all VM flags after argument and ergonomic processing") \ \ + notproduct(bool, PrintFlagsWithComments, false, \ + "Print all VM flags with default values and descriptions and exit")\ + \ diagnostic(bool, SerializeVMOutput, true, \ "Use a mutex to serialize output to tty and hotspot.log") \ \ diff -r a8b66e00933b -r 18c378513575 src/share/vm/services/heapDumper.cpp --- a/src/share/vm/services/heapDumper.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/services/heapDumper.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, 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 @@ -1305,6 +1305,8 @@ static VM_HeapDumper* _global_dumper; static DumpWriter* _global_writer; DumpWriter* _local_writer; + JavaThread* _oome_thread; + methodOop _oome_constructor; bool _gc_before_heap_dump; bool _is_segmented_dump; jlong _dump_start; @@ -1366,7 +1368,7 @@ void end_of_dump(); public: - VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump) : + VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) : VM_GC_Operation(0 /* total collections, dummy, ignored */, 0 /* total full collections, dummy, ignored */, gc_before_heap_dump) { @@ -1377,6 +1379,18 @@ _klass_map = new (ResourceObj::C_HEAP) GrowableArray(INITIAL_CLASS_COUNT, true); _stack_traces = NULL; _num_threads = 0; + if (oome) { + assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread"); + // get OutOfMemoryError zero-parameter constructor + instanceKlass* oome_ik = instanceKlass::cast(SystemDictionary::OutOfMemoryError_klass()); + _oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(), + vmSymbols::void_method_signature()); + // get thread throwing OOME when generating the heap dump at OOME + _oome_thread = JavaThread::current(); + } else { + _oome_thread = NULL; + _oome_constructor = NULL; + } } ~VM_HeapDumper() { if (_stack_traces != NULL) { @@ -1557,7 +1571,11 @@ frame f = java_thread->last_frame(); vframe* vf = vframe::new_vframe(&f, ®_map, java_thread); frame* last_entry_frame = NULL; + int extra_frames = 0; + if (java_thread == _oome_thread && _oome_constructor != NULL) { + extra_frames++; + } while (vf != NULL) { blk.set_frame_number(stack_depth); if (vf->is_java_frame()) { @@ -1574,7 +1592,7 @@ writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); writer()->write_objectID(o); writer()->write_u4(thread_serial_num); - writer()->write_u4((u4) stack_depth); + writer()->write_u4((u4) (stack_depth + extra_frames)); } } } @@ -1764,6 +1782,17 @@ // write HPROF_FRAME records for this thread's stack trace int depth = stack_trace->get_stack_depth(); int thread_frame_start = frame_serial_num; + int extra_frames = 0; + // write fake frame that makes it look like the thread, which caused OOME, + // is in the OutOfMemoryError zero-parameter constructor + if (thread == _oome_thread && _oome_constructor != NULL) { + int oome_serial_num = _klass_map->find(Klass::cast(_oome_constructor->method_holder())); + // the class serial number starts from 1 + assert(oome_serial_num > 0, "OutOfMemoryError class not found"); + DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num, + _oome_constructor, 0); + extra_frames++; + } for (int j=0; j < depth; j++) { StackFrameInfo* frame = stack_trace->stack_frame_at(j); methodOop m = frame->method(); @@ -1772,6 +1801,7 @@ assert(class_serial_num > 0, "class not found"); DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci()); } + depth += extra_frames; // write HPROF_TRACE record for one thread DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize); @@ -1808,7 +1838,7 @@ } // generate the dump - VM_HeapDumper dumper(&writer, _gc_before_heap_dump); + VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome); if (Thread::current()->is_VM_thread()) { assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint"); dumper.doit(); @@ -1869,12 +1899,22 @@ } } +// Called by out-of-memory error reporting by a single Java thread +// outside of a JVM safepoint +void HeapDumper::dump_heap_from_oome() { + HeapDumper::dump_heap(true); +} + // Called by error reporting by a single Java thread outside of a JVM safepoint, // or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various // callers are strictly serialized and guaranteed not to interfere below. For more // general use, however, this method will need modification to prevent // inteference when updating the static variables base_path and dump_file_seq below. void HeapDumper::dump_heap() { + HeapDumper::dump_heap(false); +} + +void HeapDumper::dump_heap(bool oome) { static char base_path[JVM_MAXPATHLEN] = {'\0'}; static uint dump_file_seq = 0; char my_path[JVM_MAXPATHLEN] = {'\0'}; @@ -1930,6 +1970,7 @@ dump_file_seq++; // increment seq number for next time we dump HeapDumper dumper(false /* no GC before heap dump */, - true /* send to tty */); + true /* send to tty */, + oome /* pass along out-of-memory-error flag */); dumper.dump(my_path); } diff -r a8b66e00933b -r 18c378513575 src/share/vm/services/heapDumper.hpp --- a/src/share/vm/services/heapDumper.hpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/services/heapDumper.hpp Thu Sep 16 16:48:40 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, 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 @@ -39,8 +39,12 @@ char* _error; bool _print_to_tty; bool _gc_before_heap_dump; + bool _oome; elapsedTimer _t; + HeapDumper(bool gc_before_heap_dump, bool print_to_tty, bool oome) : + _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty), _oome(oome) { } + // string representation of error char* error() const { return _error; } void set_error(char* error); @@ -51,11 +55,11 @@ // internal timer. elapsedTimer* timer() { return &_t; } + static void dump_heap(bool oome); + public: HeapDumper(bool gc_before_heap_dump) : - _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false) { } - HeapDumper(bool gc_before_heap_dump, bool print_to_tty) : - _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty) { } + _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false), _oome(false) { } ~HeapDumper(); @@ -66,4 +70,6 @@ char* error_as_C_string() const; static void dump_heap() KERNEL_RETURN; + + static void dump_heap_from_oome() KERNEL_RETURN; }; diff -r a8b66e00933b -r 18c378513575 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/utilities/debug.cpp Thu Sep 16 16:48:40 2010 -0700 @@ -234,7 +234,7 @@ // create heap dump before OnOutOfMemoryError commands are executed if (HeapDumpOnOutOfMemoryError) { tty->print_cr("java.lang.OutOfMemoryError: %s", message); - HeapDumper::dump_heap(); + HeapDumper::dump_heap_from_oome(); } if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { diff -r a8b66e00933b -r 18c378513575 src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Tue Sep 14 17:19:35 2010 -0700 +++ b/src/share/vm/utilities/macros.hpp Thu Sep 16 16:48:40 2010 -0700 @@ -84,12 +84,14 @@ #ifdef PRODUCT #define PRODUCT_ONLY(code) code #define NOT_PRODUCT(code) +#define NOT_PRODUCT_ARG(arg) #define PRODUCT_RETURN {} #define PRODUCT_RETURN0 { return 0; } #define PRODUCT_RETURN_(code) { code } #else // PRODUCT #define PRODUCT_ONLY(code) #define NOT_PRODUCT(code) code +#define NOT_PRODUCT_ARG(arg) arg, #define PRODUCT_RETURN /*next token must be ;*/ #define PRODUCT_RETURN0 /*next token must be ;*/ #define PRODUCT_RETURN_(code) /*next token must be ;*/