From 66cecec23061ece1b8e5966083aeb80423b75762 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Wed, 11 Mar 2009 14:16:13 -0700 Subject: [PATCH 01/43] 6812587: Use auxv to determine SPARC hardware features on Solaris A similar function to getisax(2) should be used to determine all possible instruction set extensions. Reviewed-by: never, kvn --- hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 8 +- hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp | 51 +++---- hotspot/src/os/solaris/vm/os_solaris.cpp | 44 ++++-- hotspot/src/os/solaris/vm/os_solaris.hpp | 9 +- .../vm/vm_version_solaris_sparc.cpp | 132 ++++++++++++------ hotspot/src/share/vm/includeDB_core | 1 + 6 files changed, 163 insertions(+), 82 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index a870c7dc15b..e2866cb4310 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -90,7 +90,7 @@ void VM_Version::initialize() { } char buf[512]; - jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s", (has_v8() ? ", has_v8" : ""), (has_v9() ? ", has_v9" : ""), (has_vis1() ? ", has_vis1" : ""), @@ -98,7 +98,9 @@ void VM_Version::initialize() { (is_ultra3() ? ", is_ultra3" : ""), (is_sun4v() ? ", is_sun4v" : ""), (is_niagara1() ? ", is_niagara1" : ""), - (!has_hardware_int_muldiv() ? ", no-muldiv" : ""), + (is_niagara1_plus() ? ", is_niagara1_plus" : ""), + (!has_hardware_mul32() ? ", no-mul32" : ""), + (!has_hardware_div32() ? ", no-div32" : ""), (!has_hardware_fsmuld() ? ", no-fsmuld" : "")); // buf is started with ", " or is empty diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index 050e7e68fcc..92133fa9bfe 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -25,34 +25,36 @@ class VM_Version: public Abstract_VM_Version { protected: enum Feature_Flag { - v8_instructions = 0, - hardware_int_muldiv = 1, - hardware_fsmuld = 2, - v9_instructions = 3, - vis1_instructions = 4, - vis2_instructions = 5, - sun4v_instructions = 6 + v8_instructions = 0, + hardware_mul32 = 1, + hardware_div32 = 2, + hardware_fsmuld = 3, + v9_instructions = 4, + vis1_instructions = 5, + vis2_instructions = 6, + sun4v_instructions = 7 }; enum Feature_Flag_Set { - unknown_m = 0, - all_features_m = -1, + unknown_m = 0, + all_features_m = -1, - v8_instructions_m = 1 << v8_instructions, - hardware_int_muldiv_m = 1 << hardware_int_muldiv, - hardware_fsmuld_m = 1 << hardware_fsmuld, - v9_instructions_m = 1 << v9_instructions, - vis1_instructions_m = 1 << vis1_instructions, - vis2_instructions_m = 1 << vis2_instructions, - sun4v_m = 1 << sun4v_instructions, + v8_instructions_m = 1 << v8_instructions, + hardware_mul32_m = 1 << hardware_mul32, + hardware_div32_m = 1 << hardware_div32, + hardware_fsmuld_m = 1 << hardware_fsmuld, + v9_instructions_m = 1 << v9_instructions, + vis1_instructions_m = 1 << vis1_instructions, + vis2_instructions_m = 1 << vis2_instructions, + sun4v_m = 1 << sun4v_instructions, - generic_v8_m = v8_instructions_m | hardware_int_muldiv_m | hardware_fsmuld_m, - generic_v9_m = generic_v8_m | v9_instructions_m | vis1_instructions_m, - ultra3_m = generic_v9_m | vis2_instructions_m, + generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m, + generic_v9_m = generic_v8_m | v9_instructions_m, + ultra3_m = generic_v9_m | vis1_instructions_m | vis2_instructions_m, // Temporary until we have something more accurate - niagara1_unique_m = sun4v_m, - niagara1_m = generic_v9_m | niagara1_unique_m + niagara1_unique_m = sun4v_m, + niagara1_m = generic_v9_m | niagara1_unique_m }; static int _features; @@ -62,7 +64,7 @@ protected: static int determine_features(); static int platform_features(int features); - static bool is_niagara1(int features) { return (features & niagara1_m) == niagara1_m; } + static bool is_niagara1(int features) { return (features & sun4v_m) != 0; } static int maximum_niagara1_processor_count() { return 32; } // Returns true if the platform is in the niagara line and @@ -76,7 +78,8 @@ public: // Instruction support static bool has_v8() { return (_features & v8_instructions_m) != 0; } static bool has_v9() { return (_features & v9_instructions_m) != 0; } - static bool has_hardware_int_muldiv() { return (_features & hardware_int_muldiv_m) != 0; } + static bool has_hardware_mul32() { return (_features & hardware_mul32_m) != 0; } + static bool has_hardware_div32() { return (_features & hardware_div32_m) != 0; } static bool has_hardware_fsmuld() { return (_features & hardware_fsmuld_m) != 0; } static bool has_vis1() { return (_features & vis1_instructions_m) != 0; } static bool has_vis2() { return (_features & vis2_instructions_m) != 0; } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index c5c83883f48..a74eb33f9da 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -4451,6 +4451,9 @@ int_fnP_thread_t_i os::Solaris::_thr_setmutator; int_fnP_thread_t os::Solaris::_thr_suspend_mutator; int_fnP_thread_t os::Solaris::_thr_continue_mutator; +// (Static) wrapper for getisax(2) call. +os::Solaris::getisax_func_t os::Solaris::_getisax = 0; + // (Static) wrappers for the liblgrp API os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home; os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init; @@ -4465,16 +4468,19 @@ os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0; // (Static) wrapper for meminfo() call. os::Solaris::meminfo_func_t os::Solaris::_meminfo = 0; -static address resolve_symbol(const char *name) { - address addr; - - addr = (address) dlsym(RTLD_DEFAULT, name); +static address resolve_symbol_lazy(const char* name) { + address addr = (address) dlsym(RTLD_DEFAULT, name); if(addr == NULL) { // RTLD_DEFAULT was not defined on some early versions of 2.5.1 addr = (address) dlsym(RTLD_NEXT, name); - if(addr == NULL) { - fatal(dlerror()); - } + } + return addr; +} + +static address resolve_symbol(const char* name) { + address addr = resolve_symbol_lazy(name); + if(addr == NULL) { + fatal(dlerror()); } return addr; } @@ -4673,15 +4679,26 @@ bool os::Solaris::liblgrp_init() { } void os::Solaris::misc_sym_init() { - address func = (address)dlsym(RTLD_DEFAULT, "meminfo"); - if(func == NULL) { - func = (address) dlsym(RTLD_NEXT, "meminfo"); + address func; + + // getisax + func = resolve_symbol_lazy("getisax"); + if (func != NULL) { + os::Solaris::_getisax = CAST_TO_FN_PTR(getisax_func_t, func); } + + // meminfo + func = resolve_symbol_lazy("meminfo"); if (func != NULL) { os::Solaris::set_meminfo(CAST_TO_FN_PTR(meminfo_func_t, func)); } } +uint_t os::Solaris::getisax(uint32_t* array, uint_t n) { + assert(_getisax != NULL, "_getisax not set"); + return _getisax(array, n); +} + // Symbol doesn't exist in Solaris 8 pset.h #ifndef PS_MYID #define PS_MYID -3 @@ -4716,6 +4733,10 @@ void os::init(void) { Solaris::initialize_system_info(); + // Initialize misc. symbols as soon as possible, so we can use them + // if we need them. + Solaris::misc_sym_init(); + int fd = open("/dev/zero", O_RDWR); if (fd < 0) { fatal1("os::init: cannot open /dev/zero (%s)", strerror(errno)); @@ -4857,7 +4878,6 @@ jint os::init_2(void) { } } - Solaris::misc_sym_init(); Solaris::signal_sets_init(); Solaris::init_signal_mem(); Solaris::install_signal_handlers(); diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 8e322456d89..e4cbdbb5cd6 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -72,6 +72,8 @@ class Solaris { LGRP_VIEW_OS /* what's available to operating system */ } lgrp_view_t; + typedef uint_t (*getisax_func_t)(uint32_t* array, uint_t n); + typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id); typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view); typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie); @@ -87,6 +89,8 @@ class Solaris { const uint_t info_req[], int info_count, uint64_t outdata[], uint_t validity[]); + static getisax_func_t _getisax; + static lgrp_home_func_t _lgrp_home; static lgrp_init_func_t _lgrp_init; static lgrp_fini_func_t _lgrp_fini; @@ -283,6 +287,9 @@ class Solaris { } static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; } + static bool supports_getisax() { return _getisax != NULL; } + static uint_t getisax(uint32_t* array, uint_t n); + static void set_meminfo(meminfo_func_t func) { _meminfo = func; } static int meminfo (const uint64_t inaddr[], int addr_count, const uint_t info_req[], int info_count, diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 5f2ec21027e..d2c5baa5fd3 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2009 Sun Microsystems, Inc. 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 @@ -25,58 +25,106 @@ # include "incls/_precompiled.incl" # include "incls/_vm_version_solaris_sparc.cpp.incl" +# include +# include # include -int VM_Version::platform_features(int features) { - // We determine what sort of hardware we have via sysinfo(SI_ISALIST, ...). - // This isn't the best of all possible ways because there's not enough - // detail in the isa list it returns, but it's a bit less arcane than - // generating assembly code and an illegal instruction handler. We used - // to generate a getpsr trap, but that's even more arcane. - // - // Another possibility would be to use sysinfo(SI_PLATFORM, ...), but - // that would require more knowledge here than is wise. +// We need to keep these here as long as we have to build on Solaris +// versions before 10. +#ifndef SI_ARCHITECTURE_32 +#define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */ +#endif - // isalist spec via 'man isalist' as of 01-Aug-2001 +#ifndef SI_ARCHITECTURE_64 +#define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */ +#endif +static void do_sysinfo(int si, const char* string, int* features, int mask) { char tmp; - size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1); - char* buf = (char*)malloc(bufsize); + size_t bufsize = sysinfo(si, &tmp, 1); - if (buf != NULL) { - if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) { - // Figure out what kind of sparc we have - char *sparc_string = strstr(buf, "sparc"); - if (sparc_string != NULL) { features |= v8_instructions_m; - if (sparc_string[5] == 'v') { - if (sparc_string[6] == '8') { - if (sparc_string[7] == '-') features |= hardware_int_muldiv_m; - else if (sparc_string[7] == 'p') features |= generic_v9_m; - else features |= generic_v8_m; - } else if (sparc_string[6] == '9') features |= generic_v9_m; + // All SI defines used below must be supported. + guarantee(bufsize != -1, "must be supported"); + + char* buf = (char*) malloc(bufsize); + + if (buf == NULL) + return; + + if (sysinfo(si, buf, bufsize) == bufsize) { + // Compare the string. + if (strcmp(buf, string) == 0) { + *features |= mask; + } + } + + free(buf); +} + +int VM_Version::platform_features(int features) { + // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are + // supported on Solaris 10 and later. + if (os::Solaris::supports_getisax()) { +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) + tty->print_cr("getisax(2) supported."); +#endif + + // Check 32-bit architecture. + do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); + + // Check 64-bit architecture. + do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); + + // Extract valid instruction set extensions. + uint_t av; + uint_t avn = os::Solaris::getisax(&av, 1); + assert(avn == 1, "should only return one av"); + + if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; + if (av & AV_SPARC_DIV32) features |= hardware_div32_m; + if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; + if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; + if (av & AV_SPARC_VIS) features |= vis1_instructions_m; + if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; + } else { + // getisax(2) failed, use the old legacy code. +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) + tty->print_cr("getisax(2) not supported."); +#endif + + char tmp; + size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1); + char* buf = (char*) malloc(bufsize); + + if (buf != NULL) { + if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) { + // Figure out what kind of sparc we have + char *sparc_string = strstr(buf, "sparc"); + if (sparc_string != NULL) { features |= v8_instructions_m; + if (sparc_string[5] == 'v') { + if (sparc_string[6] == '8') { + if (sparc_string[7] == '-') { features |= hardware_mul32_m; + features |= hardware_div32_m; + } else if (sparc_string[7] == 'p') features |= generic_v9_m; + else features |= generic_v8_m; + } else if (sparc_string[6] == '9') features |= generic_v9_m; + } + } + + // Check for visualization instructions + char *vis = strstr(buf, "vis"); + if (vis != NULL) { features |= vis1_instructions_m; + if (vis[3] == '2') features |= vis2_instructions_m; } } - - // Check for visualization instructions - char *vis = strstr(buf, "vis"); - if (vis != NULL) { features |= vis1_instructions_m; - if (vis[3] == '2') features |= vis2_instructions_m; - } + free(buf); } - free(buf); } - bufsize = sysinfo(SI_MACHINE, &tmp, 1); - buf = (char*)malloc(bufsize); - - if (buf != NULL) { - if (sysinfo(SI_MACHINE, buf, bufsize) == bufsize) { - if (strstr(buf, "sun4v") != NULL) { - features |= sun4v_m; - } - } - free(buf); - } + // Determine the machine type. + do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); return features; } diff --git a/hotspot/src/share/vm/includeDB_core b/hotspot/src/share/vm/includeDB_core index c7e5db81f88..b75a1ab39a8 100644 --- a/hotspot/src/share/vm/includeDB_core +++ b/hotspot/src/share/vm/includeDB_core @@ -4598,6 +4598,7 @@ vm_version_.cpp vm_version_.hpp vm_version_.hpp globals_extension.hpp vm_version_.hpp vm_version.hpp +vm_version_.cpp os.hpp vm_version_.cpp vm_version_.hpp vmreg.cpp assembler.hpp From 69f9ddee905fad81891d9702474c423b46790870 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 12 Mar 2009 10:37:46 -0700 Subject: [PATCH 02/43] 6791178: Specialize for zero as the compressed oop vm heap base Use zero based compressed oops if java heap is below 32gb and unscaled compressed oops if java heap is below 4gb. Reviewed-by: never, twisti, jcoomes, coleenp --- .../sun/jvm/hotspot/debugger/Debugger.java | 4 +- .../jvm/hotspot/debugger/DebuggerBase.java | 20 +- .../sun/jvm/hotspot/debugger/JVMDebugger.java | 2 +- .../debugger/remote/RemoteDebugger.java | 5 +- .../debugger/remote/RemoteDebuggerClient.java | 4 +- .../debugger/remote/RemoteDebuggerServer.java | 13 +- .../sun/jvm/hotspot/memory/Universe.java | 16 +- .../classes/sun/jvm/hotspot/runtime/VM.java | 4 +- hotspot/src/cpu/sparc/vm/assembler_sparc.cpp | 45 +- hotspot/src/cpu/sparc/vm/sparc.ad | 16 +- .../src/cpu/sparc/vm/stubGenerator_sparc.cpp | 5 +- hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 3 + .../src/cpu/sparc/vm/vtableStubs_sparc.cpp | 10 +- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 162 +++++- hotspot/src/cpu/x86/vm/assembler_x86.hpp | 12 +- hotspot/src/cpu/x86/vm/x86_64.ad | 531 +++++++++++++++--- hotspot/src/os/linux/vm/os_linux.cpp | 2 +- .../os/solaris/dtrace/generateJvmOffsets.cpp | 4 + hotspot/src/os/solaris/dtrace/jhelper.d | 29 +- hotspot/src/os/solaris/dtrace/libjvm_db.c | 63 ++- hotspot/src/os/solaris/vm/os_solaris.cpp | 2 +- hotspot/src/os/windows/vm/os_windows.cpp | 4 +- .../linux_sparc/vm/globals_linux_sparc.hpp | 2 + .../os_cpu/linux_x86/vm/globals_linux_x86.hpp | 2 + .../vm/globals_solaris_sparc.hpp | 4 + .../solaris_x86/vm/globals_solaris_x86.hpp | 2 + .../windows_x86/vm/globals_windows_x86.hpp | 2 + hotspot/src/share/vm/asm/assembler.cpp | 11 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 27 +- .../parallelScavenge/parallelScavengeHeap.cpp | 28 +- .../src/share/vm/memory/genCollectedHeap.cpp | 25 + hotspot/src/share/vm/memory/universe.cpp | 95 +++- hotspot/src/share/vm/memory/universe.hpp | 40 +- hotspot/src/share/vm/oops/oop.inline.hpp | 12 +- hotspot/src/share/vm/opto/addnode.cpp | 8 +- hotspot/src/share/vm/opto/compile.cpp | 4 +- hotspot/src/share/vm/opto/connode.cpp | 2 +- hotspot/src/share/vm/opto/lcm.cpp | 9 +- hotspot/src/share/vm/opto/matcher.cpp | 9 +- hotspot/src/share/vm/runtime/arguments.cpp | 4 +- hotspot/src/share/vm/runtime/globals.hpp | 11 +- hotspot/src/share/vm/runtime/os.hpp | 2 +- hotspot/src/share/vm/runtime/virtualspace.cpp | 27 +- hotspot/src/share/vm/runtime/virtualspace.hpp | 6 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 4 +- 45 files changed, 1072 insertions(+), 220 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java index acbb90d4b66..41e71c2228e 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java @@ -118,9 +118,9 @@ public interface Debugger extends SymbolLookup, ThreadAccess { public long getJIntSize(); public long getJLongSize(); public long getJShortSize(); - public long getHeapBase(); public long getHeapOopSize(); - public long getLogMinObjAlignmentInBytes(); + public long getNarrowOopBase(); + public int getNarrowOopShift(); public ReadResult readBytesFromProcess(long address, long numBytes) throws DebuggerException; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java index 7b4ca75f431..8f5c732499b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java @@ -56,8 +56,8 @@ public abstract class DebuggerBase implements Debugger { // heap data. protected long oopSize; protected long heapOopSize; - protected long heapBase; // heap base for compressed oops. - protected long logMinObjAlignmentInBytes; // Used to decode compressed oops. + protected long narrowOopBase; // heap base for compressed oops. + protected int narrowOopShift; // shift to decode compressed oops. // Should be initialized if desired by calling initCache() private PageCache cache; @@ -159,10 +159,10 @@ public abstract class DebuggerBase implements Debugger { javaPrimitiveTypesConfigured = true; } - public void putHeapConst(long heapBase, long heapOopSize, long logMinObjAlignmentInBytes) { - this.heapBase = heapBase; + public void putHeapConst(long heapOopSize, long narrowOopBase, int narrowOopShift) { this.heapOopSize = heapOopSize; - this.logMinObjAlignmentInBytes = logMinObjAlignmentInBytes; + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; } /** May be called by subclasses if desired to initialize the page @@ -459,7 +459,7 @@ public abstract class DebuggerBase implements Debugger { long value = readCInteger(address, getHeapOopSize(), true); if (value != 0) { // See oop.inline.hpp decode_heap_oop - value = (long)(heapBase + (long)(value << logMinObjAlignmentInBytes)); + value = (long)(narrowOopBase + (long)(value << narrowOopShift)); } return value; } @@ -545,10 +545,10 @@ public abstract class DebuggerBase implements Debugger { return heapOopSize; } - public long getHeapBase() { - return heapBase; + public long getNarrowOopBase() { + return narrowOopBase; } - public long getLogMinObjAlignmentInBytes() { - return logMinObjAlignmentInBytes; + public int getNarrowOopShift() { + return narrowOopShift; } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java index 679036cdac0..80b71637393 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java @@ -42,5 +42,5 @@ public interface JVMDebugger extends Debugger { long jintSize, long jlongSize, long jshortSize); - public void putHeapConst(long heapBase, long heapOopSize, long logMinObjAlignment); + public void putHeapConst(long heapOopSize, long narrowOopBase, int narrowOopShift); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java index 179fc1e9d64..df03ce3e01c 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java @@ -65,9 +65,10 @@ public interface RemoteDebugger extends Remote { public long getJIntSize() throws RemoteException; public long getJLongSize() throws RemoteException; public long getJShortSize() throws RemoteException; - public long getHeapBase() throws RemoteException; public long getHeapOopSize() throws RemoteException; - public long getLogMinObjAlignmentInBytes() throws RemoteException; + public long getNarrowOopBase() throws RemoteException; + public int getNarrowOopShift() throws RemoteException; + public boolean areThreadsEqual(long addrOrId1, boolean isAddress1, long addrOrId2, boolean isAddress2) throws RemoteException; public int getThreadHashCode(long addrOrId, boolean isAddress) throws RemoteException; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java index c1464f3d98c..8a1bacb2fee 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java @@ -85,9 +85,9 @@ public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger { jlongSize = remoteDebugger.getJLongSize(); jshortSize = remoteDebugger.getJShortSize(); javaPrimitiveTypesConfigured = true; - heapBase = remoteDebugger.getHeapBase(); + narrowOopBase = remoteDebugger.getNarrowOopBase(); + narrowOopShift = remoteDebugger.getNarrowOopShift(); heapOopSize = remoteDebugger.getHeapOopSize(); - logMinObjAlignmentInBytes = remoteDebugger.getLogMinObjAlignmentInBytes(); } catch (RemoteException e) { throw new DebuggerException(e); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java index cdc5c713619..edb52a65012 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java @@ -114,17 +114,18 @@ public class RemoteDebuggerServer extends UnicastRemoteObject return debugger.getJShortSize(); } - public long getHeapBase() throws RemoteException { - return debugger.getHeapBase(); - } - public long getHeapOopSize() throws RemoteException { return debugger.getHeapOopSize(); } - public long getLogMinObjAlignmentInBytes() throws RemoteException { - return debugger.getLogMinObjAlignmentInBytes(); + public long getNarrowOopBase() throws RemoteException { + return debugger.getNarrowOopBase(); } + + public int getNarrowOopShift() throws RemoteException { + return debugger.getNarrowOopShift(); + } + public boolean areThreadsEqual(long addrOrId1, boolean isAddress1, long addrOrId2, boolean isAddress2) throws RemoteException { ThreadProxy t1 = getThreadProxy(addrOrId1, isAddress1); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java index d20dfae7445..b9cdc92ff03 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java @@ -53,7 +53,8 @@ public class Universe { // system obj array klass object private static sun.jvm.hotspot.types.OopField systemObjArrayKlassObjField; - private static AddressField heapBaseField; + private static AddressField narrowOopBaseField; + private static CIntegerField narrowOopShiftField; static { VM.registerVMInitializedObserver(new Observer() { @@ -86,7 +87,8 @@ public class Universe { systemObjArrayKlassObjField = type.getOopField("_systemObjArrayKlassObj"); - heapBaseField = type.getAddressField("_heap_base"); + narrowOopBaseField = type.getAddressField("_narrow_oop._base"); + narrowOopShiftField = type.getCIntegerField("_narrow_oop._shift"); } public Universe() { @@ -100,14 +102,18 @@ public class Universe { } } - public static long getHeapBase() { - if (heapBaseField.getValue() == null) { + public static long getNarrowOopBase() { + if (narrowOopBaseField.getValue() == null) { return 0; } else { - return heapBaseField.getValue().minus(null); + return narrowOopBaseField.getValue().minus(null); } } + public static int getNarrowOopShift() { + return (int)narrowOopShiftField.getValue(); + } + /** Returns "TRUE" iff "p" points into the allocated area of the heap. */ public boolean isIn(Address p) { return heap().isIn(p); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java index 0272c069352..4c7b772c0e4 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -342,8 +342,8 @@ public class VM { throw new RuntimeException("Attempt to initialize VM twice"); } soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian()); - debugger.putHeapConst(Universe.getHeapBase(), soleInstance.getHeapOopSize(), - soleInstance.logMinObjAlignmentInBytes); + debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(), + Universe.getNarrowOopShift()); for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) { ((Observer) iter.next()).update(null, null); } diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp index d9a7cf076da..f31d9765ae7 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp @@ -4316,7 +4316,13 @@ void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset) { void MacroAssembler::encode_heap_oop(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); verify_oop(src); + if (Universe::narrow_oop_base() == NULL) { + srlx(src, LogMinObjAlignmentInBytes, dst); + return; + } Label done; if (src == dst) { // optimize for frequent case src == dst @@ -4338,26 +4344,39 @@ void MacroAssembler::encode_heap_oop(Register src, Register dst) { void MacroAssembler::encode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); verify_oop(r); - sub(r, G6_heapbase, r); + if (Universe::narrow_oop_base() != NULL) + sub(r, G6_heapbase, r); srlx(r, LogMinObjAlignmentInBytes, r); } void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); verify_oop(src); - sub(src, G6_heapbase, dst); - srlx(dst, LogMinObjAlignmentInBytes, dst); + if (Universe::narrow_oop_base() == NULL) { + srlx(src, LogMinObjAlignmentInBytes, dst); + } else { + sub(src, G6_heapbase, dst); + srlx(dst, LogMinObjAlignmentInBytes, dst); + } } // Same algorithm as oops.inline.hpp decode_heap_oop. void MacroAssembler::decode_heap_oop(Register src, Register dst) { assert (UseCompressedOops, "must be compressed"); - Label done; + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(src, LogMinObjAlignmentInBytes, dst); - bpr(rc_nz, true, Assembler::pt, dst, done); - delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken - bind(done); + if (Universe::narrow_oop_base() != NULL) { + Label done; + bpr(rc_nz, true, Assembler::pt, dst, done); + delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken + bind(done); + } verify_oop(dst); } @@ -4366,8 +4385,11 @@ void MacroAssembler::decode_heap_oop_not_null(Register r) { // pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(r, LogMinObjAlignmentInBytes, r); - add(r, G6_heapbase, r); + if (Universe::narrow_oop_base() != NULL) + add(r, G6_heapbase, r); } void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { @@ -4375,14 +4397,17 @@ void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { // pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. assert (UseCompressedOops, "must be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); sllx(src, LogMinObjAlignmentInBytes, dst); - add(dst, G6_heapbase, dst); + if (Universe::narrow_oop_base() != NULL) + add(dst, G6_heapbase, dst); } void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { // call indirectly to solve generation ordering problem - Address base(G6_heapbase, (address)Universe::heap_base_addr()); + Address base(G6_heapbase, (address)Universe::narrow_oop_base_addr()); load_ptr_contents(base, G6_heapbase); } } diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index f9631ddf61d..03c79b5a294 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -547,7 +547,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() { int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); int klass_load_size; if (UseCompressedOops) { - klass_load_size = 3*BytesPerInstWord; // see MacroAssembler::load_klass() + assert(Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) + klass_load_size = 2*BytesPerInstWord; // see MacroAssembler::load_klass() + else + klass_load_size = 3*BytesPerInstWord; } else { klass_load_size = 1*BytesPerInstWord; } @@ -1601,9 +1605,11 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { st->print_cr("\nUEP:"); #ifdef _LP64 if (UseCompressedOops) { + assert(Universe::heap() != NULL, "java heap should be initialized"); st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass"); st->print_cr("\tSLL R_G5,3,R_G5"); - st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); + if (Universe::narrow_oop_base() != NULL) + st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); } else { st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check"); } @@ -2502,7 +2508,11 @@ encode %{ __ load_klass(O0, G3_scratch); int klass_load_size; if (UseCompressedOops) { - klass_load_size = 3*BytesPerInstWord; + assert(Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) + klass_load_size = 2*BytesPerInstWord; + else + klass_load_size = 3*BytesPerInstWord; } else { klass_load_size = 1*BytesPerInstWord; } diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index 9b4981dff7a..5ef4f23ab13 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -2942,14 +2942,15 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry; StubRoutines::_fence_entry = generate_fence(); #endif // COMPILER2 !=> _LP64 - - StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check(); } void generate_all() { // Generates all stubs and initializes the entry points + // Generate partial_subtype_check first here since its code depends on + // UseZeroBaseCompressedOops which is defined after heap initialization. + StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check(); // These entry points require SharedInfo::stack0 to be set up in non-core builds StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index e2866cb4310..96d399fc6d7 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -72,6 +72,9 @@ void VM_Version::initialize() { FLAG_SET_ERGO(bool, UseCompressedOops, false); } } + // 32-bit oops don't make sense for the 64-bit VM on sparc + // since the 32-bit VM has the same registers and smaller objects. + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); #endif // _LP64 #ifdef COMPILER2 // Indirect branch is the same cost as direct diff --git a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp index df9262ccbbd..ce2c8532d08 100644 --- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp @@ -221,13 +221,15 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { if (is_vtable_stub) { // ld;ld;ld,jmp,nop const int basic = 5*BytesPerInstWord + - // shift;add for load_klass - (UseCompressedOops ? 2*BytesPerInstWord : 0); + // shift;add for load_klass (only shift with zero heap based) + (UseCompressedOops ? + ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); return basic + slop; } else { const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + - // shift;add for load_klass - (UseCompressedOops ? 2*BytesPerInstWord : 0); + // shift;add for load_klass (only shift with zero heap based) + (UseCompressedOops ? + ((Universe::narrow_oop_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); return (basic + slop); } } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 46c5a24f45a..4bae526f395 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -727,7 +727,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { } #ifdef _LP64 - assert(false, "fix locate_operand"); + assert(which == narrow_oop_operand && !is_64bit, "instruction is not a movl adr, imm32"); #else assert(which == imm_operand, "instruction has only an imm field"); #endif // LP64 @@ -3224,12 +3224,6 @@ void Assembler::fyl2x() { emit_byte(0xF1); } -void Assembler::mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec, int format) { - InstructionMark im(this); - int encode = prefix_and_encode(dst->encoding()); - emit_byte(0xB8 | encode); - emit_data((int)imm32, rspec, format); -} #ifndef _LP64 @@ -3249,6 +3243,12 @@ void Assembler::mov_literal32(Address dst, int32_t imm32, RelocationHolder cons emit_data((int)imm32, rspec, 0); } +void Assembler::mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + int encode = prefix_and_encode(dst->encoding()); + emit_byte(0xB8 | encode); + emit_data((int)imm32, rspec, 0); +} void Assembler::popa() { // 32bit emit_byte(0x61); @@ -3857,6 +3857,37 @@ void Assembler::mov_literal64(Register dst, intptr_t imm64, RelocationHolder con emit_data64(imm64, rspec); } +void Assembler::mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + int encode = prefix_and_encode(dst->encoding()); + emit_byte(0xB8 | encode); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + +void Assembler::mov_narrow_oop(Address dst, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + prefix(dst); + emit_byte(0xC7); + emit_operand(rax, dst, 4); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + +void Assembler::cmp_narrow_oop(Register src1, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + int encode = prefix_and_encode(src1->encoding()); + emit_byte(0x81); + emit_byte(0xF8 | encode); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + +void Assembler::cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder const& rspec) { + InstructionMark im(this); + prefix(src1); + emit_byte(0x81); + emit_operand(rax, src1, 4); + emit_data((int)imm32, rspec, narrow_oop_operand); +} + void Assembler::movdq(XMMRegister dst, Register src) { // table D-1 says MMX/SSE2 NOT_LP64(assert(VM_Version::supports_sse2() || VM_Version::supports_mmx(), "")); @@ -7710,14 +7741,21 @@ void MacroAssembler::load_klass(Register dst, Register src) { void MacroAssembler::load_prototype_header(Register dst, Register src) { #ifdef _LP64 if (UseCompressedOops) { + assert (Universe::heap() != NULL, "java heap should be initialized"); movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); - movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + if (Universe::narrow_oop_shift() != 0) { + assert(Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } else { + movq(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } } else #endif - { - movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); - movptr(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); - } + { + movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); + movptr(dst, Address(dst, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); + } } void MacroAssembler::store_klass(Register dst, Register src) { @@ -7760,11 +7798,20 @@ void MacroAssembler::store_heap_oop(Address dst, Register src) { // Algorithm must match oop.inline.hpp encode_heap_oop. void MacroAssembler::encode_heap_oop(Register r) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) { + verify_oop(r, "broken oop in encode_heap_oop"); + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shrq(r, LogMinObjAlignmentInBytes); + } + return; + } #ifdef ASSERT if (CheckCompressedOops) { Label ok; push(rscratch1); // cmpptr trashes rscratch1 - cmpptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr())); + cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); jcc(Assembler::equal, ok); stop("MacroAssembler::encode_heap_oop: heap base corrupted?"); bind(ok); @@ -7780,6 +7827,7 @@ void MacroAssembler::encode_heap_oop(Register r) { void MacroAssembler::encode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); #ifdef ASSERT if (CheckCompressedOops) { Label ok; @@ -7790,12 +7838,18 @@ void MacroAssembler::encode_heap_oop_not_null(Register r) { } #endif verify_oop(r, "broken oop in encode_heap_oop_not_null"); - subq(r, r12_heapbase); - shrq(r, LogMinObjAlignmentInBytes); + if (Universe::narrow_oop_base() != NULL) { + subq(r, r12_heapbase); + } + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shrq(r, LogMinObjAlignmentInBytes); + } } void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); #ifdef ASSERT if (CheckCompressedOops) { Label ok; @@ -7809,18 +7863,32 @@ void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { if (dst != src) { movq(dst, src); } - subq(dst, r12_heapbase); - shrq(dst, LogMinObjAlignmentInBytes); + if (Universe::narrow_oop_base() != NULL) { + subq(dst, r12_heapbase); + } + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shrq(dst, LogMinObjAlignmentInBytes); + } } void MacroAssembler::decode_heap_oop(Register r) { assert (UseCompressedOops, "should be compressed"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + if (Universe::narrow_oop_base() == NULL) { + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shlq(r, LogMinObjAlignmentInBytes); + } + verify_oop(r, "broken oop in decode_heap_oop"); + return; + } #ifdef ASSERT if (CheckCompressedOops) { Label ok; push(rscratch1); cmpptr(r12_heapbase, - ExternalAddress((address)Universe::heap_base_addr())); + ExternalAddress((address)Universe::narrow_oop_base_addr())); jcc(Assembler::equal, ok); stop("MacroAssembler::decode_heap_oop: heap base corrupted?"); bind(ok); @@ -7844,32 +7912,76 @@ void MacroAssembler::decode_heap_oop(Register r) { void MacroAssembler::decode_heap_oop_not_null(Register r) { assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. - assert(Address::times_8 == LogMinObjAlignmentInBytes, "decode alg wrong"); - leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); + if (Universe::narrow_oop_base() == NULL) { + if (Universe::narrow_oop_shift() != 0) { + assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); + shlq(r, LogMinObjAlignmentInBytes); + } + } else { + assert (Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); + } } void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. - assert(Address::times_8 == LogMinObjAlignmentInBytes, "decode alg wrong"); - leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); + if (Universe::narrow_oop_shift() != 0) { + assert (Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); + } else if (dst != src) { + movq(dst, src); + } } void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { - assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); int oop_index = oop_recorder()->find_index(obj); RelocationHolder rspec = oop_Relocation::spec(oop_index); - mov_literal32(dst, oop_index, rspec, narrow_oop_operand); + mov_narrow_oop(dst, oop_index, rspec); +} + +void MacroAssembler::set_narrow_oop(Address dst, jobject obj) { + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + mov_narrow_oop(dst, oop_index, rspec); +} + +void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) { + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + Assembler::cmp_narrow_oop(dst, oop_index, rspec); +} + +void MacroAssembler::cmp_narrow_oop(Address dst, jobject obj) { + assert (UseCompressedOops, "should only be used for compressed headers"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int oop_index = oop_recorder()->find_index(obj); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + Assembler::cmp_narrow_oop(dst, oop_index, rspec); } void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { - movptr(r12_heapbase, ExternalAddress((address)Universe::heap_base_addr())); + movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); } } #endif // _LP64 diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 546f8464efe..76b4559527a 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -578,20 +578,25 @@ private: // These are all easily abused and hence protected - void mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec, int format = 0); - // 32BIT ONLY SECTION #ifndef _LP64 // Make these disappear in 64bit mode since they would never be correct void cmp_literal32(Register src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void cmp_literal32(Address src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY + void mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void push_literal32(int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY #else // 64BIT ONLY SECTION void mov_literal64(Register dst, intptr_t imm64, RelocationHolder const& rspec); // 64BIT ONLY + + void cmp_narrow_oop(Register src1, int32_t imm32, RelocationHolder const& rspec); + void cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder const& rspec); + + void mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec); + void mov_narrow_oop(Address dst, int32_t imm32, RelocationHolder const& rspec); #endif // _LP64 // These are unique in that we are ensured by the caller that the 32bit @@ -1647,6 +1652,9 @@ class MacroAssembler: public Assembler { void decode_heap_oop_not_null(Register dst, Register src); void set_narrow_oop(Register dst, jobject obj); + void set_narrow_oop(Address dst, jobject obj); + void cmp_narrow_oop(Register dst, jobject obj); + void cmp_narrow_oop(Address dst, jobject obj); // if heap base register is used - reinit it with the correct value void reinit_heapbase(); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 6518663f4a8..163c87ca18c 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -326,7 +326,6 @@ reg_class ptr_no_rax_reg(RDX, RDX_H, R9, R9_H, R10, R10_H, R11, R11_H, - R12, R12_H, R13, R13_H, R14, R14_H); @@ -340,7 +339,6 @@ reg_class ptr_no_rbp_reg(RDX, RDX_H, R9, R9_H, R10, R10_H, R11, R11_H, - R12, R12_H, R13, R13_H, R14, R14_H); @@ -354,7 +352,6 @@ reg_class ptr_no_rax_rbx_reg(RDX, RDX_H, R9, R9_H, R10, R10_H, R11, R11_H, - R12, R12_H, R13, R13_H, R14, R14_H); @@ -444,9 +441,6 @@ reg_class long_rcx_reg(RCX, RCX_H); // Singleton class for RDX long register reg_class long_rdx_reg(RDX, RDX_H); -// Singleton class for R12 long register -reg_class long_r12_reg(R12, R12_H); - // Class for all int registers (except RSP) reg_class int_reg(RAX, RDX, @@ -1842,7 +1836,9 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { if (UseCompressedOops) { st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes() #%d]\t", oopDesc::klass_offset_in_bytes()); - st->print_cr("leaq rscratch1, [r12_heapbase, r, Address::times_8, 0]"); + if (Universe::narrow_oop_shift() != 0) { + st->print_cr("leaq rscratch1, [r12_heapbase, r, Address::times_8, 0]"); + } st->print_cr("cmpq rax, rscratch1\t # Inline cache check"); } else { st->print_cr("cmpq rax, [j_rarg0 + oopDesc::klass_offset_in_bytes() #%d]\t" @@ -1891,7 +1887,11 @@ void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const uint MachUEPNode::size(PhaseRegAlloc* ra_) const { if (UseCompressedOops) { - return OptoBreakpoint ? 19 : 20; + if (Universe::narrow_oop_shift() == 0) { + return OptoBreakpoint ? 15 : 16; + } else { + return OptoBreakpoint ? 19 : 20; + } } else { return OptoBreakpoint ? 11 : 12; } @@ -2593,21 +2593,19 @@ encode %{ __ movl(Rrcx, Address(Rrdi, arrayOopDesc::length_offset_in_bytes())); __ addptr(Rrdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); if (UseCompressedOops) { + __ push(Rrax); __ encode_heap_oop(Rrax); __ repne_scanl(); - __ jcc(Assembler::notEqual, cmiss); - __ decode_heap_oop(Rrax); + __ pop(Rrax); + __ jccb(Assembler::notEqual, miss); __ movptr(Address(Rrsi, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), Rrax); __ jmp(hit); - __ bind(cmiss); - __ decode_heap_oop(Rrax); - __ jmp(miss); } else { __ repne_scan(); - __ jcc(Assembler::notEqual, miss); + __ jccb(Assembler::notEqual, miss); __ movptr(Address(Rrsi, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), @@ -4906,15 +4904,6 @@ operand rRegP() interface(REG_INTER); %} - -operand r12RegL() %{ - constraint(ALLOC_IN_RC(long_r12_reg)); - match(RegL); - - format %{ %} - interface(REG_INTER); -%} - operand rRegN() %{ constraint(ALLOC_IN_RC(int_reg)); match(RegN); @@ -5289,21 +5278,6 @@ operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) %} %} -// Indirect Narrow Oop Plus Offset Operand -operand indNarrowOopOffset(rRegN src, immL32 off) %{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN src) off); - - op_cost(10); - format %{"[R12 + $src << 3 + $off] (compressed oop addressing)" %} - interface(MEMORY_INTER) %{ - base(0xc); // R12 - index($src); - scale(0x3); - disp($off); - %} -%} - // Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) %{ @@ -5321,6 +5295,158 @@ operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) %} %} +// Indirect Narrow Oop Plus Offset Operand +// Note: x86 architecture doesn't support "scale * index + offset" without a base +// we can't free r12 even with Universe::narrow_oop_base() == NULL. +operand indCompressedOopOffset(rRegN reg, immL32 off) %{ + predicate(UseCompressedOops && (Universe::narrow_oop_shift() != 0)); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + op_cost(10); + format %{"[R12 + $reg << 3 + $off] (compressed oop addressing)" %} + interface(MEMORY_INTER) %{ + base(0xc); // R12 + index($reg); + scale(0x3); + disp($off); + %} +%} + +// Indirect Memory Operand +operand indirectNarrow(rRegN reg) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(DecodeN reg); + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Plus Short Offset Operand +operand indOffset8Narrow(rRegN reg, immL8 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + format %{ "[$reg + $off (8-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Long Offset Operand +operand indOffset32Narrow(rRegN reg, immL32 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + format %{ "[$reg + $off (32-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexOffsetNarrow(rRegN reg, rRegL lreg, immL32 off) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) lreg) off); + + op_cost(10); + format %{"[$reg + $off + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexNarrow(rRegN reg, rRegL lreg) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) lreg); + + op_cost(10); + format %{"[$reg + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleNarrow(rRegN reg, rRegL lreg, immI2 scale) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) (LShiftL lreg scale)); + + op_cost(10); + format %{"[$reg + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register Plus Offset Operand +operand indIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegL lreg, immI2 scale) +%{ + predicate(Universe::narrow_oop_shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) (LShiftL lreg scale)) off); + + op_cost(10); + format %{"[$reg + $off + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp($off); + %} +%} + +// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand +operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(Universe::narrow_oop_shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeN reg) (LShiftL (ConvI2L idx) scale)) off); + + op_cost(10); + format %{"[$reg + $off + $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp($off); + %} +%} + + //----------Special Memory Operands-------------------------------------------- // Stack Slot Operand - This operand is used for loading and storing temporary // values on the stack where a match requires a value to @@ -5488,7 +5614,10 @@ operand cmpOpUCF2() %{ opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, indIndexScale, indIndexScaleOffset, indPosIndexScaleOffset, - indNarrowOopOffset); + indCompressedOopOffset, + indirectNarrow, indOffset8Narrow, indOffset32Narrow, + indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, + indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -6234,9 +6363,7 @@ instruct loadN(rRegN dst, memory mem) ins_cost(125); // XXX format %{ "movl $dst, $mem\t# compressed ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - Register dst = as_Register($dst$$reg); - __ movl(dst, addr); + __ movl($dst$$Register, $mem$$Address); %} ins_pipe(ialu_reg_mem); // XXX %} @@ -6262,9 +6389,7 @@ instruct loadNKlass(rRegN dst, memory mem) ins_cost(125); // XXX format %{ "movl $dst, $mem\t# compressed klass ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - Register dst = as_Register($dst$$reg); - __ movl(dst, addr); + __ movl($dst$$Register, $mem$$Address); %} ins_pipe(ialu_reg_mem); // XXX %} @@ -6418,6 +6543,102 @@ instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxscaleoff" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +// Load Effective Address which uses Narrow (32-bits) oop +instruct leaPCompressedOopOffset(rRegP dst, indCompressedOopOffset mem) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_shift() != 0)); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr compressedoopoff32" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP8Narrow(rRegP dst, indOffset8Narrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); // XXX + format %{ "leaq $dst, $mem\t# ptr off8narrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP32Narrow(rRegP dst, indOffset32Narrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr off32narrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxOffNarrow(rRegP dst, indIndexOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleNarrow(rRegP dst, indIndexScaleNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscalenarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleOffNarrow(rRegP dst, indIndexScaleOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscaleoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) +%{ + predicate(Universe::narrow_oop_shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxscaleoffnarrow" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct loadConI(rRegI dst, immI src) %{ match(Set dst src); @@ -6528,8 +6749,7 @@ instruct loadConN0(rRegN dst, immN0 src, rFlagsReg cr) %{ effect(KILL cr); format %{ "xorq $dst, $src\t# compressed NULL ptr" %} ins_encode %{ - Register dst = $dst$$Register; - __ xorq(dst, dst); + __ xorq($dst$$Register, $dst$$Register); %} ins_pipe(ialu_reg); %} @@ -6541,11 +6761,10 @@ instruct loadConN(rRegN dst, immN src) %{ format %{ "movl $dst, $src\t# compressed ptr" %} ins_encode %{ address con = (address)$src$$constant; - Register dst = $dst$$Register; if (con == NULL) { ShouldNotReachHere(); } else { - __ set_narrow_oop(dst, (jobject)$src$$constant); + __ set_narrow_oop($dst$$Register, (jobject)$src$$constant); } %} ins_pipe(ialu_reg_fat); // XXX @@ -6794,12 +7013,25 @@ instruct storeP(memory mem, any_RegP src) ins_pipe(ialu_mem_reg); %} +instruct storeImmP0(memory mem, immP0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreP mem zero)); + + ins_cost(125); // XXX + format %{ "movq $mem, R12\t# ptr (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + // Store NULL Pointer, mark word, or other simple pointer constant. instruct storeImmP(memory mem, immP31 src) %{ match(Set mem (StoreP mem src)); - ins_cost(125); // XXX + ins_cost(150); // XXX format %{ "movq $mem, $src\t# ptr" %} opcode(0xC7); /* C7 /0 */ ins_encode(REX_mem_wide(mem), OpcP, RM_opc_mem(0x00, mem), Con32(src)); @@ -6814,14 +7046,55 @@ instruct storeN(memory mem, rRegN src) ins_cost(125); // XXX format %{ "movl $mem, $src\t# compressed ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - Register src = as_Register($src$$reg); - __ movl(addr, src); + __ movl($mem$$Address, $src$$Register); %} ins_pipe(ialu_mem_reg); %} +instruct storeImmN0(memory mem, immN0 zero) +%{ + predicate(Universe::narrow_oop_base() == NULL); + match(Set mem (StoreN mem zero)); + + ins_cost(125); // XXX + format %{ "movl $mem, R12\t# compressed ptr (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmN(memory mem, immN src) +%{ + match(Set mem (StoreN mem src)); + + ins_cost(150); // XXX + format %{ "movl $mem, $src\t# compressed ptr" %} + ins_encode %{ + address con = (address)$src$$constant; + if (con == NULL) { + __ movl($mem$$Address, (int32_t)0); + } else { + __ set_narrow_oop($mem$$Address, (jobject)$src$$constant); + } + %} + ins_pipe(ialu_mem_imm); +%} + // Store Integer Immediate +instruct storeImmI0(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreI mem zero)); + + ins_cost(125); // XXX + format %{ "movl $mem, R12\t# int (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmI(memory mem, immI src) %{ match(Set mem (StoreI mem src)); @@ -6834,6 +7107,19 @@ instruct storeImmI(memory mem, immI src) %} // Store Long Immediate +instruct storeImmL0(memory mem, immL0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreL mem zero)); + + ins_cost(125); // XXX + format %{ "movq $mem, R12\t# long (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmL(memory mem, immL32 src) %{ match(Set mem (StoreL mem src)); @@ -6846,6 +7132,19 @@ instruct storeImmL(memory mem, immL32 src) %} // Store Short/Char Immediate +instruct storeImmC0(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreC mem zero)); + + ins_cost(125); // XXX + format %{ "movw $mem, R12\t# short/char (R12_heapbase==0)" %} + ins_encode %{ + __ movw($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmI16(memory mem, immI16 src) %{ predicate(UseStoreImmI16); @@ -6859,6 +7158,19 @@ instruct storeImmI16(memory mem, immI16 src) %} // Store Byte Immediate +instruct storeImmB0(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreB mem zero)); + + ins_cost(125); // XXX + format %{ "movb $mem, R12\t# short/char (R12_heapbase==0)" %} + ins_encode %{ + __ movb($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmB(memory mem, immI8 src) %{ match(Set mem (StoreB mem src)); @@ -6898,6 +7210,19 @@ instruct storeA2I(memory mem, regD src) %{ %} // Store CMS card-mark Immediate +instruct storeImmCM0_reg(memory mem, immI0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreCM mem zero)); + + ins_cost(125); // XXX + format %{ "movb $mem, R12\t# CMS card-mark byte 0 (R12_heapbase==0)" %} + ins_encode %{ + __ movb($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeImmCM0(memory mem, immI0 src) %{ match(Set mem (StoreCM mem src)); @@ -6931,6 +7256,19 @@ instruct storeF(memory mem, regF src) %} // Store immediate Float value (it is faster than store from XMM register) +instruct storeF0(memory mem, immF0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreF mem zero)); + + ins_cost(25); // XXX + format %{ "movl $mem, R12\t# float 0. (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeF_imm(memory mem, immF src) %{ match(Set mem (StoreF mem src)); @@ -6957,6 +7295,7 @@ instruct storeD(memory mem, regD src) // Store immediate double 0.0 (it is faster than store from XMM register) instruct storeD0_imm(memory mem, immD0 src) %{ + predicate(!UseCompressedOops || (Universe::narrow_oop_base() != NULL)); match(Set mem (StoreD mem src)); ins_cost(50); @@ -6966,6 +7305,19 @@ instruct storeD0_imm(memory mem, immD0 src) ins_pipe(ialu_mem_imm); %} +instruct storeD0(memory mem, immD0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set mem (StoreD mem zero)); + + ins_cost(25); // XXX + format %{ "movq $mem, R12\t# double 0. (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + instruct storeSSI(stackSlotI dst, rRegI src) %{ match(Set dst src); @@ -7192,9 +7544,7 @@ instruct encodeHeapOop_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ effect(KILL cr); format %{ "encode_heap_oop_not_null $dst,$src" %} ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - __ encode_heap_oop_not_null(d, s); + __ encode_heap_oop_not_null($dst$$Register, $src$$Register); %} ins_pipe(ialu_reg_long); %} @@ -7224,7 +7574,11 @@ instruct decodeHeapOop_not_null(rRegP dst, rRegN src) %{ ins_encode %{ Register s = $src$$Register; Register d = $dst$$Register; - __ decode_heap_oop_not_null(d, s); + if (s != d) { + __ decode_heap_oop_not_null(d, s); + } else { + __ decode_heap_oop_not_null(d); + } %} ins_pipe(ialu_reg_long); %} @@ -11389,8 +11743,9 @@ instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero) // This will generate a signed flags result. This should be OK since // any compare to a zero should be eq/neq. -instruct testP_reg_mem(rFlagsReg cr, memory op, immP0 zero) +instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) %{ + predicate(!UseCompressedOops || (Universe::narrow_oop_base() != NULL)); match(Set cr (CmpP (LoadP op) zero)); ins_cost(500); // XXX @@ -11401,13 +11756,24 @@ instruct testP_reg_mem(rFlagsReg cr, memory op, immP0 zero) ins_pipe(ialu_cr_reg_imm); %} +instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) +%{ + predicate(UseCompressedOops && (Universe::narrow_oop_base() == NULL)); + match(Set cr (CmpP (LoadP mem) zero)); + + format %{ "cmpq R12, $mem\t# ptr (R12_heapbase==0)" %} + ins_encode %{ + __ cmpq(r12, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) %{ match(Set cr (CmpN op1 op2)); format %{ "cmpl $op1, $op2\t# compressed ptr" %} - ins_encode %{ __ cmpl(as_Register($op1$$reg), as_Register($op2$$reg)); %} + ins_encode %{ __ cmpl($op1$$Register, $op2$$Register); %} ins_pipe(ialu_cr_reg_reg); %} @@ -11415,11 +11781,30 @@ instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) %{ match(Set cr (CmpN src (LoadN mem))); - ins_cost(500); // XXX - format %{ "cmpl $src, mem\t# compressed ptr" %} + format %{ "cmpl $src, $mem\t# compressed ptr" %} ins_encode %{ - Address adr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ cmpl(as_Register($src$$reg), adr); + __ cmpl($src$$Register, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed ptr" %} + ins_encode %{ + __ cmp_narrow_oop($op1$$Register, (jobject)$op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) +%{ + match(Set cr (CmpN src (LoadN mem))); + + format %{ "cmpl $mem, $src\t# compressed ptr" %} + ins_encode %{ + __ cmp_narrow_oop($mem$$Address, (jobject)$src$$constant); %} ins_pipe(ialu_cr_reg_mem); %} @@ -11432,15 +11817,27 @@ instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ ins_pipe(ialu_cr_reg_imm); %} -instruct testN_reg_mem(rFlagsReg cr, memory mem, immN0 zero) +instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) %{ + predicate(Universe::narrow_oop_base() != NULL); match(Set cr (CmpN (LoadN mem) zero)); ins_cost(500); // XXX format %{ "testl $mem, 0xffffffff\t# compressed ptr" %} ins_encode %{ - Address addr = build_address($mem$$base, $mem$$index, $mem$$scale, $mem$$disp); - __ cmpl(addr, (int)0xFFFFFFFF); + __ cmpl($mem$$Address, (int)0xFFFFFFFF); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) +%{ + predicate(Universe::narrow_oop_base() == NULL); + match(Set cr (CmpN (LoadN mem) zero)); + + format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} + ins_encode %{ + __ cmpl(r12, $mem$$Address); %} ins_pipe(ialu_cr_reg_mem); %} @@ -11472,7 +11869,6 @@ instruct compL_rReg_mem(rFlagsReg cr, rRegL op1, memory op2) %{ match(Set cr (CmpL op1 (LoadL op2))); - ins_cost(500); // XXX format %{ "cmpq $op1, $op2" %} opcode(0x3B); /* Opcode 3B /r */ ins_encode(REX_reg_mem_wide(op1, op2), OpcP, reg_mem(op1, op2)); @@ -11756,7 +12152,6 @@ instruct partialSubtypeCheck_vs_Zero(rFlagsReg cr, rdi_RegP result) %{ match(Set cr (CmpP (PartialSubtypeCheck sub super) zero)); - predicate(!UseCompressedOops); // decoding oop kills condition codes effect(KILL rcx, KILL result); ins_cost(1000); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 846906951d4..178985fce7b 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2582,7 +2582,7 @@ bool os::large_page_init() { #define SHM_HUGETLB 04000 #endif -char* os::reserve_memory_special(size_t bytes) { +char* os::reserve_memory_special(size_t bytes, char* req_addr) { assert(UseLargePages, "only for large pages"); key_t key = IPC_PRIVATE; diff --git a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp index feedb287ada..5ad280c3b7b 100644 --- a/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp +++ b/hotspot/src/os/solaris/dtrace/generateJvmOffsets.cpp @@ -249,6 +249,10 @@ int generateJvmOffsets(GEN_variant gen_variant) { printf("\n"); + GEN_OFFS(NarrowOopStruct, _base); + GEN_OFFS(NarrowOopStruct, _shift); + printf("\n"); + GEN_VALUE(SIZE_HeapBlockHeader, sizeof(HeapBlock::Header)); GEN_SIZE(oopDesc); GEN_SIZE(constantPoolOopDesc); diff --git a/hotspot/src/os/solaris/dtrace/jhelper.d b/hotspot/src/os/solaris/dtrace/jhelper.d index 6f2f6165c35..da5837238c8 100644 --- a/hotspot/src/os/solaris/dtrace/jhelper.d +++ b/hotspot/src/os/solaris/dtrace/jhelper.d @@ -46,7 +46,10 @@ extern pointer __JvmOffsets; extern pointer __1cJCodeCacheF_heap_; extern pointer __1cIUniverseP_methodKlassObj_; extern pointer __1cIUniverseO_collectedHeap_; -extern pointer __1cIUniverseK_heap_base_; +extern pointer __1cIUniverseL_narrow_oop_; +#ifdef _LP64 +extern pointer UseCompressedOops; +#endif extern pointer __1cHnmethodG__vtbl_; extern pointer __1cKBufferBlobG__vtbl_; @@ -56,6 +59,7 @@ extern pointer __1cKBufferBlobG__vtbl_; #define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t)) #define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t)) #define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t)) +#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t)) #define SAME(x) x #define copyin_offset(JVM_CONST) JVM_CONST = \ @@ -132,6 +136,9 @@ dtrace:helper:ustack: copyin_offset(SIZE_oopDesc); copyin_offset(SIZE_constantPoolOopDesc); + copyin_offset(OFFSET_NarrowOopStruct_base); + copyin_offset(OFFSET_NarrowOopStruct_shift); + /* * The PC to translate is in arg0. */ @@ -151,9 +158,19 @@ dtrace:helper:ustack: this->Universe_methodKlassOop = copyin_ptr(&``__1cIUniverseP_methodKlassObj_); this->CodeCache_heap_address = copyin_ptr(&``__1cJCodeCacheF_heap_); - this->Universe_heap_base = copyin_ptr(&``__1cIUniverseK_heap_base_); /* Reading volatile values */ +#ifdef _LP64 + this->Use_Compressed_Oops = copyin_uint8(&``UseCompressedOops); +#else + this->Use_Compressed_Oops = 0; +#endif + + this->Universe_narrow_oop_base = copyin_ptr(&``__1cIUniverseL_narrow_oop_ + + OFFSET_NarrowOopStruct_base); + this->Universe_narrow_oop_shift = copyin_int32(&``__1cIUniverseL_narrow_oop_ + + OFFSET_NarrowOopStruct_shift); + this->CodeCache_low = copyin_ptr(this->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); @@ -295,7 +312,7 @@ dtrace:helper:ustack: dtrace:helper:ustack: /!this->done && this->vtbl == this->BufferBlob_vtbl && -this->Universe_heap_base == NULL && +this->Use_Compressed_Oops == 0 && this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ { MARK_LINE; @@ -306,7 +323,7 @@ this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ dtrace:helper:ustack: /!this->done && this->vtbl == this->BufferBlob_vtbl && -this->Universe_heap_base != NULL && +this->Use_Compressed_Oops != 0 && this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ { MARK_LINE; @@ -314,8 +331,8 @@ this->methodOopPtr > this->heap_start && this->methodOopPtr < this->heap_end/ * Read compressed pointer and decode heap oop, same as oop.inline.hpp */ this->cklass = copyin_uint32(this->methodOopPtr + OFFSET_oopDesc_metadata); - this->klass = (uint64_t)((uintptr_t)this->Universe_heap_base + - ((uintptr_t)this->cklass << 3)); + this->klass = (uint64_t)((uintptr_t)this->Universe_narrow_oop_base + + ((uintptr_t)this->cklass << this->Universe_narrow_oop_shift)); this->methodOop = this->klass == this->Universe_methodKlassOop; this->done = !this->methodOop; } diff --git a/hotspot/src/os/solaris/dtrace/libjvm_db.c b/hotspot/src/os/solaris/dtrace/libjvm_db.c index ad0031e4b92..afa443092b4 100644 --- a/hotspot/src/os/solaris/dtrace/libjvm_db.c +++ b/hotspot/src/os/solaris/dtrace/libjvm_db.c @@ -146,13 +146,17 @@ struct jvm_agent { uint64_t BufferBlob_vtbl; uint64_t RuntimeStub_vtbl; + uint64_t Use_Compressed_Oops_address; uint64_t Universe_methodKlassObj_address; + uint64_t Universe_narrow_oop_base_address; + uint64_t Universe_narrow_oop_shift_address; uint64_t CodeCache_heap_address; - uint64_t Universe_heap_base_address; /* Volatiles */ + uint8_t Use_Compressed_Oops; uint64_t Universe_methodKlassObj; - uint64_t Universe_heap_base; + uint64_t Universe_narrow_oop_base; + uint32_t Universe_narrow_oop_shift; uint64_t CodeCache_low; uint64_t CodeCache_high; uint64_t CodeCache_segmap_low; @@ -279,8 +283,11 @@ static int parse_vmstructs(jvm_agent_t* J) { if (strcmp("_methodKlassObj", vmp->fieldName) == 0) { J->Universe_methodKlassObj_address = vmp->address; } - if (strcmp("_heap_base", vmp->fieldName) == 0) { - J->Universe_heap_base_address = vmp->address; + if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { + J->Universe_narrow_oop_base_address = vmp->address; + } + if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { + J->Universe_narrow_oop_shift_address = vmp->address; } } CHECK_FAIL(err); @@ -298,14 +305,39 @@ static int parse_vmstructs(jvm_agent_t* J) { return -1; } +static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { + psaddr_t sym_addr; + int err; + + err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); + if (err != PS_OK) goto fail; + *valuep = sym_addr; + return PS_OK; + + fail: + return err; +} + static int read_volatiles(jvm_agent_t* J) { uint64_t ptr; int err; + err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); + if (err == PS_OK) { + err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); + CHECK_FAIL(err); + } else { + J->Use_Compressed_Oops = 0; + } + err = read_pointer(J, J->Universe_methodKlassObj_address, &J->Universe_methodKlassObj); CHECK_FAIL(err); - err = read_pointer(J, J->Universe_heap_base_address, &J->Universe_heap_base); + + err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); CHECK_FAIL(err); + err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); + CHECK_FAIL(err); + err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low, &J->CodeCache_low); CHECK_FAIL(err); @@ -374,19 +406,6 @@ static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { return -1; } -static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { - psaddr_t sym_addr; - int err; - - err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); - if (err != PS_OK) goto fail; - *valuep = sym_addr; - return PS_OK; - - fail: - return err; -} - static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { psaddr_t sym_addr; int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); @@ -458,14 +477,14 @@ void Jagent_destroy(jvm_agent_t *J) { static int is_methodOop(jvm_agent_t* J, uint64_t methodOopPtr) { uint64_t klass; int err; - // If heap_base is nonnull, this was a compressed oop. - if (J->Universe_heap_base != NULL) { + // If UseCompressedOops, this was a compressed oop. + if (J->Use_Compressed_Oops != 0) { uint32_t cklass; err = read_compressed_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, &cklass); // decode heap oop, same as oop.inline.hpp - klass = (uint64_t)((uintptr_t)J->Universe_heap_base + - ((uintptr_t)cklass << 3)); + klass = (uint64_t)((uintptr_t)J->Universe_narrow_oop_base + + ((uintptr_t)cklass << J->Universe_narrow_oop_shift)); } else { err = read_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, &klass); } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index a74eb33f9da..165c71e659f 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -3220,7 +3220,7 @@ bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) { return true; } -char* os::reserve_memory_special(size_t bytes) { +char* os::reserve_memory_special(size_t bytes, char* addr) { assert(UseLargePages && UseISM, "only for ISM large pages"); size_t size = bytes; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index dce602e8ecb..66651f29f5e 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2595,7 +2595,7 @@ bool os::can_execute_large_page_memory() { return true; } -char* os::reserve_memory_special(size_t bytes) { +char* os::reserve_memory_special(size_t bytes, char* addr) { if (UseLargePagesIndividualAllocation) { if (TracePageSizes && Verbose) { @@ -2615,7 +2615,7 @@ char* os::reserve_memory_special(size_t bytes) { "use -XX:-UseLargePagesIndividualAllocation to turn off"); return NULL; } - p_buf = (char *) VirtualAlloc(NULL, + p_buf = (char *) VirtualAlloc(addr, size_of_reserve, // size of Reserve MEM_RESERVE, PAGE_EXECUTE_READWRITE); diff --git a/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp b/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp index ccc884e8329..68be1d43523 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp @@ -30,5 +30,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 12288); define_pd_global(intx, CompilerThreadStackSize, 0); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 4*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp index 317993ce58f..24d2bab7c19 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp @@ -43,5 +43,7 @@ define_pd_global(intx, SurvivorRatio, 8); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 2*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp index c0bf513235e..71f16d94158 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp @@ -30,5 +30,9 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 12288); define_pd_global(intx, CompilerThreadStackSize, 0); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 4*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); + + diff --git a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp index aef1d7314d3..754195f10ff 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp @@ -46,5 +46,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 10*K); define_pd_global(intx, CompilerThreadStackSize, 0); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 256*M); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp index 7c578df700c..97226fa37dd 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp @@ -45,5 +45,7 @@ define_pd_global(intx, CompilerThreadStackSize, 0); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); +// Only used on 64 bit platforms +define_pd_global(uintx, HeapBaseMinAddress, 2*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/share/vm/asm/assembler.cpp b/hotspot/src/share/vm/asm/assembler.cpp index 1cbbad6d435..e41fc7e9d31 100644 --- a/hotspot/src/share/vm/asm/assembler.cpp +++ b/hotspot/src/share/vm/asm/assembler.cpp @@ -321,16 +321,19 @@ void AbstractAssembler::block_comment(const char* comment) { bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Exception handler checks the nmethod's implicit null checks table // only when this method returns false. - if (UseCompressedOops) { +#ifdef _LP64 + if (UseCompressedOops && Universe::narrow_oop_base() != NULL) { + assert (Universe::heap() != NULL, "java heap should be initialized"); // The first page after heap_base is unmapped and // the 'offset' is equal to [heap_base + offset] for // narrow oop implicit null checks. - uintptr_t heap_base = (uintptr_t)Universe::heap_base(); - if ((uintptr_t)offset >= heap_base) { + uintptr_t base = (uintptr_t)Universe::narrow_oop_base(); + if ((uintptr_t)offset >= base) { // Normalize offset for the next check. - offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); + offset = (intptr_t)(pointer_delta((void*)offset, (void*)base, 1)); } } +#endif return offset < 0 || os::vm_page_size() <= offset; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 03063b56396..a94f9a8755e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1360,9 +1360,34 @@ jint G1CollectedHeap::initialize() { // Reserve the maximum. PermanentGenerationSpec* pgs = collector_policy()->permanent_generation(); // Includes the perm-gen. + + const size_t total_reserved = max_byte_size + pgs->max_size(); + char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); + ReservedSpace heap_rs(max_byte_size + pgs->max_size(), HeapRegion::GrainBytes, - false /*ism*/); + false /*ism*/, addr); + + if (UseCompressedOops) { + if (addr != NULL && !heap_rs.is_reserved()) { + // Failed to reserve at specified address - the requested memory + // region is taken already, for example, by 'java' launcher. + // Try again to reserver heap higher. + addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + ReservedSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, + false /*ism*/, addr); + if (addr != NULL && !heap_rs0.is_reserved()) { + // Failed to reserve at specified address again - give up. + addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + assert(addr == NULL, ""); + ReservedSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, + false /*ism*/, addr); + heap_rs = heap_rs1; + } else { + heap_rs = heap_rs0; + } + } + } if (!heap_rs.is_reserved()) { vm_exit_during_initialization("Could not reserve enough space for object heap"); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index 2d5334b780c..195847a66e2 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -104,12 +104,38 @@ jint ParallelScavengeHeap::initialize() { og_min_size, og_max_size, yg_min_size, yg_max_size); + const size_t total_reserved = pg_max_size + og_max_size + yg_max_size; + char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); + // The main part of the heap (old gen + young gen) can often use a larger page // size than is needed or wanted for the perm gen. Use the "compound // alignment" ReservedSpace ctor to avoid having to use the same page size for // all gens. + ReservedHeapSpace heap_rs(pg_max_size, pg_align, og_max_size + yg_max_size, - og_align); + og_align, addr); + + if (UseCompressedOops) { + if (addr != NULL && !heap_rs.is_reserved()) { + // Failed to reserve at specified address - the requested memory + // region is taken already, for example, by 'java' launcher. + // Try again to reserver heap higher. + addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + ReservedHeapSpace heap_rs0(pg_max_size, pg_align, og_max_size + yg_max_size, + og_align, addr); + if (addr != NULL && !heap_rs0.is_reserved()) { + // Failed to reserve at specified address again - give up. + addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + assert(addr == NULL, ""); + ReservedHeapSpace heap_rs1(pg_max_size, pg_align, og_max_size + yg_max_size, + og_align, addr); + heap_rs = heap_rs1; + } else { + heap_rs = heap_rs0; + } + } + } + os::trace_page_sizes("ps perm", pg_min_size, pg_max_size, pg_page_sz, heap_rs.base(), pg_max_size); os::trace_page_sizes("ps main", og_min_size + yg_min_size, diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 77e9a5cd0d3..58a4892785d 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -218,6 +218,31 @@ char* GenCollectedHeap::allocate(size_t alignment, heap_address -= total_reserved; } else { heap_address = NULL; // any address will do. + if (UseCompressedOops) { + heap_address = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); + *_total_reserved = total_reserved; + *_n_covered_regions = n_covered_regions; + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); + + if (heap_address != NULL && !heap_rs->is_reserved()) { + // Failed to reserve at specified address - the requested memory + // region is taken already, for example, by 'java' launcher. + // Try again to reserver heap higher. + heap_address = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); + + if (heap_address != NULL && !heap_rs->is_reserved()) { + // Failed to reserve at specified address again - give up. + heap_address = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + assert(heap_address == NULL, ""); + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); + } + } + return heap_address; + } } *_total_reserved = total_reserved; diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 88243f2d56c..09df28b38ec 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -99,7 +99,8 @@ size_t Universe::_heap_capacity_at_last_gc; size_t Universe::_heap_used_at_last_gc = 0; CollectedHeap* Universe::_collectedHeap = NULL; -address Universe::_heap_base = NULL; + +NarrowOopStruct Universe::_narrow_oop = { NULL, 0, true }; void Universe::basic_type_classes_do(void f(klassOop)) { @@ -729,6 +730,53 @@ jint universe_init() { return JNI_OK; } +// Choose the heap base address and oop encoding mode +// when compressed oops are used: +// Unscaled - Use 32-bits oops without encoding when +// NarrowOopHeapBaseMin + heap_size < 4Gb +// ZeroBased - Use zero based compressed oops with encoding when +// NarrowOopHeapBaseMin + heap_size < 32Gb +// HeapBased - Use compressed oops with heap base + encoding. + +// 4Gb +static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1); +// 32Gb +static const uint64_t OopEncodingHeapMax = NarrowOopHeapMax << LogMinObjAlignmentInBytes; + +char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { +#ifdef _LP64 + if (UseCompressedOops) { + assert(mode == UnscaledNarrowOop || + mode == ZeroBasedNarrowOop || + mode == HeapBasedNarrowOop, "mode is invalid"); + + const size_t total_size = heap_size + HeapBaseMinAddress; + if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { + if (total_size <= NarrowOopHeapMax && (mode == UnscaledNarrowOop) && + (Universe::narrow_oop_shift() == 0)) { + // Use 32-bits oops without encoding and + // place heap's top on the 4Gb boundary + return (char*)(NarrowOopHeapMax - heap_size); + } else { + // Can't reserve with NarrowOopShift == 0 + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + if (mode == UnscaledNarrowOop || + mode == ZeroBasedNarrowOop && total_size <= NarrowOopHeapMax) { + // Use zero based compressed oops with encoding and + // place heap's top on the 32Gb boundary in case + // total_size > 4Gb or failed to reserve below 4Gb. + return (char*)(OopEncodingHeapMax - heap_size); + } + } + } else { + // Can't reserve below 32Gb. + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + } + } +#endif + return NULL; // also return NULL (don't care) for 32-bit VM +} + jint Universe::initialize_heap() { if (UseParallelGC) { @@ -773,6 +821,8 @@ jint Universe::initialize_heap() { if (status != JNI_OK) { return status; } + +#ifdef _LP64 if (UseCompressedOops) { // Subtract a page because something can get allocated at heap base. // This also makes implicit null checking work, because the @@ -780,8 +830,49 @@ jint Universe::initialize_heap() { // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. - Universe::_heap_base = Universe::heap()->base() - os::vm_page_size(); + if (PrintCompressedOopsMode) { + tty->cr(); + tty->print("heap address: "PTR_FORMAT, Universe::heap()->base()); + } + if ((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) { + // Can't reserve heap below 32Gb. + Universe::set_narrow_oop_base(Universe::heap()->base() - os::vm_page_size()); + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + if (PrintCompressedOopsMode) { + tty->print(", Compressed Oops with base: "PTR_FORMAT, Universe::narrow_oop_base()); + } + } else { + Universe::set_narrow_oop_base(0); + if (PrintCompressedOopsMode) { + tty->print(", zero based Compressed Oops"); + } +#ifdef _WIN64 + if (!Universe::narrow_oop_use_implicit_null_checks()) { + // Don't need guard page for implicit checks in indexed addressing + // mode with zero based Compressed Oops. + Universe::set_narrow_oop_use_implicit_null_checks(true); + } +#endif // _WIN64 + if((uint64_t)Universe::heap()->reserved_region().end() > NarrowOopHeapMax) { + // Can't reserve heap below 4Gb. + Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); + } else { + assert(Universe::narrow_oop_shift() == 0, "use unscaled narrow oop"); + if (PrintCompressedOopsMode) { + tty->print(", 32-bits Oops"); + } + } + } + if (PrintCompressedOopsMode) { + tty->cr(); + tty->cr(); + } } + assert(Universe::narrow_oop_base() == (Universe::heap()->base() - os::vm_page_size()) || + Universe::narrow_oop_base() == NULL, "invalid value"); + assert(Universe::narrow_oop_shift() == LogMinObjAlignmentInBytes || + Universe::narrow_oop_shift() == 0, "invalid value"); +#endif // We will never reach the CATCH below since Exceptions::_throw will cause // the VM to exit if an exception is thrown during initialization diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 45c9f96d21f..e3d945a0dcd 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -90,6 +90,19 @@ class LatestMethodOopCache : public CommonMethodOopCache { methodOop get_methodOop(); }; +// For UseCompressedOops. +struct NarrowOopStruct { + // Base address for oop-within-java-object materialization. + // NULL if using wide oops or zero based narrow oops. + address _base; + // Number of shift bits for encoding/decoding narrow oops. + // 0 if using wide oops or zero based unscaled narrow oops, + // LogMinObjAlignmentInBytes otherwise. + int _shift; + // Generate code with implicit null checks for narrow oops. + bool _use_implicit_null_checks; +}; + class Universe: AllStatic { // Ugh. Universe is much too friendly. @@ -181,9 +194,9 @@ class Universe: AllStatic { // The particular choice of collected heap. static CollectedHeap* _collectedHeap; - // Base address for oop-within-java-object materialization. - // NULL if using wide oops. Doubles as heap oop null value. - static address _heap_base; + + // For UseCompressedOops. + static struct NarrowOopStruct _narrow_oop; // array of dummy objects used with +FullGCAlot debug_only(static objArrayOop _fullgc_alot_dummy_array;) @@ -328,8 +341,25 @@ class Universe: AllStatic { static CollectedHeap* heap() { return _collectedHeap; } // For UseCompressedOops - static address heap_base() { return _heap_base; } - static address* heap_base_addr() { return &_heap_base; } + static address* narrow_oop_base_addr() { return &_narrow_oop._base; } + static address narrow_oop_base() { return _narrow_oop._base; } + static int narrow_oop_shift() { return _narrow_oop._shift; } + static void set_narrow_oop_base(address base) { _narrow_oop._base = base; } + static void set_narrow_oop_shift(int shift) { _narrow_oop._shift = shift; } + static bool narrow_oop_use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; } + static void set_narrow_oop_use_implicit_null_checks(bool use) { _narrow_oop._use_implicit_null_checks = use; } + // Narrow Oop encoding mode: + // 0 - Use 32-bits oops without encoding when + // NarrowOopHeapBaseMin + heap_size < 4Gb + // 1 - Use zero based compressed oops with encoding when + // NarrowOopHeapBaseMin + heap_size < 32Gb + // 2 - Use compressed oops with heap base + encoding. + enum NARROW_OOP_MODE { + UnscaledNarrowOop = 0, + ZeroBasedNarrowOop = 1, + HeapBasedNarrowOop = 2 + }; + static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); // Historic gc information static size_t get_heap_capacity_at_last_gc() { return _heap_capacity_at_last_gc; } diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp index 9161310de60..509a3c840a6 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.inline.hpp @@ -148,10 +148,11 @@ inline bool oopDesc::is_null(narrowOop obj) { return obj == 0; } inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { assert(!is_null(v), "oop value can never be zero"); - address heap_base = Universe::heap_base(); - uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)heap_base, 1)); + address base = Universe::narrow_oop_base(); + int shift = Universe::narrow_oop_shift(); + uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); - uint64_t result = pd >> LogMinObjAlignmentInBytes; + uint64_t result = pd >> shift; assert((result & CONST64(0xffffffff00000000)) == 0, "narrow oop overflow"); return (narrowOop)result; } @@ -162,8 +163,9 @@ inline narrowOop oopDesc::encode_heap_oop(oop v) { inline oop oopDesc::decode_heap_oop_not_null(narrowOop v) { assert(!is_null(v), "narrow oop value can never be zero"); - address heap_base = Universe::heap_base(); - return (oop)(void*)((uintptr_t)heap_base + ((uintptr_t)v << LogMinObjAlignmentInBytes)); + address base = Universe::narrow_oop_base(); + int shift = Universe::narrow_oop_shift(); + return (oop)(void*)((uintptr_t)base + ((uintptr_t)v << shift)); } inline oop oopDesc::decode_heap_oop(narrowOop v) { diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp index 2ff10cd083d..63932df349d 100644 --- a/hotspot/src/share/vm/opto/addnode.cpp +++ b/hotspot/src/share/vm/opto/addnode.cpp @@ -756,7 +756,13 @@ const Type *AddPNode::mach_bottom_type( const MachNode* n) { if ( eti == NULL ) { // there must be one pointer among the operands guarantee(tptr == NULL, "must be only one pointer operand"); - tptr = et->isa_oopptr(); + if (UseCompressedOops && Universe::narrow_oop_shift() == 0) { + // 32-bits narrow oop can be the base of address expressions + tptr = et->make_ptr()->isa_oopptr(); + } else { + // only regular oops are expected here + tptr = et->isa_oopptr(); + } guarantee(tptr != NULL, "non-int operand must be pointer"); if (tptr->higher_equal(tp->add_offset(tptr->offset()))) tp = tptr; // Set more precise type for bailout diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index d1b9332a9cd..f3197152194 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -2081,7 +2081,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { #ifdef _LP64 case Op_CastPP: - if (n->in(1)->is_DecodeN() && UseImplicitNullCheckForNarrowOop) { + if (n->in(1)->is_DecodeN() && Universe::narrow_oop_use_implicit_null_checks()) { Compile* C = Compile::current(); Node* in1 = n->in(1); const Type* t = n->bottom_type(); @@ -2136,7 +2136,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) { new_in2 = in2->in(1); } else if (in2->Opcode() == Op_ConP) { const Type* t = in2->bottom_type(); - if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) { + if (t == TypePtr::NULL_PTR && Universe::narrow_oop_use_implicit_null_checks()) { new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); // // This transformation together with CastPP transformation above diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index d46b6d4e952..46f13c652b6 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -433,7 +433,7 @@ Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { // If not converting int->oop, throw away cast after constant propagation Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { const Type *t = ccp->type(in(1)); - if (!t->isa_oop_ptr() || in(1)->is_DecodeN()) { + if (!t->isa_oop_ptr() || (in(1)->is_DecodeN() && Universe::narrow_oop_use_implicit_null_checks())) { return NULL; // do not transform raw pointers or narrow oops } return ConstraintCastNode::Ideal_DU_postCCP(ccp); diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index dcedbd61f83..48d24dcb9b8 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -158,7 +158,14 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe continue; // Give up if offset is beyond page size // cannot reason about it; is probably not implicit null exception } else { - const TypePtr* tptr = base->bottom_type()->is_ptr(); + const TypePtr* tptr; + if (UseCompressedOops && Universe::narrow_oop_shift() == 0) { + // 32-bits narrow oop can be the base of address expressions + tptr = base->bottom_type()->make_ptr(); + } else { + // only regular oops are expected here + tptr = base->bottom_type()->is_ptr(); + } // Give up if offset is not a compile-time constant if( offset == Type::OffsetBot || tptr->_offset == Type::OffsetBot ) continue; diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 74c7a70878e..f72503d61d8 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1481,8 +1481,13 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) { const Type* mach_at = mach->adr_type(); // DecodeN node consumed by an address may have different type // then its input. Don't compare types for such case. - if (m->adr_type() != mach_at && m->in(MemNode::Address)->is_AddP() && - m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeN()) { + if (m->adr_type() != mach_at && + (m->in(MemNode::Address)->is_DecodeN() || + m->in(MemNode::Address)->is_AddP() && + m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeN() || + m->in(MemNode::Address)->is_AddP() && + m->in(MemNode::Address)->in(AddPNode::Address)->is_AddP() && + m->in(MemNode::Address)->in(AddPNode::Address)->in(AddPNode::Address)->is_DecodeN())) { mach_at = m->adr_type(); } if (m->adr_type() != mach_at) { diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 417522943ad..664fcdd03ac 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1211,7 +1211,9 @@ void Arguments::set_ergonomics_flags() { if (UseLargePages && UseCompressedOops) { // Cannot allocate guard pages for implicit checks in indexed addressing // mode, when large pages are specified on windows. - FLAG_SET_DEFAULT(UseImplicitNullCheckForNarrowOop, false); + // This flag could be switched ON if narrow oop base address is set to 0, + // see code in Universe::initialize_heap(). + Universe::set_narrow_oop_use_implicit_null_checks(false); } #endif // _WIN64 } else { diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 0ed9522f39e..9855d5b8e5b 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -303,11 +303,14 @@ class CommandLineFlags { "Use 32-bit object references in 64-bit VM. " \ "lp64_product means flag is always constant in 32 bit VM") \ \ - lp64_product(bool, CheckCompressedOops, trueInDebug, \ - "generate checks in encoding/decoding code") \ + notproduct(bool, CheckCompressedOops, true, \ + "generate checks in encoding/decoding code in debug VM") \ \ - product(bool, UseImplicitNullCheckForNarrowOop, true, \ - "generate implicit null check in indexed addressing mode.") \ + product_pd(uintx, HeapBaseMinAddress, \ + "OS specific low limit for heap base address") \ + \ + diagnostic(bool, PrintCompressedOopsMode, false, \ + "Print compressed oops base address and encoding mode") \ \ /* UseMembar is theoretically a temp flag used for memory barrier \ * removal testing. It was supposed to be removed before FCS but has \ diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index ce653c5f6f2..1236002d8ed 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -243,7 +243,7 @@ class os: AllStatic { static char* non_memory_address_word(); // reserve, commit and pin the entire memory region - static char* reserve_memory_special(size_t size); + static char* reserve_memory_special(size_t size, char* addr = NULL); static bool release_memory_special(char* addr, size_t bytes); static bool large_page_init(); static size_t large_page_size(); diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index 5cd996194d9..8ade3eb6abe 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -109,6 +109,7 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, const size_t suffix_align, + char* requested_address, const size_t noaccess_prefix) { assert(prefix_size != 0, "sanity"); @@ -131,7 +132,7 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, const bool try_reserve_special = UseLargePages && prefix_align == os::large_page_size(); if (!os::can_commit_large_page_memory() && try_reserve_special) { - initialize(size, prefix_align, true, NULL, noaccess_prefix); + initialize(size, prefix_align, true, requested_address, noaccess_prefix); return; } @@ -146,7 +147,13 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, noaccess_prefix == prefix_align, "noaccess prefix wrong"); // Optimistically try to reserve the exact size needed. - char* addr = os::reserve_memory(size, NULL, prefix_align); + char* addr; + if (requested_address != 0) { + addr = os::attempt_reserve_memory_at(size, + requested_address-noaccess_prefix); + } else { + addr = os::reserve_memory(size, NULL, prefix_align); + } if (addr == NULL) return; // Check whether the result has the needed alignment (unlikely unless @@ -206,12 +213,8 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* base = NULL; if (special) { - // It's not hard to implement reserve_memory_special() such that it can - // allocate at fixed address, but there seems no use of this feature - // for now, so it's not implemented. - assert(requested_address == NULL, "not implemented"); - base = os::reserve_memory_special(size); + base = os::reserve_memory_special(size, requested_address); if (base != NULL) { // Check alignment constraints @@ -372,7 +375,8 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large, char* requested_address) : ReservedSpace(size, alignment, large, requested_address, - UseCompressedOops && UseImplicitNullCheckForNarrowOop ? + (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && + Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), alignment) : 0) { // Only reserved space for the java heap should have a noaccess_prefix // if using compressed oops. @@ -382,9 +386,12 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, ReservedHeapSpace::ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, - const size_t suffix_align) : + const size_t suffix_align, + char* requested_address) : ReservedSpace(prefix_size, prefix_align, suffix_size, suffix_align, - UseCompressedOops && UseImplicitNullCheckForNarrowOop ? + requested_address, + (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && + Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), prefix_align) : 0) { protect_noaccess_prefix(prefix_size+suffix_size); } diff --git a/hotspot/src/share/vm/runtime/virtualspace.hpp b/hotspot/src/share/vm/runtime/virtualspace.hpp index fa65035fde0..b6e5a71099b 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.hpp +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp @@ -73,7 +73,8 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { const size_t noaccess_prefix = 0); ReservedSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, const size_t suffix_align, - const size_t noaccess_prefix); + char* requested_address, + const size_t noaccess_prefix = 0); // Accessors char* base() const { return _base; } @@ -121,7 +122,8 @@ public: ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large, char* requested_address); ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align, - const size_t suffix_size, const size_t suffix_align); + const size_t suffix_size, const size_t suffix_align, + char* requested_address); }; // VirtualSpace is data structure for committing a previously reserved address range in smaller chunks. diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index bc8ea34d52e..2de7bbdf56f 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -263,7 +263,9 @@ static inline uint64_t cast_uint64_t(size_t x) static_field(Universe, _bootstrapping, bool) \ static_field(Universe, _fully_initialized, bool) \ static_field(Universe, _verify_count, int) \ - static_field(Universe, _heap_base, address) \ + static_field(Universe, _narrow_oop._base, address) \ + static_field(Universe, _narrow_oop._shift, int) \ + static_field(Universe, _narrow_oop._use_implicit_null_checks, bool) \ \ /**********************************************************************************/ \ /* Generation and Space hierarchies */ \ From 1e875ce5627423db8ee32e750606f8c7aab1d582 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 12 Mar 2009 14:01:36 -0700 Subject: [PATCH 03/43] 6816433: Test G1 and ParOld in JPRT Reviewed-by: jmasa, never, ysr --- hotspot/make/jprt.properties | 97 ++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 012015262ae..63320086cd8 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -19,12 +19,12 @@ # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. -# +# # # Properties for jprt -# All build result bundles are full jdks, so the 64bit testing does not +# All build result bundles are full jdks, so the 64bit testing does not # need the 32bit sibling bundle installed. # Note: If the hotspot/make/Makefile changed to only bundle the 64bit files # when bundling 64bit, and stripped out the 64bit files from any 32bit @@ -89,60 +89,52 @@ jprt.my.solaris.sparc.test.targets= \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp_2, \ - ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese_Xcomp_3, \ ${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_default_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_CMS_2, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_default, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParNewGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_CMS, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_G1, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_default, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark_2, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark_3 + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_G1, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParOldGC jprt.my.solaris.sparcv9.test.targets= \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \ ${jprt.my.solaris.sparcv9}-product-c2-runThese, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp_2, \ - ${jprt.my.solaris.sparcv9}-product-c2-runThese_Xcomp_3, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_CMS_2, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_G1, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParOldGC jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \ @@ -154,73 +146,80 @@ jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_default_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_SerialGC_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC_2, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_CMS_2, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_CMS + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC jprt.my.solaris.i586.test.targets= \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \ - ${jprt.my.solaris.i586}-product-c2-runThese_Xcomp_2, \ - ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp_2, \ + ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp, \ ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xshare, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_default, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_SerialGC, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_ParallelGC, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_ParNewGC, \ ${jprt.my.solaris.i586}-product-c1-GCBasher_CMS, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_G1, \ + ${jprt.my.solaris.i586}-product-c1-GCBasher_ParOldGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_default, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_SerialGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParallelGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParNewGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_CMS, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_G1, \ + ${jprt.my.solaris.i586}-fastdebug-c2-GCBasher_ParOldGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_default, \ ${jprt.my.solaris.i586}-product-c1-GCOld_SerialGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_ParallelGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_ParNewGC, \ ${jprt.my.solaris.i586}-product-c1-GCOld_CMS, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_G1, \ + ${jprt.my.solaris.i586}-product-c1-GCOld_ParOldGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark_2, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark_3 + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_G1, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParOldGC jprt.my.linux.i586.test.targets = \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \ - ${jprt.my.linux.i586}-product-c1-runThese_Xcomp_2, \ - ${jprt.my.linux.i586}-product-c1-runThese_Xcomp_3, \ ${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \ ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp, \ - ${jprt.my.linux.i586}-fastdebug-c2-runThese_Xcomp_2, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_default, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_SerialGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ + ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_default, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_SerialGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParallelGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParNewGC, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_CMS, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_G1, \ + ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_default, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_G1, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParOldGC jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \ @@ -230,15 +229,19 @@ jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_G1, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParOldGC jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ @@ -251,16 +254,20 @@ jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParallelGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParNewGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_CMS, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_G1, \ + ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-GCBasher_ParOldGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_default, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_SerialGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParallelGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParNewGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_CMS, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_G1, \ + ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \ - ${jprt.my.windows.i586}-product-{c1|c2}-scimark_2, \ - ${jprt.my.windows.i586}-product-{c1|c2}-scimark_3 + ${jprt.my.windows.i586}-product-{c1|c2}-jbb_G1, \ + ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParOldGC jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \ @@ -272,16 +279,20 @@ jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_G1, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParallelGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParNewGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_CMS, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_G1, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \ ${jprt.my.windows.x64}-product-c2-jbb_CMS, \ ${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark_2, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark_3 + ${jprt.my.windows.x64}-product-c2-jbb_G1, \ + ${jprt.my.windows.x64}-product-c2-jbb_ParOldGC # The complete list of test targets for jprt From de67e5294982ce197f2abd051cbb1c8aa6c29499 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Fri, 13 Mar 2009 11:35:17 -0700 Subject: [PATCH 04/43] 6378821: bitCount() should use POPC on SPARC processors and AMD+10h BitCount() should use POPC on SPARC processors where POPC is implemented directly in hardware. Reviewed-by: kvn, never --- hotspot/src/cpu/sparc/vm/sparc.ad | 27 +++++++ hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 10 ++- hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp | 11 ++- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 38 +++++++++ hotspot/src/cpu/x86/vm/assembler_x86.hpp | 8 ++ hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 10 ++- hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 10 ++- hotspot/src/cpu/x86/vm/x86_32.ad | 77 +++++++++++++++++-- hotspot/src/cpu/x86/vm/x86_64.ad | 50 ++++++++++++ .../vm/vm_version_solaris_sparc.cpp | 1 + hotspot/src/share/vm/classfile/vmSymbols.hpp | 11 ++- hotspot/src/share/vm/opto/classes.hpp | 2 + hotspot/src/share/vm/opto/connode.hpp | 22 +++++- hotspot/src/share/vm/opto/library_call.cpp | 33 +++++++- hotspot/src/share/vm/runtime/globals.hpp | 5 +- .../test/compiler/6378821/Test6378821.java | 75 ++++++++++++++++++ 16 files changed, 370 insertions(+), 20 deletions(-) create mode 100644 hotspot/test/compiler/6378821/Test6378821.java diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 03c79b5a294..df6e9049ebb 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -9015,6 +9015,33 @@ instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, note ins_pipe(long_memory_op); %} + +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(iRegI dst, iRegI src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + format %{ "POPC $src, $dst" %} + ins_encode %{ + __ popc($src$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(iRegI dst, iRegL src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + + format %{ "POPC $src, $dst" %} + ins_encode %{ + __ popc($src$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + + // ============================================================================ //------------Bytes reverse-------------------------------------------------- diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 96d399fc6d7..dc7f6b5bdbe 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -92,10 +92,18 @@ void VM_Version::initialize() { #endif } + // Use hardware population count instruction if available. + if (has_hardware_popc()) { + if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { + UsePopCountInstruction = true; + } + } + char buf[512]; - jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s", (has_v8() ? ", has_v8" : ""), (has_v9() ? ", has_v9" : ""), + (has_hardware_popc() ? ", popc" : ""), (has_vis1() ? ", has_vis1" : ""), (has_vis2() ? ", has_vis2" : ""), (is_ultra3() ? ", is_ultra3" : ""), diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index 92133fa9bfe..e057c608ce8 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -29,10 +29,11 @@ protected: hardware_mul32 = 1, hardware_div32 = 2, hardware_fsmuld = 3, - v9_instructions = 4, - vis1_instructions = 5, - vis2_instructions = 6, - sun4v_instructions = 7 + hardware_popc = 4, + v9_instructions = 5, + vis1_instructions = 6, + vis2_instructions = 7, + sun4v_instructions = 8 }; enum Feature_Flag_Set { @@ -43,6 +44,7 @@ protected: hardware_mul32_m = 1 << hardware_mul32, hardware_div32_m = 1 << hardware_div32, hardware_fsmuld_m = 1 << hardware_fsmuld, + hardware_popc_m = 1 << hardware_popc, v9_instructions_m = 1 << v9_instructions, vis1_instructions_m = 1 << vis1_instructions, vis2_instructions_m = 1 << vis2_instructions, @@ -81,6 +83,7 @@ public: static bool has_hardware_mul32() { return (_features & hardware_mul32_m) != 0; } static bool has_hardware_div32() { return (_features & hardware_div32_m) != 0; } static bool has_hardware_fsmuld() { return (_features & hardware_fsmuld_m) != 0; } + static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; } static bool has_vis1() { return (_features & vis1_instructions_m) != 0; } static bool has_vis2() { return (_features & vis2_instructions_m) != 0; } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 4bae526f395..dcb9585f1ef 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -2193,6 +2193,25 @@ void Assembler::pop(Register dst) { emit_byte(0x58 | encode); } +void Assembler::popcntl(Register dst, Address src) { + assert(VM_Version::supports_popcnt(), "must support"); + InstructionMark im(this); + emit_byte(0xF3); + prefix(src, dst); + emit_byte(0x0F); + emit_byte(0xB8); + emit_operand(dst, src); +} + +void Assembler::popcntl(Register dst, Register src) { + assert(VM_Version::supports_popcnt(), "must support"); + emit_byte(0xF3); + int encode = prefix_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xB8); + emit_byte(0xC0 | encode); +} + void Assembler::popf() { emit_byte(0x9D); } @@ -4080,6 +4099,25 @@ void Assembler::popa() { // 64bit addq(rsp, 16 * wordSize); } +void Assembler::popcntq(Register dst, Address src) { + assert(VM_Version::supports_popcnt(), "must support"); + InstructionMark im(this); + emit_byte(0xF3); + prefixq(src, dst); + emit_byte(0x0F); + emit_byte(0xB8); + emit_operand(dst, src); +} + +void Assembler::popcntq(Register dst, Register src) { + assert(VM_Version::supports_popcnt(), "must support"); + emit_byte(0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_byte(0x0F); + emit_byte(0xB8); + emit_byte(0xC0 | encode); +} + void Assembler::popq(Address dst) { InstructionMark im(this); prefixq(dst); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 76b4559527a..f369d4760fb 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1224,6 +1224,14 @@ private: void popq(Address dst); #endif + void popcntl(Register dst, Address src); + void popcntl(Register dst, Register src); + +#ifdef _LP64 + void popcntq(Register dst, Address src); + void popcntq(Register dst, Register src); +#endif + // Prefetches (SSE, SSE2, 3DNOW only) void prefetchnta(Address src); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index cf112067fe4..1307dd1e54f 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -284,7 +284,7 @@ void VM_Version::get_processor_features() { } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -297,6 +297,7 @@ void VM_Version::get_processor_features() { (supports_ssse3()? ", ssse3": ""), (supports_sse4_1() ? ", sse4.1" : ""), (supports_sse4_2() ? ", sse4.2" : ""), + (supports_popcnt() ? ", popcnt" : ""), (supports_mmx_ext() ? ", mmxext" : ""), (supports_3dnow() ? ", 3dnow" : ""), (supports_3dnow2() ? ", 3dnowext" : ""), @@ -410,6 +411,13 @@ void VM_Version::get_processor_features() { } } + // Use population count instruction if available. + if (supports_popcnt()) { + if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { + UsePopCountInstruction = true; + } + } + assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value"); assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index bf876fc92a6..7b6206b0e32 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -70,7 +70,9 @@ public: dca : 1, sse4_1 : 1, sse4_2 : 1, - : 11; + : 2, + popcnt : 1, + : 8; } bits; }; @@ -179,7 +181,8 @@ protected: CPU_SSSE3 = (1 << 9), CPU_SSE4A = (1 << 10), CPU_SSE4_1 = (1 << 11), - CPU_SSE4_2 = (1 << 12) + CPU_SSE4_2 = (1 << 12), + CPU_POPCNT = (1 << 13) } cpuFeatureFlags; // cpuid information block. All info derived from executing cpuid with @@ -290,6 +293,8 @@ protected: result |= CPU_SSE4_1; if (_cpuid_info.std_cpuid1_ecx.bits.sse4_2 != 0) result |= CPU_SSE4_2; + if (_cpuid_info.std_cpuid1_ecx.bits.popcnt != 0) + result |= CPU_POPCNT; return result; } @@ -379,6 +384,7 @@ public: static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; } static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; } static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; } + static bool supports_popcnt() { return (_cpuFeatures & CPU_POPCNT) != 0; } // // AMD features // diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 1e770159226..9f09138bc55 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1483,16 +1483,20 @@ encode %{ // main source block for now. In future, we can generalize this by // adding a syntax that specifies the sizes of fields in an order, // so that the adlc can build the emit functions automagically - enc_class OpcP %{ // Emit opcode - emit_opcode(cbuf,$primary); + + // Emit primary opcode + enc_class OpcP %{ + emit_opcode(cbuf, $primary); %} - enc_class OpcS %{ // Emit opcode - emit_opcode(cbuf,$secondary); + // Emit secondary opcode + enc_class OpcS %{ + emit_opcode(cbuf, $secondary); %} - enc_class Opcode(immI d8 ) %{ // Emit opcode - emit_opcode(cbuf,$d8$$constant); + // Emit opcode directly + enc_class Opcode(immI d8) %{ + emit_opcode(cbuf, $d8$$constant); %} enc_class SizePrefix %{ @@ -6387,6 +6391,67 @@ instruct bytes_reverse_long(eRegL dst) %{ %} +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(eRegI dst, eRegI src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + format %{ "POPCNT $dst, $src" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct popCountI_mem(eRegI dst, memory mem) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI (LoadI mem))); + + format %{ "POPCNT $dst, $mem" %} + ins_encode %{ + __ popcntl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(eRegI dst, eRegL src, eRegI tmp, eFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + effect(KILL cr, TEMP tmp, TEMP dst); + + format %{ "POPCNT $dst, $src.lo\n\t" + "POPCNT $tmp, $src.hi\n\t" + "ADD $dst, $tmp" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + __ popcntl($tmp$$Register, HIGH_FROM_LOW($src$$Register)); + __ addl($dst$$Register, $tmp$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL_mem(eRegI dst, memory mem, eRegI tmp, eFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL (LoadL mem))); + effect(KILL cr, TEMP tmp, TEMP dst); + + format %{ "POPCNT $dst, $mem\n\t" + "POPCNT $tmp, $mem+4\n\t" + "ADD $dst, $tmp" %} + ins_encode %{ + //__ popcntl($dst$$Register, $mem$$Address$$first); + //__ popcntl($tmp$$Register, $mem$$Address$$second); + __ popcntl($dst$$Register, Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, false)); + __ popcntl($tmp$$Register, Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, false)); + __ addl($dst$$Register, $tmp$$Register); + %} + ins_pipe(ialu_reg); +%} + + //----------Load/Store/Move Instructions--------------------------------------- //----------Load Instructions-------------------------------------------------- // Load Byte (8bit signed) diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 163c87ca18c..5872d2b6d4a 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -7429,6 +7429,56 @@ instruct storeL_reversed(memory dst, rRegL src) %{ ins_pipe( ialu_mem_reg ); %} + +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(rRegI dst, rRegI src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + format %{ "popcnt $dst, $src" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct popCountI_mem(rRegI dst, memory mem) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI (LoadI mem))); + + format %{ "popcnt $dst, $mem" %} + ins_encode %{ + __ popcntl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(rRegI dst, rRegL src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + + format %{ "popcnt $dst, $src" %} + ins_encode %{ + __ popcntq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL_mem(rRegI dst, memory mem) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL (LoadL mem))); + + format %{ "popcnt $dst, $mem" %} + ins_encode %{ + __ popcntq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + + //----------MemBar Instructions----------------------------------------------- // Memory barrier flavors diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index d2c5baa5fd3..ec537c7fe54 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -85,6 +85,7 @@ int VM_Version::platform_features(int features) { if (av & AV_SPARC_DIV32) features |= hardware_div32_m; if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; + if (av & AV_SPARC_POPC) features |= hardware_popc_m; if (av & AV_SPARC_VIS) features |= vis1_instructions_m; if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; } else { diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 8379af9c414..b9c17c2e2d2 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -284,6 +284,7 @@ template(value_name, "value") \ template(frontCacheEnabled_name, "frontCacheEnabled") \ template(stringCacheEnabled_name, "stringCacheEnabled") \ + template(bitCount_name, "bitCount") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -304,6 +305,7 @@ template(double_long_signature, "(D)J") \ template(double_double_signature, "(D)D") \ template(int_float_signature, "(I)F") \ + template(long_int_signature, "(J)I") \ template(long_long_signature, "(J)J") \ template(long_double_signature, "(J)D") \ template(byte_signature, "B") \ @@ -507,6 +509,10 @@ do_name( doubleToLongBits_name, "doubleToLongBits") \ do_intrinsic(_longBitsToDouble, java_lang_Double, longBitsToDouble_name, long_double_signature, F_S) \ do_name( longBitsToDouble_name, "longBitsToDouble") \ + \ + do_intrinsic(_bitCount_i, java_lang_Integer, bitCount_name, int_int_signature, F_S) \ + do_intrinsic(_bitCount_l, java_lang_Long, bitCount_name, long_int_signature, F_S) \ + \ do_intrinsic(_reverseBytes_i, java_lang_Integer, reverseBytes_name, int_int_signature, F_S) \ do_name( reverseBytes_name, "reverseBytes") \ do_intrinsic(_reverseBytes_l, java_lang_Long, reverseBytes_name, long_long_signature, F_S) \ @@ -696,7 +702,6 @@ do_signature(putShort_raw_signature, "(JS)V") \ do_signature(getChar_raw_signature, "(J)C") \ do_signature(putChar_raw_signature, "(JC)V") \ - do_signature(getInt_raw_signature, "(J)I") \ do_signature(putInt_raw_signature, "(JI)V") \ do_alias(getLong_raw_signature, /*(J)J*/ long_long_signature) \ do_alias(putLong_raw_signature, /*(JJ)V*/ long_long_void_signature) \ @@ -713,7 +718,7 @@ do_intrinsic(_getByte_raw, sun_misc_Unsafe, getByte_name, getByte_raw_signature, F_RN) \ do_intrinsic(_getShort_raw, sun_misc_Unsafe, getShort_name, getShort_raw_signature, F_RN) \ do_intrinsic(_getChar_raw, sun_misc_Unsafe, getChar_name, getChar_raw_signature, F_RN) \ - do_intrinsic(_getInt_raw, sun_misc_Unsafe, getInt_name, getInt_raw_signature, F_RN) \ + do_intrinsic(_getInt_raw, sun_misc_Unsafe, getInt_name, long_int_signature, F_RN) \ do_intrinsic(_getLong_raw, sun_misc_Unsafe, getLong_name, getLong_raw_signature, F_RN) \ do_intrinsic(_getFloat_raw, sun_misc_Unsafe, getFloat_name, getFloat_raw_signature, F_RN) \ do_intrinsic(_getDouble_raw, sun_misc_Unsafe, getDouble_name, getDouble_raw_signature, F_RN) \ diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index d527f5ea475..87adb737cb7 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -184,6 +184,8 @@ macro(PCTable) macro(Parm) macro(PartialSubtypeCheck) macro(Phi) +macro(PopCountI) +macro(PopCountL) macro(PowD) macro(PrefetchRead) macro(PrefetchWrite) diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp index a16d7f2ee84..4c078d1b091 100644 --- a/hotspot/src/share/vm/opto/connode.hpp +++ b/hotspot/src/share/vm/opto/connode.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -635,3 +635,23 @@ class MoveD2LNode : public Node { virtual uint ideal_reg() const { return Op_RegL; } virtual const Type* Value( PhaseTransform *phase ) const; }; + +//---------- PopCountINode ----------------------------------------------------- +// Population count (bit count) of an integer. +class PopCountINode : public Node { +public: + PopCountINode(Node* in1) : Node(0, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//---------- PopCountLNode ----------------------------------------------------- +// Population count (bit count) of a long. +class PopCountLNode : public Node { +public: + PopCountLNode(Node* in1) : Node(0, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 6cbcee84b51..b5b7136a375 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 @@ -221,6 +221,7 @@ class LibraryCallKit : public GraphKit { bool inline_unsafe_CAS(BasicType type); bool inline_unsafe_ordered_store(BasicType type); bool inline_fp_conversions(vmIntrinsics::ID id); + bool inline_bitCount(vmIntrinsics::ID id); bool inline_reverseBytes(vmIntrinsics::ID id); }; @@ -314,6 +315,11 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { if (!JDK_Version::is_gte_jdk14x_version()) return NULL; break; + case vmIntrinsics::_bitCount_i: + case vmIntrinsics::_bitCount_l: + if (!UsePopCountInstruction) return NULL; + break; + default: break; } @@ -617,6 +623,10 @@ bool LibraryCallKit::try_to_inline() { case vmIntrinsics::_longBitsToDouble: return inline_fp_conversions(intrinsic_id()); + case vmIntrinsics::_bitCount_i: + case vmIntrinsics::_bitCount_l: + return inline_bitCount(intrinsic_id()); + case vmIntrinsics::_reverseBytes_i: case vmIntrinsics::_reverseBytes_l: return inline_reverseBytes((vmIntrinsics::ID) intrinsic_id()); @@ -1714,6 +1724,27 @@ inline Node* LibraryCallKit::make_unsafe_address(Node* base, Node* offset) { } } +//----------------------------inline_bitCount_int/long----------------------- +// inline int Integer.bitCount(int) +// inline int Long.bitCount(long) +bool LibraryCallKit::inline_bitCount(vmIntrinsics::ID id) { + assert(id == vmIntrinsics::_bitCount_i || id == vmIntrinsics::_bitCount_l, "not bitCount"); + if (id == vmIntrinsics::_bitCount_i && !Matcher::has_match_rule(Op_PopCountI)) return false; + if (id == vmIntrinsics::_bitCount_l && !Matcher::has_match_rule(Op_PopCountL)) return false; + _sp += arg_size(); // restore stack pointer + switch (id) { + case vmIntrinsics::_bitCount_i: + push(_gvn.transform(new (C, 2) PopCountINode(pop()))); + break; + case vmIntrinsics::_bitCount_l: + push(_gvn.transform(new (C, 2) PopCountLNode(pop_pair()))); + break; + default: + ShouldNotReachHere(); + } + return true; +} + //----------------------------inline_reverseBytes_int/long------------------- // inline Integer.reverseBytes(int) // inline Long.reverseBytes(long) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 9855d5b8e5b..2d33287fcd4 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -2172,6 +2172,9 @@ class CommandLineFlags { diagnostic(bool, PrintIntrinsics, false, \ "prints attempted and successful inlining of intrinsics") \ \ + product(bool, UsePopCountInstruction, false, \ + "Use population count instruction") \ + \ diagnostic(ccstrlist, DisableIntrinsic, "", \ "do not expand intrinsics whose (internal) names appear here") \ \ diff --git a/hotspot/test/compiler/6378821/Test6378821.java b/hotspot/test/compiler/6378821/Test6378821.java new file mode 100644 index 00000000000..83c52decb41 --- /dev/null +++ b/hotspot/test/compiler/6378821/Test6378821.java @@ -0,0 +1,75 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6378821 + * @summary where available, bitCount() should use POPC on SPARC processors and AMD+10h + * + * @run main/othervm -Xcomp -XX:CompileOnly=Test6378821.fcomp Test6378821 + */ + +public class Test6378821 { + static final int[] ia = new int[] { 0x12345678 }; + static final long[] la = new long[] { 0x12345678abcdefL }; + + public static void main(String [] args) { + // Resolve the class and the method. + Integer.bitCount(1); + Long.bitCount(1); + + sub(ia[0]); + sub(la[0]); + sub(ia); + sub(la); + } + + static void check(int i, int expected, int result) { + if (result != expected) { + throw new InternalError("Wrong population count for " + i + ": " + result + " != " + expected); + } + } + + static void check(long l, int expected, int result) { + if (result != expected) { + throw new InternalError("Wrong population count for " + l + ": " + result + " != " + expected); + } + } + + static void sub(int i) { check(i, fint(i), fcomp(i) ); } + static void sub(int[] ia) { check(ia[0], fint(ia), fcomp(ia)); } + static void sub(long l) { check(l, fint(l), fcomp(l) ); } + static void sub(long[] la) { check(la[0], fint(la), fcomp(la)); } + + static int fint (int i) { return Integer.bitCount(i); } + static int fcomp(int i) { return Integer.bitCount(i); } + + static int fint (int[] ia) { return Integer.bitCount(ia[0]); } + static int fcomp(int[] ia) { return Integer.bitCount(ia[0]); } + + static int fint (long l) { return Long.bitCount(l); } + static int fcomp(long l) { return Long.bitCount(l); } + + static int fint (long[] la) { return Long.bitCount(la[0]); } + static int fcomp(long[] la) { return Long.bitCount(la[0]); } +} From a45005f646750c91148f02a7aa677bb51aee5cc0 Mon Sep 17 00:00:00 2001 From: "Y. Srinivas Ramakrishna" Date: Fri, 13 Mar 2009 13:56:01 -0700 Subject: [PATCH 05/43] 6808322: ParNew, CMS, G1: ParGCAllocBuffer overflow Correct the overflow check in ParGCAllocBuffer::allocate(); simplify ParGCAllocBuffer::undo_allocation(). Reviewed-by: apetrusenko, jcoomes, jmasa, minqi, phh, tonyp --- .../vm/gc_implementation/parNew/parGCAllocBuffer.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp index 89331a81bd3..dddb3bb7d3c 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.hpp @@ -63,9 +63,8 @@ public: // return NULL. HeapWord* allocate(size_t word_sz) { HeapWord* res = _top; - HeapWord* new_top = _top + word_sz; - if (new_top <= _end) { - _top = new_top; + if (pointer_delta(_end, _top) >= word_sz) { + _top = _top + word_sz; return res; } else { return NULL; @@ -75,10 +74,9 @@ public: // Undo the last allocation in the buffer, which is required to be of the // "obj" of the given "word_sz". void undo_allocation(HeapWord* obj, size_t word_sz) { - assert(_top - word_sz >= _bottom - && _top - word_sz == obj, - "Bad undo_allocation"); - _top = _top - word_sz; + assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); + assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); + _top = obj; } // The total (word) size of the buffer, including both allocated and From b8dbe8d8f650124b61a4ce8b70286b5b444a3316 Mon Sep 17 00:00:00 2001 From: John R Rose Date: Fri, 13 Mar 2009 18:39:22 -0700 Subject: [PATCH 06/43] 6813212: factor duplicated assembly code for general subclass check (for 6655638) Code in interp_masm, stubGenerator, c1_LIRAssembler, and AD files moved into MacroAssembler. Reviewed-by: kvn --- hotspot/src/cpu/sparc/vm/assembler_sparc.cpp | 262 ++++++++++++++++++ hotspot/src/cpu/sparc/vm/assembler_sparc.hpp | 40 +++ .../cpu/sparc/vm/c1_LIRAssembler_sparc.cpp | 144 +++------- .../src/cpu/sparc/vm/c1_Runtime1_sparc.cpp | 27 +- .../src/cpu/sparc/vm/interp_masm_sparc.cpp | 61 +--- .../src/cpu/sparc/vm/stubGenerator_sparc.cpp | 137 ++------- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 219 +++++++++++++++ hotspot/src/cpu/x86/vm/assembler_x86.hpp | 34 +++ .../src/cpu/x86/vm/c1_LIRAssembler_x86.cpp | 49 +--- hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp | 33 ++- hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp | 43 +-- hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp | 60 +--- .../src/cpu/x86/vm/stubGenerator_x86_32.cpp | 74 ++--- .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 63 +---- hotspot/src/cpu/x86/vm/x86_32.ad | 34 +-- hotspot/src/cpu/x86/vm/x86_64.ad | 49 +--- hotspot/src/share/vm/opto/graphKit.cpp | 22 +- 17 files changed, 734 insertions(+), 617 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp index f31d9765ae7..4a61d2f2c5d 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp @@ -2767,6 +2767,268 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, } +void MacroAssembler::check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label& L_success) { + Label L_failure, L_pop_to_failure; + check_klass_subtype_fast_path(sub_klass, super_klass, + temp_reg, temp2_reg, + &L_success, &L_failure, NULL); + Register sub_2 = sub_klass; + Register sup_2 = super_klass; + if (!sub_2->is_global()) sub_2 = L0; + if (!sup_2->is_global()) sup_2 = L1; + + save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2); + check_klass_subtype_slow_path(sub_2, sup_2, + L2, L3, L4, L5, + NULL, &L_pop_to_failure); + + // on success: + restore(); + ba(false, L_success); + delayed()->nop(); + + // on failure: + bind(L_pop_to_failure); + restore(); + bind(L_failure); +} + + +void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterConstant super_check_offset, + Register instanceof_hack) { + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + int sco_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::super_check_offset_offset_in_bytes()); + + bool must_load_sco = (super_check_offset.constant_or_zero() == -1); + bool need_slow_path = (must_load_sco || + super_check_offset.constant_or_zero() == sco_offset); + + assert_different_registers(sub_klass, super_klass, temp_reg); + if (super_check_offset.is_register()) { + assert_different_registers(sub_klass, super_klass, + super_check_offset.as_register()); + } else if (must_load_sco) { + assert(temp2_reg != noreg, "supply either a temp or a register offset"); + } + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1 || instanceof_hack != noreg || + (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path), + "at most one NULL in the batch, usually"); + + // Support for the instanceof hack, which uses delay slots to + // set a destination register to zero or one. + bool do_bool_sets = (instanceof_hack != noreg); +#define BOOL_SET(bool_value) \ + if (do_bool_sets && bool_value >= 0) \ + set(bool_value, instanceof_hack) +#define DELAYED_BOOL_SET(bool_value) \ + if (do_bool_sets && bool_value >= 0) \ + delayed()->set(bool_value, instanceof_hack); \ + else delayed()->nop() + // Hacked ba(), which may only be used just before L_fallthrough. +#define FINAL_JUMP(label, bool_value) \ + if (&(label) == &L_fallthrough) { \ + BOOL_SET(bool_value); \ + } else { \ + ba((do_bool_sets && bool_value >= 0), label); \ + DELAYED_BOOL_SET(bool_value); \ + } + + // If the pointers are equal, we are done (e.g., String[] elements). + // This self-check enables sharing of secondary supertype arrays among + // non-primary types such as array-of-interface. Otherwise, each such + // type would need its own customized SSA. + // We move this check to the front of the fast path because many + // type checks are in fact trivially successful in this manner, + // so we get a nicely predicted branch right at the start of the check. + cmp(super_klass, sub_klass); + brx(Assembler::equal, do_bool_sets, Assembler::pn, *L_success); + DELAYED_BOOL_SET(1); + + // Check the supertype display: + if (must_load_sco) { + // The super check offset is always positive... + lduw(super_klass, sco_offset, temp2_reg); + super_check_offset = RegisterConstant(temp2_reg); + } + ld_ptr(sub_klass, super_check_offset, temp_reg); + cmp(super_klass, temp_reg); + + // This check has worked decisively for primary supers. + // Secondary supers are sought in the super_cache ('super_cache_addr'). + // (Secondary supers are interfaces and very deeply nested subtypes.) + // This works in the same check above because of a tricky aliasing + // between the super_cache and the primary super display elements. + // (The 'super_check_addr' can address either, as the case requires.) + // Note that the cache is updated below if it does not help us find + // what we need immediately. + // So if it was a primary super, we can just fail immediately. + // Otherwise, it's the slow path for us (no success at this point). + + if (super_check_offset.is_register()) { + brx(Assembler::equal, do_bool_sets, Assembler::pn, *L_success); + delayed(); if (do_bool_sets) BOOL_SET(1); + // if !do_bool_sets, sneak the next cmp into the delay slot: + cmp(super_check_offset.as_register(), sc_offset); + + if (L_failure == &L_fallthrough) { + brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_slow_path); + delayed()->nop(); + BOOL_SET(0); // fallthrough on failure + } else { + brx(Assembler::notEqual, do_bool_sets, Assembler::pn, *L_failure); + DELAYED_BOOL_SET(0); + FINAL_JUMP(*L_slow_path, -1); // -1 => vanilla delay slot + } + } else if (super_check_offset.as_constant() == sc_offset) { + // Need a slow path; fast failure is impossible. + if (L_slow_path == &L_fallthrough) { + brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_success); + DELAYED_BOOL_SET(1); + } else { + brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path); + delayed()->nop(); + FINAL_JUMP(*L_success, 1); + } + } else { + // No slow path; it's a fast decision. + if (L_failure == &L_fallthrough) { + brx(Assembler::equal, do_bool_sets, Assembler::pt, *L_success); + DELAYED_BOOL_SET(1); + BOOL_SET(0); + } else { + brx(Assembler::notEqual, do_bool_sets, Assembler::pn, *L_failure); + DELAYED_BOOL_SET(0); + FINAL_JUMP(*L_success, 1); + } + } + + bind(L_fallthrough); + +#undef final_jump +#undef bool_set +#undef DELAYED_BOOL_SET +#undef final_jump +} + + +void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register count_temp, + Register scan_temp, + Register scratch_reg, + Register coop_reg, + Label* L_success, + Label* L_failure) { + assert_different_registers(sub_klass, super_klass, + count_temp, scan_temp, scratch_reg, coop_reg); + + Label L_fallthrough, L_loop; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in the batch"); + + // a couple of useful fields in sub_klass: + int ss_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_supers_offset_in_bytes()); + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + + // Do a linear scan of the secondary super-klass chain. + // This code is rarely used, so simplicity is a virtue here. + +#ifndef PRODUCT + int* pst_counter = &SharedRuntime::_partial_subtype_ctr; + inc_counter((address) pst_counter, count_temp, scan_temp); +#endif + + // We will consult the secondary-super array. + ld_ptr(sub_klass, ss_offset, scan_temp); + + // Compress superclass if necessary. + Register search_key = super_klass; + bool decode_super_klass = false; + if (UseCompressedOops) { + if (coop_reg != noreg) { + encode_heap_oop_not_null(super_klass, coop_reg); + search_key = coop_reg; + } else { + encode_heap_oop_not_null(super_klass); + decode_super_klass = true; // scarce temps! + } + // The superclass is never null; it would be a basic system error if a null + // pointer were to sneak in here. Note that we have already loaded the + // Klass::super_check_offset from the super_klass in the fast path, + // so if there is a null in that register, we are already in the afterlife. + } + + // Load the array length. (Positive movl does right thing on LP64.) + lduw(scan_temp, arrayOopDesc::length_offset_in_bytes(), count_temp); + + // Check for empty secondary super list + tst(count_temp); + + // Top of search loop + bind(L_loop); + br(Assembler::equal, false, Assembler::pn, *L_failure); + delayed()->add(scan_temp, heapOopSize, scan_temp); + assert(heapOopSize != 0, "heapOopSize should be initialized"); + + // Skip the array header in all array accesses. + int elem_offset = arrayOopDesc::base_offset_in_bytes(T_OBJECT); + elem_offset -= heapOopSize; // the scan pointer was pre-incremented also + + // Load next super to check + if (UseCompressedOops) { + // Don't use load_heap_oop; we don't want to decode the element. + lduw( scan_temp, elem_offset, scratch_reg ); + } else { + ld_ptr( scan_temp, elem_offset, scratch_reg ); + } + + // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list + cmp(scratch_reg, search_key); + + // A miss means we are NOT a subtype and need to keep looping + brx(Assembler::notEqual, false, Assembler::pn, L_loop); + delayed()->deccc(count_temp); // decrement trip counter in delay slot + + // Falling out the bottom means we found a hit; we ARE a subtype + if (decode_super_klass) decode_heap_oop(super_klass); + + // Success. Cache the super we found and proceed in triumph. + st_ptr(super_klass, sub_klass, sc_offset); + + if (L_success != &L_fallthrough) { + ba(false, *L_success); + delayed()->nop(); + } + + bind(L_fallthrough); +} + + + + void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg, Label& done, Label* slow_case, diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index 8f1de780c28..fc05cef68a4 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -2327,6 +2327,46 @@ class MacroAssembler: public Assembler { Register temp_reg, Register temp2_reg, Label& no_such_interface); + // Test sub_klass against super_klass, with fast and slow paths. + + // The fast path produces a tri-state answer: yes / no / maybe-slow. + // One of the three labels can be NULL, meaning take the fall-through. + // If super_check_offset is -1, the value is loaded up from super_klass. + // No registers are killed, except temp_reg and temp2_reg. + // If super_check_offset is not -1, temp2_reg is not used and can be noreg. + void check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterConstant super_check_offset = RegisterConstant(-1), + Register instanceof_hack = noreg); + + // The rest of the type check; must be wired to a corresponding fast path. + // It does not repeat the fast path logic, so don't use it standalone. + // The temp_reg can be noreg, if no temps are available. + // It can also be sub_klass or super_klass, meaning it's OK to kill that one. + // Updates the sub's secondary super cache as necessary. + void check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Register temp3_reg, + Register temp4_reg, + Label* L_success, + Label* L_failure); + + // Simplified, combined version, good for typical uses. + // Falls through on failure. + void check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label& L_success); + + // Stack overflow checking // Note: this clobbers G3_scratch diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index dabea15a087..389acd2ee26 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -2393,23 +2393,11 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { // get instance klass load(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc), k_RInfo, T_OBJECT, NULL); - // get super_check_offset - load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1, T_INT, NULL); - // See if we get an immediate positive hit - __ ld_ptr(klass_RInfo, Rtmp1, FrameMap::O7_oop_opr->as_register()); - __ cmp(k_RInfo, O7); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - // check for immediate negative hit - __ cmp(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - // check for self - __ cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, &done, stub->entry(), NULL); - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ cmp(G3, 0); @@ -2493,58 +2481,30 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ delayed()->nop(); __ bind(done); } else { + bool need_slow_path = true; if (k->is_loaded()) { - load(klass_RInfo, k->super_check_offset(), Rtmp1, T_OBJECT, NULL); - - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { - // See if we get an immediate positive hit - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } else { - // See if we get an immediate positive hit - assert_different_registers(Rtmp1, k_RInfo, klass_RInfo); - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::equal, false, Assembler::pn, done); - // check for self - __ delayed()->cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - __ bind(done); + if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) + need_slow_path = false; + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg, + (need_slow_path ? &done : NULL), + stub->entry(), NULL, + RegisterConstant(k->super_check_offset())); } else { - assert_different_registers(Rtmp1, klass_RInfo, k_RInfo); - - load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1, T_INT, NULL); - // See if we get an immediate positive hit - load(klass_RInfo, Rtmp1, FrameMap::O7_oop_opr, T_OBJECT); - __ cmp(k_RInfo, O7); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - // check for immediate negative hit - __ cmp(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ br(Assembler::notEqual, false, Assembler::pn, *stub->entry()); - // check for self - __ delayed()->cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, false, Assembler::pn, done); - __ delayed()->nop(); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, + &done, stub->entry(), NULL); + } + if (need_slow_path) { + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ cmp(G3, 0); __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); __ delayed()->nop(); - __ bind(done); } - + __ bind(done); } __ mov(obj, dst); } else if (code == lir_instanceof) { @@ -2582,58 +2542,32 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ set(0, dst); __ bind(done); } else { + bool need_slow_path = true; if (k->is_loaded()) { - assert_different_registers(Rtmp1, klass_RInfo, k_RInfo); - load(klass_RInfo, k->super_check_offset(), Rtmp1, T_OBJECT, NULL); - - if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { - // See if we get an immediate positive hit - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - __ set(0, dst); - __ bind(done); - } else { - // See if we get an immediate positive hit - assert_different_registers(Rtmp1, k_RInfo, klass_RInfo); - __ cmp(Rtmp1, k_RInfo ); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - // check for self - __ cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ mov(G3, dst); - __ bind(done); - } + if (k->super_check_offset() != sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()) + need_slow_path = false; + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, noreg, + (need_slow_path ? &done : NULL), + (need_slow_path ? &done : NULL), NULL, + RegisterConstant(k->super_check_offset()), + dst); } else { assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - - load(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), dst, T_INT, NULL); - // See if we get an immediate positive hit - load(klass_RInfo, dst, FrameMap::O7_oop_opr, T_OBJECT); - __ cmp(k_RInfo, O7); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - // check for immediate negative hit - __ cmp(dst, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ br(Assembler::notEqual, true, Assembler::pt, done); - __ delayed()->set(0, dst); - // check for self - __ cmp(klass_RInfo, k_RInfo); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->set(1, dst); - - // assert(sub.is_same(FrameMap::G3_RInfo) && super.is_same(FrameMap::G1_RInfo), "incorrect call setup"); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, dst, + &done, &done, NULL, + RegisterConstant(-1), + dst); + } + if (need_slow_path) { + // call out-of-line instance of __ check_klass_subtype_slow_path(...): + assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); __ delayed()->nop(); __ mov(G3, dst); - __ bind(done); } + __ bind(done); } } else { ShouldNotReachHere(); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 489e84dd58c..6dfb8efbc7c 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -714,38 +714,19 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // sub : G3, argument, destroyed // super: G1, argument, not changed // raddr: O7, blown by call - Label loop, miss; + Label miss; __ save_frame(0); // Blow no registers! - __ ld_ptr( G3, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), L3 ); - __ lduw(L3,arrayOopDesc::length_offset_in_bytes(),L0); // length in l0 - __ add(L3,arrayOopDesc::base_offset_in_bytes(T_OBJECT),L1); // ptr into array - __ clr(L4); // Index - // Load a little early; will load 1 off the end of the array. - // Ok for now; revisit if we have other uses of this routine. - __ ld_ptr(L1,0,L2); // Will load a little early - - // The scan loop - __ bind(loop); - __ add(L1,wordSize,L1); // Bump by OOP size - __ cmp(L4,L0); - __ br(Assembler::equal,false,Assembler::pn,miss); - __ delayed()->inc(L4); // Bump index - __ subcc(L2,G1,L3); // Check for match; zero in L3 for a hit - __ brx( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->ld_ptr(L1,0,L2); // Will load a little early - - // Got a hit; report success; set cache - __ st_ptr( G1, G3, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); + __ check_klass_subtype_slow_path(G3, G1, L0, L1, L2, L4, NULL, &miss); __ mov(1, G3); - __ ret(); // Result in G5 is ok; flags set + __ ret(); // Result in G5 is 'true' __ delayed()->restore(); // free copy or add can go here __ bind(miss); __ mov(0, G3); - __ ret(); // Result in G5 is ok; flags set + __ ret(); // Result in G5 is 'false' __ delayed()->restore(); // free copy or add can go here } diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index dee9fcc3cd0..e843d3fad8b 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -866,65 +866,18 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rtmp2, Register Rtmp3, Label &ok_is_subtype ) { - Label not_subtype, loop; + Label not_subtype; // Profile the not-null value's klass. profile_typecheck(Rsub_klass, Rtmp1); - // Load the super-klass's check offset into Rtmp1 - ld( Rsuper_klass, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes(), Rtmp1 ); - // Load from the sub-klass's super-class display list, or a 1-word cache of - // the secondary superclass list, or a failing value with a sentinel offset - // if the super-klass is an interface or exceptionally deep in the Java - // hierarchy and we have to scan the secondary superclass list the hard way. - ld_ptr( Rsub_klass, Rtmp1, Rtmp2 ); - // See if we get an immediate positive hit - cmp( Rtmp2, Rsuper_klass ); - brx( Assembler::equal, false, Assembler::pt, ok_is_subtype ); - // In the delay slot, check for immediate negative hit - delayed()->cmp( Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); - br( Assembler::notEqual, false, Assembler::pt, not_subtype ); - // In the delay slot, check for self - delayed()->cmp( Rsub_klass, Rsuper_klass ); - brx( Assembler::equal, false, Assembler::pt, ok_is_subtype ); + check_klass_subtype_fast_path(Rsub_klass, Rsuper_klass, + Rtmp1, Rtmp2, + &ok_is_subtype, ¬_subtype, NULL); - // Now do a linear scan of the secondary super-klass chain. - delayed()->ld_ptr( Rsub_klass, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), Rtmp2 ); - - // compress superclass - if (UseCompressedOops) encode_heap_oop(Rsuper_klass); - - // Rtmp2 holds the objArrayOop of secondary supers. - ld( Rtmp2, arrayOopDesc::length_offset_in_bytes(), Rtmp1 );// Load the array length - // Check for empty secondary super list - tst(Rtmp1); - - // Top of search loop - bind( loop ); - br( Assembler::equal, false, Assembler::pn, not_subtype ); - delayed()->nop(); - - // load next super to check - if (UseCompressedOops) { - lduw( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3); - // Bump array pointer forward one oop - add( Rtmp2, 4, Rtmp2 ); - } else { - ld_ptr( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3); - // Bump array pointer forward one oop - add( Rtmp2, wordSize, Rtmp2); - } - // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list - cmp( Rtmp3, Rsuper_klass ); - // A miss means we are NOT a subtype and need to keep looping - brx( Assembler::notEqual, false, Assembler::pt, loop ); - delayed()->deccc( Rtmp1 ); // dec trip counter in delay slot - // Falling out the bottom means we found a hit; we ARE a subtype - if (UseCompressedOops) decode_heap_oop(Rsuper_klass); - br( Assembler::always, false, Assembler::pt, ok_is_subtype ); - // Update the cache - delayed()->st_ptr( Rsuper_klass, Rsub_klass, - sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); + check_klass_subtype_slow_path(Rsub_klass, Rsuper_klass, + Rtmp1, Rtmp2, Rtmp3, /*hack:*/ noreg, + &ok_is_subtype, NULL); bind(not_subtype); profile_typecheck_failed(Rtmp1); diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index 5ef4f23ab13..e4a3806da86 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -900,19 +900,7 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", "partial_subtype_check"); address start = __ pc(); - Label loop, miss; - - // Compare super with sub directly, since super is not in its own SSA. - // The compiler used to emit this test, but we fold it in here, - // to increase overall code density, with no real loss of speed. - { Label L; - __ cmp(O1, O2); - __ brx(Assembler::notEqual, false, Assembler::pt, L); - __ delayed()->nop(); - __ retl(); - __ delayed()->addcc(G0,0,O0); // set Z flags, zero result - __ bind(L); - } + Label miss; #if defined(COMPILER2) && !defined(_LP64) // Do not use a 'save' because it blows the 64-bit O registers. @@ -936,56 +924,12 @@ class StubGenerator: public StubCodeGenerator { Register L2_super = L2; Register L3_index = L3; -#ifdef _LP64 - Register L4_ooptmp = L4; + __ check_klass_subtype_slow_path(Rsub, Rsuper, + L0, L1, L2, L3, + NULL, &miss); - if (UseCompressedOops) { - // this must be under UseCompressedOops check, as we rely upon fact - // that L4 not clobbered in C2 on 32-bit platforms, where we do explicit save - // on stack, see several lines above - __ encode_heap_oop(Rsuper, L4_ooptmp); - } -#endif - - inc_counter_np(SharedRuntime::_partial_subtype_ctr, L0, L1); - - __ ld_ptr( Rsub, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes(), L3 ); - __ lduw(L3,arrayOopDesc::length_offset_in_bytes(),L0_ary_len); - __ add(L3,arrayOopDesc::base_offset_in_bytes(T_OBJECT),L1_ary_ptr); - __ clr(L3_index); // zero index - // Load a little early; will load 1 off the end of the array. - // Ok for now; revisit if we have other uses of this routine. - if (UseCompressedOops) { - __ lduw(L1_ary_ptr,0,L2_super);// Will load a little early - } else { - __ ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early - } - - assert(heapOopSize != 0, "heapOopSize should be initialized"); - // The scan loop - __ BIND(loop); - __ add(L1_ary_ptr, heapOopSize, L1_ary_ptr); // Bump by OOP size - __ cmp(L3_index,L0_ary_len); - __ br(Assembler::equal,false,Assembler::pn,miss); - __ delayed()->inc(L3_index); // Bump index - - if (UseCompressedOops) { -#ifdef _LP64 - __ subcc(L2_super,L4_ooptmp,Rret); // Check for match; zero in Rret for a hit - __ br( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->lduw(L1_ary_ptr,0,L2_super);// Will load a little early -#else - ShouldNotReachHere(); -#endif - } else { - __ subcc(L2_super,Rsuper,Rret); // Check for match; zero in Rret for a hit - __ brx( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early - } - - // Got a hit; report success; set cache. Cache load doesn't - // happen here; for speed it is directly emitted by the compiler. - __ st_ptr( Rsuper, Rsub, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); + // Match falls through here. + __ addcc(G0,0,Rret); // set Z flags, Z result #if defined(COMPILER2) && !defined(_LP64) __ ld_ptr(SP,(frame::register_save_words+0)*wordSize,L0); @@ -999,7 +943,6 @@ class StubGenerator: public StubCodeGenerator { __ delayed()->restore(); #endif - // Hit or miss falls through here __ BIND(miss); __ addcc(G0,1,Rret); // set NZ flags, NZ result @@ -2330,51 +2273,31 @@ class StubGenerator: public StubCodeGenerator { Register super_check_offset, Register super_klass, Register temp, - Label& L_success, - Register deccc_hack = noreg) { + Label& L_success) { assert_different_registers(sub_klass, super_check_offset, super_klass, temp); BLOCK_COMMENT("type_check:"); - Label L_miss; + Label L_miss, L_pop_to_miss; assert_clean_int(super_check_offset, temp); - // maybe decrement caller's trip count: -#define DELAY_SLOT delayed(); \ - { if (deccc_hack == noreg) __ nop(); else __ deccc(deccc_hack); } - - // if the pointers are equal, we are done (e.g., String[] elements) - __ cmp(sub_klass, super_klass); - __ brx(Assembler::equal, true, Assembler::pt, L_success); - __ DELAY_SLOT; - - // check the supertype display: - __ ld_ptr(sub_klass, super_check_offset, temp); // query the super type - __ cmp(super_klass, temp); // test the super type - __ brx(Assembler::equal, true, Assembler::pt, L_success); - __ DELAY_SLOT; - - int sc_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_super_cache_offset_in_bytes()); - __ cmp(super_klass, sc_offset); - __ brx(Assembler::notEqual, true, Assembler::pt, L_miss); - __ delayed()->nop(); + __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, noreg, + &L_success, &L_miss, NULL, + super_check_offset); + BLOCK_COMMENT("type_check_slow_path:"); __ save_frame(0); - __ mov(sub_klass->after_save(), O1); - // mov(super_klass->after_save(), O2); //fill delay slot - assert(StubRoutines::Sparc::_partial_subtype_check != NULL, "order of generation"); - __ call(StubRoutines::Sparc::_partial_subtype_check); - __ delayed()->mov(super_klass->after_save(), O2); + __ check_klass_subtype_slow_path(sub_klass->after_save(), + super_klass->after_save(), + L0, L1, L2, L4, + NULL, &L_pop_to_miss); + __ ba(false, L_success); + __ delayed()->restore(); + + __ bind(L_pop_to_miss); __ restore(); - // Upon return, the condition codes are already set. - __ brx(Assembler::equal, true, Assembler::pt, L_success); - __ DELAY_SLOT; - -#undef DELAY_SLOT - // Fall through on failure! __ BIND(L_miss); } @@ -2411,7 +2334,7 @@ class StubGenerator: public StubCodeGenerator { gen_write_ref_array_pre_barrier(O1, O2); #ifdef ASSERT - // We sometimes save a frame (see partial_subtype_check below). + // We sometimes save a frame (see generate_type_check below). // If this will cause trouble, let's fail now instead of later. __ save_frame(0); __ restore(); @@ -2455,41 +2378,39 @@ class StubGenerator: public StubCodeGenerator { // G3, G4, G5 --- current oop, oop.klass, oop.klass.super __ align(16); - __ bind(store_element); - // deccc(G1_remain); // decrement the count (hoisted) + __ BIND(store_element); + __ deccc(G1_remain); // decrement the count __ store_heap_oop(G3_oop, O1_to, O5_offset); // store the oop __ inc(O5_offset, heapOopSize); // step to next offset __ brx(Assembler::zero, true, Assembler::pt, do_card_marks); __ delayed()->set(0, O0); // return -1 on success // ======== loop entry is here ======== - __ bind(load_element); + __ BIND(load_element); __ load_heap_oop(O0_from, O5_offset, G3_oop); // load the oop __ br_null(G3_oop, true, Assembler::pt, store_element); - __ delayed()->deccc(G1_remain); // decrement the count + __ delayed()->nop(); __ load_klass(G3_oop, G4_klass); // query the object klass generate_type_check(G4_klass, O3_ckoff, O4_ckval, G5_super, // branch to this on success: - store_element, - // decrement this on success: - G1_remain); + store_element); // ======== end loop ======== // It was a real error; we must depend on the caller to finish the job. // Register G1 has number of *remaining* oops, O2 number of *total* oops. // Emit GC store barriers for the oops we have copied (O2 minus G1), // and report their number to the caller. - __ bind(fail); + __ BIND(fail); __ subcc(O2_count, G1_remain, O2_count); __ brx(Assembler::zero, false, Assembler::pt, done); __ delayed()->not1(O2_count, O0); // report (-1^K) to caller - __ bind(do_card_marks); + __ BIND(do_card_marks); gen_write_ref_array_post_barrier(O1_to, O2_count, O3); // store check on O1[0..O2] - __ bind(done); + __ BIND(done); inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4); __ retl(); __ delayed()->nop(); // return value in 00 diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index dcb9585f1ef..b043c9d3506 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -7286,6 +7286,225 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, } +void MacroAssembler::check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Label& L_success) { + Label L_failure; + check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_failure, NULL); + check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, noreg, &L_success, NULL); + bind(L_failure); +} + + +void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterConstant super_check_offset) { + assert_different_registers(sub_klass, super_klass, temp_reg); + bool must_load_sco = (super_check_offset.constant_or_zero() == -1); + if (super_check_offset.is_register()) { + assert_different_registers(sub_klass, super_klass, + super_check_offset.as_register()); + } else if (must_load_sco) { + assert(temp_reg != noreg, "supply either a temp or a register offset"); + } + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in the batch"); + + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + int sco_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::super_check_offset_offset_in_bytes()); + Address super_check_offset_addr(super_klass, sco_offset); + + // Hacked jcc, which "knows" that L_fallthrough, at least, is in + // range of a jccb. If this routine grows larger, reconsider at + // least some of these. +#define local_jcc(assembler_cond, label) \ + if (&(label) == &L_fallthrough) jccb(assembler_cond, label); \ + else jcc( assembler_cond, label) /*omit semi*/ + + // Hacked jmp, which may only be used just before L_fallthrough. +#define final_jmp(label) \ + if (&(label) == &L_fallthrough) { /*do nothing*/ } \ + else jmp(label) /*omit semi*/ + + // If the pointers are equal, we are done (e.g., String[] elements). + // This self-check enables sharing of secondary supertype arrays among + // non-primary types such as array-of-interface. Otherwise, each such + // type would need its own customized SSA. + // We move this check to the front of the fast path because many + // type checks are in fact trivially successful in this manner, + // so we get a nicely predicted branch right at the start of the check. + cmpptr(sub_klass, super_klass); + local_jcc(Assembler::equal, *L_success); + + // Check the supertype display: + if (must_load_sco) { + // Positive movl does right thing on LP64. + movl(temp_reg, super_check_offset_addr); + super_check_offset = RegisterConstant(temp_reg); + } + Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0); + cmpptr(super_klass, super_check_addr); // load displayed supertype + + // This check has worked decisively for primary supers. + // Secondary supers are sought in the super_cache ('super_cache_addr'). + // (Secondary supers are interfaces and very deeply nested subtypes.) + // This works in the same check above because of a tricky aliasing + // between the super_cache and the primary super display elements. + // (The 'super_check_addr' can address either, as the case requires.) + // Note that the cache is updated below if it does not help us find + // what we need immediately. + // So if it was a primary super, we can just fail immediately. + // Otherwise, it's the slow path for us (no success at this point). + + if (super_check_offset.is_register()) { + local_jcc(Assembler::equal, *L_success); + cmpl(super_check_offset.as_register(), sc_offset); + if (L_failure == &L_fallthrough) { + local_jcc(Assembler::equal, *L_slow_path); + } else { + local_jcc(Assembler::notEqual, *L_failure); + final_jmp(*L_slow_path); + } + } else if (super_check_offset.as_constant() == sc_offset) { + // Need a slow path; fast failure is impossible. + if (L_slow_path == &L_fallthrough) { + local_jcc(Assembler::equal, *L_success); + } else { + local_jcc(Assembler::notEqual, *L_slow_path); + final_jmp(*L_success); + } + } else { + // No slow path; it's a fast decision. + if (L_failure == &L_fallthrough) { + local_jcc(Assembler::equal, *L_success); + } else { + local_jcc(Assembler::notEqual, *L_failure); + final_jmp(*L_success); + } + } + + bind(L_fallthrough); + +#undef local_jcc +#undef final_jmp +} + + +void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + bool set_cond_codes) { + assert_different_registers(sub_klass, super_klass, temp_reg); + if (temp2_reg != noreg) + assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg); +#define IS_A_TEMP(reg) ((reg) == temp_reg || (reg) == temp2_reg) + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in the batch"); + + // a couple of useful fields in sub_klass: + int ss_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_supers_offset_in_bytes()); + int sc_offset = (klassOopDesc::header_size() * HeapWordSize + + Klass::secondary_super_cache_offset_in_bytes()); + Address secondary_supers_addr(sub_klass, ss_offset); + Address super_cache_addr( sub_klass, sc_offset); + + // Do a linear scan of the secondary super-klass chain. + // This code is rarely used, so simplicity is a virtue here. + // The repne_scan instruction uses fixed registers, which we must spill. + // Don't worry too much about pre-existing connections with the input regs. + + assert(sub_klass != rax, "killed reg"); // killed by mov(rax, super) + assert(sub_klass != rcx, "killed reg"); // killed by lea(rcx, &pst_counter) + + // Get super_klass value into rax (even if it was in rdi or rcx). + bool pushed_rax = false, pushed_rcx = false, pushed_rdi = false; + if (super_klass != rax || UseCompressedOops) { + if (!IS_A_TEMP(rax)) { push(rax); pushed_rax = true; } + mov(rax, super_klass); + } + if (!IS_A_TEMP(rcx)) { push(rcx); pushed_rcx = true; } + if (!IS_A_TEMP(rdi)) { push(rdi); pushed_rdi = true; } + +#ifndef PRODUCT + int* pst_counter = &SharedRuntime::_partial_subtype_ctr; + ExternalAddress pst_counter_addr((address) pst_counter); + NOT_LP64( incrementl(pst_counter_addr) ); + LP64_ONLY( lea(rcx, pst_counter_addr) ); + LP64_ONLY( incrementl(Address(rcx, 0)) ); +#endif //PRODUCT + + // We will consult the secondary-super array. + movptr(rdi, secondary_supers_addr); + // Load the array length. (Positive movl does right thing on LP64.) + movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); + // Skip to start of data. + addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + + // Scan RCX words at [RDI] for an occurrence of RAX. + // Set NZ/Z based on last compare. +#ifdef _LP64 + // This part is tricky, as values in supers array could be 32 or 64 bit wide + // and we store values in objArrays always encoded, thus we need to encode + // the value of rax before repne. Note that rax is dead after the repne. + if (UseCompressedOops) { + encode_heap_oop_not_null(rax); + // The superclass is never null; it would be a basic system error if a null + // pointer were to sneak in here. Note that we have already loaded the + // Klass::super_check_offset from the super_klass in the fast path, + // so if there is a null in that register, we are already in the afterlife. + repne_scanl(); + } else +#endif // _LP64 + repne_scan(); + + // Unspill the temp. registers: + if (pushed_rdi) pop(rdi); + if (pushed_rcx) pop(rcx); + if (pushed_rax) pop(rax); + + if (set_cond_codes) { + // Special hack for the AD files: rdi is guaranteed non-zero. + assert(!pushed_rdi, "rdi must be left non-NULL"); + // Also, the condition codes are properly set Z/NZ on succeed/failure. + } + + if (L_failure == &L_fallthrough) + jccb(Assembler::notEqual, *L_failure); + else jcc(Assembler::notEqual, *L_failure); + + // Success. Cache the super we found and proceed in triumph. + movptr(super_cache_addr, super_klass); + + if (L_success != &L_fallthrough) { + jmp(*L_success); + } + +#undef IS_A_TEMP + + bind(L_fallthrough); +} + + void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) { ucomisd(dst, as_Address(src)); } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index f369d4760fb..9b54b800ba1 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1807,6 +1807,40 @@ class MacroAssembler: public Assembler { Register scan_temp, Label& no_such_interface); + // Test sub_klass against super_klass, with fast and slow paths. + + // The fast path produces a tri-state answer: yes / no / maybe-slow. + // One of the three labels can be NULL, meaning take the fall-through. + // If super_check_offset is -1, the value is loaded up from super_klass. + // No registers are killed, except temp_reg. + void check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterConstant super_check_offset = RegisterConstant(-1)); + + // The rest of the type check; must be wired to a corresponding fast path. + // It does not repeat the fast path logic, so don't use it standalone. + // The temp_reg and temp2_reg can be noreg, if no temps are available. + // Updates the sub's secondary super cache as necessary. + // If set_cond_codes, condition codes will be Z on success, NZ on failure. + void check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register temp_reg, + Register temp2_reg, + Label* L_success, + Label* L_failure, + bool set_cond_codes = false); + + // Simplified, combined version, good for typical uses. + // Falls through on failure. + void check_klass_subtype(Register sub_klass, + Register super_klass, + Register temp_reg, + Label& L_success); + //---- void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0 diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 1e491190e65..b7ffb5b7e6a 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -1598,18 +1598,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { // get instance klass __ movptr(k_RInfo, Address(k_RInfo, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); - // get super_check_offset - __ movl(Rtmp1, Address(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes())); - // See if we get an immediate positive hit - __ cmpptr(k_RInfo, Address(klass_RInfo, Rtmp1, Address::times_1)); - __ jcc(Assembler::equal, done); - // check for immediate negative hit - __ cmpl(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ jcc(Assembler::notEqual, *stub->entry()); - // check for self - __ cmpptr(klass_RInfo, k_RInfo); - __ jcc(Assembler::equal, done); - + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); @@ -1735,17 +1726,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { } __ bind(done); } else { - __ movl(Rtmp1, Address(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes())); - // See if we get an immediate positive hit - __ cmpptr(k_RInfo, Address(klass_RInfo, Rtmp1, Address::times_1)); - __ jcc(Assembler::equal, done); - // check for immediate negative hit - __ cmpl(Rtmp1, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ jcc(Assembler::notEqual, *stub->entry()); - // check for self - __ cmpptr(klass_RInfo, k_RInfo); - __ jcc(Assembler::equal, done); - + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, &done, stub->entry(), NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); @@ -1821,23 +1804,15 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ pop(dst); __ jmp(done); } - } else { -#else - { // YUCK + } + else // next block is unconditional if LP64: #endif // LP64 + { assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers"); - __ movl(dst, Address(k_RInfo, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes())); - // See if we get an immediate positive hit - __ cmpptr(k_RInfo, Address(klass_RInfo, dst, Address::times_1)); - __ jcc(Assembler::equal, one); - // check for immediate negative hit - __ cmpl(dst, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - __ jcc(Assembler::notEqual, zero); - // check for self - __ cmpptr(klass_RInfo, k_RInfo); - __ jcc(Assembler::equal, one); - + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, dst, &one, &zero, NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...): __ push(klass_RInfo); __ push(k_RInfo); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 12aea3fde07..9c5cd181ee9 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1354,6 +1354,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { case slow_subtype_check_id: { + // Typical calling sequence: + // __ push(klass_RInfo); // object klass or other subclass + // __ push(sup_k_RInfo); // array element klass or other superclass + // __ call(slow_subtype_check); + // Note that the subclass is pushed first, and is therefore deepest. + // Previous versions of this code reversed the names 'sub' and 'super'. + // This was operationally harmless but made the code unreadable. enum layout { rax_off, SLOT2(raxH_off) rcx_off, SLOT2(rcxH_off) @@ -1361,9 +1368,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { rdi_off, SLOT2(rdiH_off) // saved_rbp_off, SLOT2(saved_rbpH_off) return_off, SLOT2(returnH_off) - sub_off, SLOT2(subH_off) - super_off, SLOT2(superH_off) - framesize + sup_k_off, SLOT2(sup_kH_off) + klass_off, SLOT2(superH_off) + framesize, + result_off = klass_off // deepest argument is also the return value }; __ set_info("slow_subtype_check", dont_gc_arguments); @@ -1373,19 +1381,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ push(rax); // This is called by pushing args and not with C abi - __ movptr(rsi, Address(rsp, (super_off) * VMRegImpl::stack_slot_size)); // super - __ movptr(rax, Address(rsp, (sub_off ) * VMRegImpl::stack_slot_size)); // sub - - __ movptr(rdi,Address(rsi,sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())); - // since size is postive movl does right thing on 64bit - __ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - __ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ movptr(rsi, Address(rsp, (klass_off) * VMRegImpl::stack_slot_size)); // subclass + __ movptr(rax, Address(rsp, (sup_k_off) * VMRegImpl::stack_slot_size)); // superclass Label miss; - __ repne_scan(); - __ jcc(Assembler::notEqual, miss); - __ movptr(Address(rsi,sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), rax); - __ movptr(Address(rsp, (super_off) * VMRegImpl::stack_slot_size), 1); // result + __ check_klass_subtype_slow_path(rsi, rax, rcx, rdi, NULL, &miss); + + // fallthrough on success: + __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), 1); // result __ pop(rax); __ pop(rcx); __ pop(rsi); @@ -1393,7 +1396,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ ret(0); __ bind(miss); - __ movptr(Address(rsp, (super_off) * VMRegImpl::stack_slot_size), NULL_WORD); // result + __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), NULL_WORD); // result __ pop(rax); __ pop(rcx); __ pop(rsi); diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp index 41d51f7aed4..1b344db23ad 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -219,47 +219,16 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, R // Resets EDI to locals. Register sub_klass cannot be any of the above. void InterpreterMacroAssembler::gen_subtype_check( Register Rsub_klass, Label &ok_is_subtype ) { assert( Rsub_klass != rax, "rax, holds superklass" ); - assert( Rsub_klass != rcx, "rcx holds 2ndary super array length" ); - assert( Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr" ); - Label not_subtype, loop; + assert( Rsub_klass != rcx, "used as a temp" ); + assert( Rsub_klass != rdi, "used as a temp, restored from locals" ); // Profile the not-null value's klass. - profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, rdi + profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi - // Load the super-klass's check offset into ECX - movl( rcx, Address(rax, sizeof(oopDesc) + Klass::super_check_offset_offset_in_bytes() ) ); - // Load from the sub-klass's super-class display list, or a 1-word cache of - // the secondary superclass list, or a failing value with a sentinel offset - // if the super-klass is an interface or exceptionally deep in the Java - // hierarchy and we have to scan the secondary superclass list the hard way. - // See if we get an immediate positive hit - cmpptr( rax, Address(Rsub_klass,rcx,Address::times_1) ); - jcc( Assembler::equal,ok_is_subtype ); + // Do the check. + check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx - // Check for immediate negative hit - cmpl( rcx, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() ); - jcc( Assembler::notEqual, not_subtype ); - // Check for self - cmpptr( Rsub_klass, rax ); - jcc( Assembler::equal, ok_is_subtype ); - - // Now do a linear scan of the secondary super-klass chain. - movptr( rdi, Address(Rsub_klass, sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes()) ); - // EDI holds the objArrayOop of secondary supers. - movl( rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes()));// Load the array length - // Skip to start of data; also clear Z flag incase ECX is zero - addptr( rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT) ); - // Scan ECX words at [EDI] for occurance of EAX - // Set NZ/Z based on last compare - repne_scan(); - restore_locals(); // Restore EDI; Must not blow flags - // Not equal? - jcc( Assembler::notEqual, not_subtype ); - // Must be equal but missed in cache. Update cache. - movptr( Address(Rsub_klass, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()), rax ); - jmp( ok_is_subtype ); - - bind(not_subtype); + // Profile the failure of the check. profile_typecheck_failed(rcx); // blows rcx } diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp index 6f7cd5298db..757793d0573 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -232,65 +232,13 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); - Label not_subtype, not_subtype_pop, loop; - // Profile the not-null value's klass. - profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, rdi + profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi - // Load the super-klass's check offset into rcx - movl(rcx, Address(rax, sizeof(oopDesc) + - Klass::super_check_offset_offset_in_bytes())); - // Load from the sub-klass's super-class display list, or a 1-word - // cache of the secondary superclass list, or a failing value with a - // sentinel offset if the super-klass is an interface or - // exceptionally deep in the Java hierarchy and we have to scan the - // secondary superclass list the hard way. See if we get an - // immediate positive hit - cmpptr(rax, Address(Rsub_klass, rcx, Address::times_1)); - jcc(Assembler::equal,ok_is_subtype); + // Do the check. + check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx - // Check for immediate negative hit - cmpl(rcx, sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()); - jcc( Assembler::notEqual, not_subtype ); - // Check for self - cmpptr(Rsub_klass, rax); - jcc(Assembler::equal, ok_is_subtype); - - // Now do a linear scan of the secondary super-klass chain. - movptr(rdi, Address(Rsub_klass, sizeof(oopDesc) + - Klass::secondary_supers_offset_in_bytes())); - // rdi holds the objArrayOop of secondary supers. - // Load the array length - movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - // Skip to start of data; also clear Z flag incase rcx is zero - addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - // Scan rcx words at [rdi] for occurance of rax - // Set NZ/Z based on last compare - - // this part is kind tricky, as values in supers array could be 32 or 64 bit wide - // and we store values in objArrays always encoded, thus we need to encode value - // before repne - if (UseCompressedOops) { - push(rax); - encode_heap_oop(rax); - repne_scanl(); - // Not equal? - jcc(Assembler::notEqual, not_subtype_pop); - // restore heap oop here for movq - pop(rax); - } else { - repne_scan(); - jcc(Assembler::notEqual, not_subtype); - } - // Must be equal but missed in cache. Update cache. - movptr(Address(Rsub_klass, sizeof(oopDesc) + - Klass::secondary_super_cache_offset_in_bytes()), rax); - jmp(ok_is_subtype); - - bind(not_subtype_pop); - // restore heap oop here for miss - if (UseCompressedOops) pop(rax); - bind(not_subtype); + // Profile the failure of the check. profile_typecheck_failed(rcx); // blows rcx } diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 9b220e20449..87c7730c7be 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -1310,81 +1310,51 @@ class StubGenerator: public StubCodeGenerator { Address& super_check_offset_addr, Address& super_klass_addr, Register temp, - Label* L_success_ptr, Label* L_failure_ptr) { + Label* L_success, Label* L_failure) { BLOCK_COMMENT("type_check:"); Label L_fallthrough; - bool fall_through_on_success = (L_success_ptr == NULL); - if (fall_through_on_success) { - L_success_ptr = &L_fallthrough; - } else { - L_failure_ptr = &L_fallthrough; - } - Label& L_success = *L_success_ptr; - Label& L_failure = *L_failure_ptr; +#define LOCAL_JCC(assembler_con, label_ptr) \ + if (label_ptr != NULL) __ jcc(assembler_con, *(label_ptr)); \ + else __ jcc(assembler_con, L_fallthrough) /*omit semi*/ + // The following is a strange variation of the fast path which requires + // one less register, because needed values are on the argument stack. + // __ check_klass_subtype_fast_path(sub_klass, *super_klass*, temp, + // L_success, L_failure, NULL); assert_different_registers(sub_klass, temp); - // a couple of useful fields in sub_klass: - int ss_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_supers_offset_in_bytes()); int sc_offset = (klassOopDesc::header_size() * HeapWordSize + Klass::secondary_super_cache_offset_in_bytes()); - Address secondary_supers_addr(sub_klass, ss_offset); - Address super_cache_addr( sub_klass, sc_offset); // if the pointers are equal, we are done (e.g., String[] elements) __ cmpptr(sub_klass, super_klass_addr); - __ jcc(Assembler::equal, L_success); + LOCAL_JCC(Assembler::equal, L_success); // check the supertype display: __ movl2ptr(temp, super_check_offset_addr); Address super_check_addr(sub_klass, temp, Address::times_1, 0); __ movptr(temp, super_check_addr); // load displayed supertype __ cmpptr(temp, super_klass_addr); // test the super type - __ jcc(Assembler::equal, L_success); + LOCAL_JCC(Assembler::equal, L_success); // if it was a primary super, we can just fail immediately __ cmpl(super_check_offset_addr, sc_offset); - __ jcc(Assembler::notEqual, L_failure); + LOCAL_JCC(Assembler::notEqual, L_failure); - // Now do a linear scan of the secondary super-klass chain. - // This code is rarely used, so simplicity is a virtue here. - inc_counter_np(SharedRuntime::_partial_subtype_ctr); - { - // The repne_scan instruction uses fixed registers, which we must spill. - // (We need a couple more temps in any case.) - __ push(rax); - __ push(rcx); - __ push(rdi); - assert_different_registers(sub_klass, rax, rcx, rdi); + // The repne_scan instruction uses fixed registers, which will get spilled. + // We happen to know this works best when super_klass is in rax. + Register super_klass = temp; + __ movptr(super_klass, super_klass_addr); + __ check_klass_subtype_slow_path(sub_klass, super_klass, noreg, noreg, + L_success, L_failure); - __ movptr(rdi, secondary_supers_addr); - // Load the array length. - __ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - // Skip to start of data. - __ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - // Scan rcx words at [edi] for occurance of rax, - // Set NZ/Z based on last compare - __ movptr(rax, super_klass_addr); - __ repne_scan(); - - // Unspill the temp. registers: - __ pop(rdi); - __ pop(rcx); - __ pop(rax); - } - __ jcc(Assembler::notEqual, L_failure); - - // Success. Cache the super we found and proceed in triumph. - __ movptr(temp, super_klass_addr); // note: rax, is dead - __ movptr(super_cache_addr, temp); - - if (!fall_through_on_success) - __ jmp(L_success); - - // Fall through on failure! __ bind(L_fallthrough); + + if (L_success == NULL) { BLOCK_COMMENT("L_success:"); } + if (L_failure == NULL) { BLOCK_COMMENT("L_failure:"); } + +#undef LOCAL_JCC } // diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 6c2fb5694e8..f1f1bc140f2 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -2091,66 +2091,9 @@ class StubGenerator: public StubCodeGenerator { Label L_miss; - // a couple of useful fields in sub_klass: - int ss_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_supers_offset_in_bytes()); - int sc_offset = (klassOopDesc::header_size() * HeapWordSize + - Klass::secondary_super_cache_offset_in_bytes()); - Address secondary_supers_addr(sub_klass, ss_offset); - Address super_cache_addr( sub_klass, sc_offset); - - // if the pointers are equal, we are done (e.g., String[] elements) - __ cmpptr(super_klass, sub_klass); - __ jcc(Assembler::equal, L_success); - - // check the supertype display: - Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0); - __ cmpptr(super_klass, super_check_addr); // test the super type - __ jcc(Assembler::equal, L_success); - - // if it was a primary super, we can just fail immediately - __ cmpl(super_check_offset, sc_offset); - __ jcc(Assembler::notEqual, L_miss); - - // Now do a linear scan of the secondary super-klass chain. - // The repne_scan instruction uses fixed registers, which we must spill. - // (We need a couple more temps in any case.) - // This code is rarely used, so simplicity is a virtue here. - inc_counter_np(SharedRuntime::_partial_subtype_ctr); - { - __ push(rax); - __ push(rcx); - __ push(rdi); - assert_different_registers(sub_klass, super_klass, rax, rcx, rdi); - - __ movptr(rdi, secondary_supers_addr); - // Load the array length. - __ movl(rcx, Address(rdi, arrayOopDesc::length_offset_in_bytes())); - // Skip to start of data. - __ addptr(rdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - // Scan rcx words at [rdi] for occurance of rax - // Set NZ/Z based on last compare - __ movptr(rax, super_klass); - if (UseCompressedOops) { - // Compare against compressed form. Don't need to uncompress because - // looks like orig rax is restored in popq below. - __ encode_heap_oop(rax); - __ repne_scanl(); - } else { - __ repne_scan(); - } - - // Unspill the temp. registers: - __ pop(rdi); - __ pop(rcx); - __ pop(rax); - - __ jcc(Assembler::notEqual, L_miss); - } - - // Success. Cache the super we found and proceed in triumph. - __ movptr(super_cache_addr, super_klass); // note: rax is dead - __ jmp(L_success); + __ check_klass_subtype_fast_path(sub_klass, super_klass, noreg, &L_success, &L_miss, NULL, + super_check_offset); + __ check_klass_subtype_slow_path(sub_klass, super_klass, noreg, noreg, &L_success, NULL); // Fall through on failure! __ BIND(L_miss); diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 9f09138bc55..479adb1cbfd 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1692,26 +1692,15 @@ encode %{ Register Reax = as_Register(EAX_enc); // super class Register Recx = as_Register(ECX_enc); // killed Register Resi = as_Register(ESI_enc); // sub class - Label hit, miss; + Label miss; MacroAssembler _masm(&cbuf); - // Compare super with sub directly, since super is not in its own SSA. - // The compiler used to emit this test, but we fold it in here, - // to allow platform-specific tweaking on sparc. - __ cmpptr(Reax, Resi); - __ jcc(Assembler::equal, hit); -#ifndef PRODUCT - __ incrementl(ExternalAddress((address)&SharedRuntime::_partial_subtype_ctr)); -#endif //PRODUCT - __ movptr(Redi,Address(Resi,sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())); - __ movl(Recx,Address(Redi,arrayOopDesc::length_offset_in_bytes())); - __ addptr(Redi,arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - __ repne_scan(); - __ jcc(Assembler::notEqual, miss); - __ movptr(Address(Resi,sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes()),Reax); - __ bind(hit); - if( $primary ) - __ xorptr(Redi,Redi); + __ check_klass_subtype_slow_path(Resi, Reax, Recx, Redi, + NULL, &miss, + /*set_cond_codes:*/ true); + if ($primary) { + __ xorptr(Redi, Redi); + } __ bind(miss); %} @@ -12566,15 +12555,12 @@ instruct partialSubtypeCheck( eDIRegP result, eSIRegP sub, eAXRegP super, eCXReg effect( KILL rcx, KILL cr ); ins_cost(1100); // slightly larger than the next version - format %{ "CMPL EAX,ESI\n\t" - "JEQ,s hit\n\t" - "MOV EDI,[$sub+Klass::secondary_supers]\n\t" + format %{ "MOV EDI,[$sub+Klass::secondary_supers]\n\t" "MOV ECX,[EDI+arrayKlass::length]\t# length to scan\n\t" "ADD EDI,arrayKlass::base_offset\t# Skip to start of data; set NZ in case count is zero\n\t" "REPNE SCASD\t# Scan *EDI++ for a match with EAX while CX-- != 0\n\t" "JNE,s miss\t\t# Missed: EDI not-zero\n\t" "MOV [$sub+Klass::secondary_super_cache],$super\t# Hit: update cache\n\t" - "hit:\n\t" "XOR $result,$result\t\t Hit: EDI zero\n\t" "miss:\t" %} @@ -12588,9 +12574,7 @@ instruct partialSubtypeCheck_vs_Zero( eFlagsReg cr, eSIRegP sub, eAXRegP super, effect( KILL rcx, KILL result ); ins_cost(1000); - format %{ "CMPL EAX,ESI\n\t" - "JEQ,s miss\t# Actually a hit; we are done.\n\t" - "MOV EDI,[$sub+Klass::secondary_supers]\n\t" + format %{ "MOV EDI,[$sub+Klass::secondary_supers]\n\t" "MOV ECX,[EDI+arrayKlass::length]\t# length to scan\n\t" "ADD EDI,arrayKlass::base_offset\t# Skip to start of data; set NZ in case count is zero\n\t" "REPNE SCASD\t# Scan *EDI++ for a match with EAX while CX-- != 0\n\t" diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 5872d2b6d4a..0705c2a009e 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -2575,43 +2575,13 @@ encode %{ Register Rrax = as_Register(RAX_enc); // super class Register Rrcx = as_Register(RCX_enc); // killed Register Rrsi = as_Register(RSI_enc); // sub class - Label hit, miss, cmiss; + Label miss; + const bool set_cond_codes = true; MacroAssembler _masm(&cbuf); - // Compare super with sub directly, since super is not in its own SSA. - // The compiler used to emit this test, but we fold it in here, - // to allow platform-specific tweaking on sparc. - __ cmpptr(Rrax, Rrsi); - __ jcc(Assembler::equal, hit); -#ifndef PRODUCT - __ lea(Rrcx, ExternalAddress((address)&SharedRuntime::_partial_subtype_ctr)); - __ incrementl(Address(Rrcx, 0)); -#endif //PRODUCT - __ movptr(Rrdi, Address(Rrsi, - sizeof(oopDesc) + - Klass::secondary_supers_offset_in_bytes())); - __ movl(Rrcx, Address(Rrdi, arrayOopDesc::length_offset_in_bytes())); - __ addptr(Rrdi, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - if (UseCompressedOops) { - __ push(Rrax); - __ encode_heap_oop(Rrax); - __ repne_scanl(); - __ pop(Rrax); - __ jccb(Assembler::notEqual, miss); - __ movptr(Address(Rrsi, - sizeof(oopDesc) + - Klass::secondary_super_cache_offset_in_bytes()), - Rrax); - __ jmp(hit); - } else { - __ repne_scan(); - __ jccb(Assembler::notEqual, miss); - __ movptr(Address(Rrsi, - sizeof(oopDesc) + - Klass::secondary_super_cache_offset_in_bytes()), - Rrax); - } - __ bind(hit); + __ check_klass_subtype_slow_path(Rrsi, Rrax, Rrcx, Rrdi, + NULL, &miss, + /*set_cond_codes:*/ true); if ($primary) { __ xorptr(Rrdi, Rrdi); } @@ -12179,15 +12149,12 @@ instruct partialSubtypeCheck(rdi_RegP result, effect(KILL rcx, KILL cr); ins_cost(1100); // slightly larger than the next version - format %{ "cmpq rax, rsi\n\t" - "jeq,s hit\n\t" - "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" + format %{ "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" "movl rcx, [rdi + arrayOopDesc::length_offset_in_bytes()]\t# length to scan\n\t" "addq rdi, arrayOopDex::base_offset_in_bytes(T_OBJECT)\t# Skip to start of data; set NZ in case count is zero\n\t" "repne scasq\t# Scan *rdi++ for a match with rax while rcx--\n\t" "jne,s miss\t\t# Missed: rdi not-zero\n\t" "movq [$sub + (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes())], $super\t# Hit: update cache\n\t" - "hit:\n\t" "xorq $result, $result\t\t Hit: rdi zero\n\t" "miss:\t" %} @@ -12205,9 +12172,7 @@ instruct partialSubtypeCheck_vs_Zero(rFlagsReg cr, effect(KILL rcx, KILL result); ins_cost(1000); - format %{ "cmpq rax, rsi\n\t" - "jeq,s miss\t# Actually a hit; we are done.\n\t" - "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" + format %{ "movq rdi, [$sub + (sizeof(oopDesc) + Klass::secondary_supers_offset_in_bytes())]\n\t" "movl rcx, [rdi + arrayOopDesc::length_offset_in_bytes()]\t# length to scan\n\t" "addq rdi, arrayOopDex::base_offset_in_bytes(T_OBJECT)\t# Skip to start of data; set NZ in case count is zero\n\t" "repne scasq\t# Scan *rdi++ for a match with rax while cx-- != 0\n\t" diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index e81e0075340..a3e7589d57b 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -2277,7 +2277,7 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { r_not_subtype->init_req(1, _gvn.transform( new (C, 1) IfTrueNode (iff2) ) ); set_control( _gvn.transform( new (C, 1) IfFalseNode(iff2) ) ); - // Check for self. Very rare to get here, but its taken 1/3 the time. + // Check for self. Very rare to get here, but it is taken 1/3 the time. // No performance impact (too rare) but allows sharing of secondary arrays // which has some footprint reduction. Node *cmp3 = _gvn.transform( new (C, 3) CmpPNode( subklass, superklass ) ); @@ -2286,11 +2286,27 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) { r_ok_subtype->init_req(2, _gvn.transform( new (C, 1) IfTrueNode ( iff3 ) ) ); set_control( _gvn.transform( new (C, 1) IfFalseNode( iff3 ) ) ); + // -- Roads not taken here: -- + // We could also have chosen to perform the self-check at the beginning + // of this code sequence, as the assembler does. This would not pay off + // the same way, since the optimizer, unlike the assembler, can perform + // static type analysis to fold away many successful self-checks. + // Non-foldable self checks work better here in second position, because + // the initial primary superclass check subsumes a self-check for most + // types. An exception would be a secondary type like array-of-interface, + // which does not appear in its own primary supertype display. + // Finally, we could have chosen to move the self-check into the + // PartialSubtypeCheckNode, and from there out-of-line in a platform + // dependent manner. But it is worthwhile to have the check here, + // where it can be perhaps be optimized. The cost in code space is + // small (register compare, branch). + // Now do a linear scan of the secondary super-klass array. Again, no real // performance impact (too rare) but it's gotta be done. - // (The stub also contains the self-check of subklass == superklass. // Since the code is rarely used, there is no penalty for moving it - // out of line, and it can only improve I-cache density.) + // out of line, and it can only improve I-cache density. + // The decision to inline or out-of-line this final check is platform + // dependent, and is found in the AD file definition of PartialSubtypeCheck. Node* psc = _gvn.transform( new (C, 3) PartialSubtypeCheckNode(control(), subklass, superklass) ); From 9dff23337ba066dd704a1d51aa9b2a8953f2fb7c Mon Sep 17 00:00:00 2001 From: Poonam Bajaj Date: Sun, 15 Mar 2009 18:11:46 -0700 Subject: [PATCH 07/43] 6812971: SA: re-attaching to process fails After attaching, de-attaching SA from a process, the second time attach() call fails. This happens because in VM.initialize(), Universe does not get re-initialized before it is accessed. Reviewed-by: swamyv --- .../agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java index 0272c069352..8f176f2f5e3 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -342,11 +342,13 @@ public class VM { throw new RuntimeException("Attempt to initialize VM twice"); } soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian()); - debugger.putHeapConst(Universe.getHeapBase(), soleInstance.getHeapOopSize(), - soleInstance.logMinObjAlignmentInBytes); + for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) { ((Observer) iter.next()).update(null, null); } + + debugger.putHeapConst(Universe.getHeapBase(), soleInstance.getHeapOopSize(), + soleInstance.logMinObjAlignmentInBytes); } /** This is used by the debugging system */ From ecdb99412dc521b5e539e1996bcc9b5ccb9afb9d Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Sun, 15 Mar 2009 22:03:38 -0400 Subject: [PATCH 08/43] 6604422: G1: re-use half-promoted regions 6728271: G1: Cleanup G1CollectedHeap::get_gc_alloc_regions() It allows the last half-full region to be allocated to during a GC to be reused during the next GC. Reviewed-by: apetrusenko, jcoomes --- .../gc_implementation/g1/g1CollectedHeap.cpp | 122 +++++++++++++++--- .../gc_implementation/g1/g1CollectedHeap.hpp | 27 +++- .../g1/g1CollectorPolicy.cpp | 1 + 3 files changed, 126 insertions(+), 24 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 7346a545468..6cb639724f0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -786,6 +786,12 @@ void G1CollectedHeap::abandon_cur_alloc_region() { } } +void G1CollectedHeap::abandon_gc_alloc_regions() { + // first, make sure that the GC alloc region list is empty (it should!) + assert(_gc_alloc_region_list == NULL, "invariant"); + release_gc_alloc_regions(true /* totally */); +} + class PostMCRemSetClearClosure: public HeapRegionClosure { ModRefBarrierSet* _mr_bs; public: @@ -914,6 +920,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, // Make sure we'll choose a new allocation region afterwards. abandon_cur_alloc_region(); + abandon_gc_alloc_regions(); assert(_cur_alloc_region == NULL, "Invariant."); g1_rem_set()->as_HRInto_G1RemSet()->cleanupHRRS(); tear_down_region_lists(); @@ -1306,7 +1313,7 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) } void G1CollectedHeap::shrink(size_t shrink_bytes) { - release_gc_alloc_regions(); + release_gc_alloc_regions(true /* totally */); tear_down_region_lists(); // We will rebuild them in a moment. shrink_helper(shrink_bytes); rebuild_region_lists(); @@ -1345,8 +1352,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _gc_time_stamp(0), _surviving_young_words(NULL), _in_cset_fast_test(NULL), - _in_cset_fast_test_base(NULL) -{ + _in_cset_fast_test_base(NULL) { _g1h = this; // To catch bugs. if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { vm_exit_during_initialization("Failed necessary allocation."); @@ -1371,9 +1377,19 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : } for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { - _gc_alloc_regions[ap] = NULL; - _gc_alloc_region_counts[ap] = 0; + _gc_alloc_regions[ap] = NULL; + _gc_alloc_region_counts[ap] = 0; + _retained_gc_alloc_regions[ap] = NULL; + // by default, we do not retain a GC alloc region for each ap; + // we'll override this, when appropriate, below + _retain_gc_alloc_region[ap] = false; } + + // We will try to remember the last half-full tenured region we + // allocated to at the end of a collection so that we can re-use it + // during the next collection. + _retain_gc_alloc_region[GCAllocForTenured] = true; + guarantee(_task_queues != NULL, "task_queues allocation failure."); } @@ -2644,7 +2660,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { popular_region->set_popular_pending(false); } - release_gc_alloc_regions(); + release_gc_alloc_regions(false /* totally */); cleanup_surviving_young_words(); @@ -2735,6 +2751,10 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) { assert(purpose >= 0 && purpose < GCAllocPurposeCount, "invalid purpose"); + // make sure we don't call set_gc_alloc_region() multiple times on + // the same region + assert(r == NULL || !r->is_gc_alloc_region(), + "shouldn't already be a GC alloc region"); HeapWord* original_top = NULL; if (r != NULL) original_top = r->top(); @@ -2851,23 +2871,55 @@ bool G1CollectedHeap::check_gc_alloc_regions() { } void G1CollectedHeap::get_gc_alloc_regions() { + // First, let's check that the GC alloc region list is empty (it should) + assert(_gc_alloc_region_list == NULL, "invariant"); + for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { + assert(_gc_alloc_regions[ap] == NULL, "invariant"); + // Create new GC alloc regions. - HeapRegion* alloc_region = _gc_alloc_regions[ap]; - // Clear this alloc region, so that in case it turns out to be - // unacceptable, we end up with no allocation region, rather than a bad - // one. - _gc_alloc_regions[ap] = NULL; - if (alloc_region == NULL || alloc_region->in_collection_set()) { - // Can't re-use old one. Allocate a new one. + HeapRegion* alloc_region = _retained_gc_alloc_regions[ap]; + _retained_gc_alloc_regions[ap] = NULL; + + if (alloc_region != NULL) { + assert(_retain_gc_alloc_region[ap], "only way to retain a GC region"); + + // let's make sure that the GC alloc region is not tagged as such + // outside a GC operation + assert(!alloc_region->is_gc_alloc_region(), "sanity"); + + if (alloc_region->in_collection_set() || + alloc_region->top() == alloc_region->end() || + alloc_region->top() == alloc_region->bottom()) { + // we will discard the current GC alloc region if it's in the + // collection set (it can happen!), if it's already full (no + // point in using it), or if it's empty (this means that it + // was emptied during a cleanup and it should be on the free + // list now). + + alloc_region = NULL; + } + } + + if (alloc_region == NULL) { + // we will get a new GC alloc region alloc_region = newAllocRegionWithExpansion(ap, 0); } + if (alloc_region != NULL) { + assert(_gc_alloc_regions[ap] == NULL, "pre-condition"); set_gc_alloc_region(ap, alloc_region); } + + assert(_gc_alloc_regions[ap] == NULL || + _gc_alloc_regions[ap]->is_gc_alloc_region(), + "the GC alloc region should be tagged as such"); + assert(_gc_alloc_regions[ap] == NULL || + _gc_alloc_regions[ap] == _gc_alloc_region_list, + "the GC alloc region should be the same as the GC alloc list head"); } // Set alternative regions for allocation purposes that have reached - // thier limit. + // their limit. for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { GCAllocPurpose alt_purpose = g1_policy()->alternative_purpose(ap); if (_gc_alloc_regions[ap] == NULL && alt_purpose != ap) { @@ -2877,28 +2929,56 @@ void G1CollectedHeap::get_gc_alloc_regions() { assert(check_gc_alloc_regions(), "alloc regions messed up"); } -void G1CollectedHeap::release_gc_alloc_regions() { +void G1CollectedHeap::release_gc_alloc_regions(bool totally) { // We keep a separate list of all regions that have been alloc regions in - // the current collection pause. Forget that now. + // the current collection pause. Forget that now. This method will + // untag the GC alloc regions and tear down the GC alloc region + // list. It's desirable that no regions are tagged as GC alloc + // outside GCs. forget_alloc_region_list(); // The current alloc regions contain objs that have survived // collection. Make them no longer GC alloc regions. for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { HeapRegion* r = _gc_alloc_regions[ap]; - if (r != NULL && r->is_empty()) { - { + _retained_gc_alloc_regions[ap] = NULL; + + if (r != NULL) { + // we retain nothing on _gc_alloc_regions between GCs + set_gc_alloc_region(ap, NULL); + _gc_alloc_region_counts[ap] = 0; + + if (r->is_empty()) { + // we didn't actually allocate anything in it; let's just put + // it on the free list MutexLockerEx x(ZF_mon, Mutex::_no_safepoint_check_flag); r->set_zero_fill_complete(); put_free_region_on_list_locked(r); + } else if (_retain_gc_alloc_region[ap] && !totally) { + // retain it so that we can use it at the beginning of the next GC + _retained_gc_alloc_regions[ap] = r; } } - // set_gc_alloc_region will also NULLify all aliases to the region - set_gc_alloc_region(ap, NULL); - _gc_alloc_region_counts[ap] = 0; } } +#ifndef PRODUCT +// Useful for debugging + +void G1CollectedHeap::print_gc_alloc_regions() { + gclog_or_tty->print_cr("GC alloc regions"); + for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { + HeapRegion* r = _gc_alloc_regions[ap]; + if (r == NULL) { + gclog_or_tty->print_cr(" %2d : "PTR_FORMAT, ap, NULL); + } else { + gclog_or_tty->print_cr(" %2d : "PTR_FORMAT" "SIZE_FORMAT, + ap, r->bottom(), r->used()); + } + } +} +#endif // PRODUCT + void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) { _drain_in_progress = false; set_evac_failure_closure(cl); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index d5637ee5836..f8c8d3f9d36 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -172,7 +172,6 @@ private: NumAPIs = HeapRegion::MaxAge }; - // The one and only G1CollectedHeap, so static functions can find it. static G1CollectedHeap* _g1h; @@ -217,11 +216,20 @@ private: // Postcondition: cur_alloc_region == NULL. void abandon_cur_alloc_region(); + void abandon_gc_alloc_regions(); // The to-space memory regions into which objects are being copied during // a GC. HeapRegion* _gc_alloc_regions[GCAllocPurposeCount]; size_t _gc_alloc_region_counts[GCAllocPurposeCount]; + // These are the regions, one per GCAllocPurpose, that are half-full + // at the end of a collection and that we want to reuse during the + // next collection. + HeapRegion* _retained_gc_alloc_regions[GCAllocPurposeCount]; + // This specifies whether we will keep the last half-full region at + // the end of a collection so that it can be reused during the next + // collection (this is specified per GCAllocPurpose) + bool _retain_gc_alloc_region[GCAllocPurposeCount]; // A list of the regions that have been set to be alloc regions in the // current collection. @@ -589,8 +597,21 @@ protected: // Ensure that the relevant gc_alloc regions are set. void get_gc_alloc_regions(); - // We're done with GC alloc regions; release them, as appropriate. - void release_gc_alloc_regions(); + // We're done with GC alloc regions. We are going to tear down the + // gc alloc list and remove the gc alloc tag from all the regions on + // that list. However, we will also retain the last (i.e., the one + // that is half-full) GC alloc region, per GCAllocPurpose, for + // possible reuse during the next collection, provided + // _retain_gc_alloc_region[] indicates that it should be the + // case. Said regions are kept in the _retained_gc_alloc_regions[] + // array. If the parameter totally is set, we will not retain any + // regions, irrespective of what _retain_gc_alloc_region[] + // indicates. + void release_gc_alloc_regions(bool totally); +#ifndef PRODUCT + // Useful for debugging. + void print_gc_alloc_regions(); +#endif // !PRODUCT // ("Weak") Reference processing support ReferenceProcessor* _ref_processor; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 142a4e24fcc..16f95f35fa8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -1087,6 +1087,7 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, assert(_g1->used_regions() == _g1->recalculate_used_regions(), "sanity"); + assert(_g1->used() == _g1->recalculate_used(), "sanity"); double s_w_t_ms = (start_time_sec - _stop_world_start) * 1000.0; _all_stop_world_times_ms->add(s_w_t_ms); From 82619cc8da8e8603b6bbd3c76f0f23ef21cff1c8 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Mon, 16 Mar 2009 08:01:32 -0700 Subject: [PATCH 09/43] 6817419: G1: Enable extensive verification for humongous regions Enabled full verification for humongous regions. Also made sure that the VerifyAfterGC works with deferred updates and G1HRRSFlushLogBuffersOnVerify. Reviewed-by: tonyp --- .../g1/concurrentG1Refine.cpp | 11 +++------ .../gc_implementation/g1/g1CollectedHeap.cpp | 23 +++++++++++-------- .../vm/gc_implementation/g1/g1RemSet.cpp | 11 +++++---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp index 2eb2bc0ca69..6f12a396216 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp @@ -145,14 +145,9 @@ void ConcurrentG1Refine::set_pya_restart() { if (G1RSBarrierUseQueue) { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.abandon_logs(); - if (_cg1rThread->do_traversal()) { - _pya = PYA_restart; - } else { - _cg1rThread->set_do_traversal(true); - // Reset the post-yield actions. - _pya = PYA_continue; - _last_pya = PYA_continue; - } + // Reset the post-yield actions. + _pya = PYA_continue; + _last_pya = PYA_continue; } else { _pya = PYA_restart; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 6cb639724f0..b6a4413eeb1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -961,6 +961,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); + prepare_for_verify(); Universe::verify(false); } NOT_PRODUCT(ref_processor()->verify_no_references_recorded()); @@ -2135,15 +2136,7 @@ public: bool doHeapRegion(HeapRegion* r) { guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue, "Should be unclaimed at verify points."); - if (r->isHumongous()) { - if (r->startsHumongous()) { - // Verify the single H object. - oop(r->bottom())->verify(); - size_t word_sz = oop(r->bottom())->size(); - guarantee(r->top() == r->bottom() + word_sz, - "Only one object in a humongous region"); - } - } else { + if (!r->continuesHumongous()) { VerifyObjsInRegionClosure not_dead_yet_cl(r); r->verify(_allow_dirty); r->object_iterate(¬_dead_yet_cl); @@ -2195,6 +2188,7 @@ public: _g1h(g1h), _allow_dirty(allow_dirty) { } void work(int worker_i) { + HandleMark hm; VerifyRegionClosure blk(_allow_dirty, true); _g1h->heap_region_par_iterate_chunked(&blk, worker_i, HeapRegion::ParVerifyClaimValue); @@ -2713,6 +2707,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) { if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); + prepare_for_verify(); Universe::verify(false); } @@ -2844,6 +2839,12 @@ void G1CollectedHeap::forget_alloc_region_list() { while (_gc_alloc_region_list != NULL) { HeapRegion* r = _gc_alloc_region_list; assert(r->is_gc_alloc_region(), "Invariant."); + // We need HeapRegion::oops_on_card_seq_iterate_careful() to work on + // newly allocated data in order to be able to apply deferred updates + // before the GC is done for verification purposes (i.e to allow + // G1HRRSFlushLogBuffersOnVerify). It's safe thing to do after the + // collection. + r->ContiguousSpace::set_saved_mark(); _gc_alloc_region_list = r->next_gc_alloc_region(); r->set_next_gc_alloc_region(NULL); r->set_is_gc_alloc_region(false); @@ -3738,7 +3739,9 @@ protected: CardTableModRefBS* ctbs() { return _ct_bs; } void immediate_rs_update(HeapRegion* from, oop* p, int tid) { - _g1_rem->par_write_ref(from, p, tid); + if (!from->is_survivor()) { + _g1_rem->par_write_ref(from, p, tid); + } } void deferred_rs_update(HeapRegion* from, oop* p, int tid) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 90636edc93a..6e36bda9c72 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -716,8 +716,7 @@ public: bool doHeapRegion(HeapRegion* r) { if (!r->in_collection_set() && !r->continuesHumongous() && - !r->is_young() && - !r->is_survivor()) { + !r->is_young()) { _update_rs_oop_cl.set_from(r); UpdateRSObjectClosure update_rs_obj_cl(&_update_rs_oop_cl); @@ -854,7 +853,7 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // before all the cards on the region are dirtied. This is unlikely, // and it doesn't happen often, but it can happen. So, the extra // check below filters out those cards. - if (r->is_young() || r->is_survivor()) { + if (r->is_young()) { return; } // While we are processing RSet buffers during the collection, we @@ -1025,7 +1024,9 @@ void HRInto_G1RemSet::print_summary_info() { } } void HRInto_G1RemSet::prepare_for_verify() { - if (G1HRRSFlushLogBuffersOnVerify && VerifyBeforeGC && !_g1->full_collection()) { + if (G1HRRSFlushLogBuffersOnVerify && + (VerifyBeforeGC || VerifyAfterGC) + && !_g1->full_collection()) { cleanupHRRS(); _g1->set_refine_cte_cl_concurrency(false); if (SafepointSynchronize::is_at_safepoint()) { @@ -1036,5 +1037,7 @@ void HRInto_G1RemSet::prepare_for_verify() { _cg1r->set_use_cache(false); updateRS(0); _cg1r->set_use_cache(cg1r_use_cache); + + assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); } } From 217739210df6df97ca4529ed56377e7f225f9da5 Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Mon, 16 Mar 2009 10:52:44 -0400 Subject: [PATCH 10/43] 6816154: G1: introduce flags to enable/disable RSet updating and scanning Introduces two flags, -XX:-/+G1EnableParallelRSetUpdating and -XX:-/+G1EnableParallelRSetScanning, to turn on/off the "band aid" fix that serializes RSet updating / scanning during GCs. Reviewed-by: iveresov --- .../share/vm/gc_implementation/g1/g1RemSet.cpp | 15 +++++++++------ .../share/vm/gc_implementation/g1/g1_globals.hpp | 10 +++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 6e36bda9c72..b4f9791d5cb 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -502,14 +502,17 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, } if (ParallelGCThreads > 0) { - // This is a temporary change to serialize the update and scanning - // of remembered sets. There are some race conditions when this is - // done in parallel and they are causing failures. When we resolve - // said race conditions, we'll revert back to parallel remembered - // set updating and scanning. See CRs 6677707 and 6677708. - if (worker_i == 0) { + // The two flags below were introduced temporarily to serialize + // the updating and scanning of remembered sets. There are some + // race conditions when these two operations are done in parallel + // and they are causing failures. When we resolve said race + // conditions, we'll revert back to parallel remembered set + // updating and scanning. See CRs 6677707 and 6677708. + if (G1EnableParallelRSetUpdating || (worker_i == 0)) { updateRS(worker_i); scanNewRefsRS(oc, worker_i); + } + if (G1EnableParallelRSetScanning || (worker_i == 0)) { scanRS(oc, worker_i); } } else { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index fd23f65d15a..d05a6a6400a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -295,6 +295,14 @@ \ product(uintx, G1FixedSurvivorSpaceSize, 0, \ "If non-0 is the size of the G1 survivor space, " \ - "otherwise SurvivorRatio is used to determine the size") + "otherwise SurvivorRatio is used to determine the size") \ + \ + experimental(bool, G1EnableParallelRSetUpdating, false, \ + "Enables the parallelization of remembered set updating " \ + "during evacuation pauses") \ + \ + experimental(bool, G1EnableParallelRSetScanning, false, \ + "Enables the parallelization of remembered set scanning " \ + "during evacuation pauses") G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) From f210928e7311ce05a67b2f3d74cf189ba6fb0bde Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 16 Mar 2009 15:06:33 -0700 Subject: [PATCH 11/43] 6816308: Changes to allow builds with latest Windows SDK 6.1 on 64bit Windows 2003 Allow Hotspot builds with latest Windows SDK 6.1 on 64bit Windows 2003 Reviewed-by: ohair, tbell, jcoomes --- hotspot/make/windows/get_msc_ver.sh | 1 + hotspot/make/windows/makefiles/compile.make | 8 ++------ hotspot/make/windows/makefiles/sa.make | 2 ++ hotspot/make/windows/makefiles/sanity.make | 4 ++-- hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp | 4 ++-- hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp | 5 +++++ hotspot/src/share/vm/adlc/adlc.hpp | 2 +- .../src/share/vm/gc_implementation/g1/concurrentMark.cpp | 2 +- .../share/vm/gc_implementation/g1/heapRegionRemSet.cpp | 2 +- hotspot/src/share/vm/memory/blockOffsetTable.hpp | 2 +- hotspot/src/share/vm/runtime/vm_version.cpp | 6 ++++-- .../src/share/vm/utilities/globalDefinitions_visCPP.hpp | 2 +- 12 files changed, 23 insertions(+), 17 deletions(-) diff --git a/hotspot/make/windows/get_msc_ver.sh b/hotspot/make/windows/get_msc_ver.sh index 6bbbbef7859..67df0d0dd95 100644 --- a/hotspot/make/windows/get_msc_ver.sh +++ b/hotspot/make/windows/get_msc_ver.sh @@ -29,6 +29,7 @@ # cl version 13.10.3077 returns "MSC_VER=1310" # cl version 14.00.30701 returns "MSC_VER=1399" (OLD_MSSDK version) # cl version 14.00.40310.41 returns "MSC_VER=1400" +# cl version 15.00.21022.8 returns "MSC_VER=1500" # Note that we currently do not have a way to set HotSpotMksHome in # the batch build, but so far this has not seemed to be a problem. The diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make index ddc9ea11a9f..5869d7cb800 100644 --- a/hotspot/make/windows/makefiles/compile.make +++ b/hotspot/make/windows/makefiles/compile.make @@ -170,11 +170,9 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) $(BUFFEROVERFLOWLIB) # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. MT=mt.exe -!if "$(BUILDARCH)" == "i486" -# VS2005 on x86 restricts the use of certain libc functions without this +# VS2005 and later restricts the use of certain libc functions without this CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE !endif -!endif !if "$(COMPILER_NAME)" == "VS2008" PRODUCT_OPT_OPTION = /O2 /Oy- @@ -185,11 +183,9 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. MT=mt.exe -!if "$(BUILDARCH)" == "i486" -# VS2005 on x86 restricts the use of certain libc functions without this +# VS2005 and later restricts the use of certain libc functions without this CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE !endif -!endif # Compile for space above time. !if "$(Variant)" == "kernel" diff --git a/hotspot/make/windows/makefiles/sa.make b/hotspot/make/windows/makefiles/sa.make index c1956057188..1970f116b45 100644 --- a/hotspot/make/windows/makefiles/sa.make +++ b/hotspot/make/windows/makefiles/sa.make @@ -89,9 +89,11 @@ checkAndBuildSA:: $(SAWINDBG) SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 $(GX_OPTION) /Od /D "WIN32" /D "WIN64" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c !elseif "$(BUILDARCH)" == "amd64" SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 $(GX_OPTION) /Od /D "WIN32" /D "WIN64" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +!if "$(COMPILER_NAME)" == "VS2005" # On amd64, VS2005 compiler requires bufferoverflowU.lib on the link command line, # otherwise we get missing __security_check_cookie externals at link time. SA_LINK_FLAGS = bufferoverflowU.lib +!endif !else SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 /Gm $(GX_OPTION) /ZI /Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c !endif diff --git a/hotspot/make/windows/makefiles/sanity.make b/hotspot/make/windows/makefiles/sanity.make index 5b4293d27f8..dd5c7499f1d 100644 --- a/hotspot/make/windows/makefiles/sanity.make +++ b/hotspot/make/windows/makefiles/sanity.make @@ -27,9 +27,9 @@ all: checkCL checkLink checkCL: - @ if "$(MSC_VER)" NEQ "1310" if "$(MSC_VER)" NEQ "1399" if "$(MSC_VER)" NEQ "1400" \ + @ if "$(MSC_VER)" NEQ "1310" if "$(MSC_VER)" NEQ "1399" if "$(MSC_VER)" NEQ "1400" if "$(MSC_VER)" NEQ "1500" \ echo *** WARNING *** unrecognized cl.exe version $(MSC_VER) ($(RAW_MSC_VER)). Use FORCE_MSC_VER to override automatic detection. checkLink: - @ if "$(LINK_VER)" NEQ "710" if "$(LINK_VER)" NEQ "800" \ + @ if "$(LINK_VER)" NEQ "710" if "$(LINK_VER)" NEQ "800" if "$(LINK_VER)" NEQ "900" \ echo *** WARNING *** unrecognized link.exe version $(LINK_VER) ($(RAW_LINK_VER)). Use FORCE_LINK_VER to override automatic detection. diff --git a/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp index e3c8c6be94b..04f87f3bbab 100644 --- a/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreterRT_x86_64.cpp @@ -349,7 +349,7 @@ class SlowSignatureHandler if (_num_args < Argument::n_float_register_parameters_c-1) { *_reg_args++ = from_obj; - *_fp_identifiers |= (0x01 << (_num_args*2)); // mark as float + *_fp_identifiers |= (intptr_t)(0x01 << (_num_args*2)); // mark as float _num_args++; } else { *_to++ = from_obj; @@ -364,7 +364,7 @@ class SlowSignatureHandler if (_num_args < Argument::n_float_register_parameters_c-1) { *_reg_args++ = from_obj; - *_fp_identifiers |= (0x3 << (_num_args*2)); // mark as double + *_fp_identifiers |= (intptr_t)(0x3 << (_num_args*2)); // mark as double _num_args++; } else { *_to++ = from_obj; diff --git a/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp index 1e8ed078d54..5f8958567e0 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/unwind_windows_x86.hpp @@ -68,6 +68,9 @@ typedef struct _DISPATCHER_CONTEXT { PVOID HandlerData; } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; +#if MSC_VER < 1500 + +/* Not needed for VS2008 compiler, comes from winnt.h. */ typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) ( IN PEXCEPTION_RECORD ExceptionRecord, IN ULONG64 EstablisherFrame, @@ -75,4 +78,6 @@ typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) ( IN OUT PDISPATCHER_CONTEXT DispatcherContext ); +#endif + #endif // AMD64 diff --git a/hotspot/src/share/vm/adlc/adlc.hpp b/hotspot/src/share/vm/adlc/adlc.hpp index 3d59b539b3e..6b92dfd8476 100644 --- a/hotspot/src/share/vm/adlc/adlc.hpp +++ b/hotspot/src/share/vm/adlc/adlc.hpp @@ -44,7 +44,7 @@ using namespace std; #error "Something is wrong with the detection of MSC_VER in the makefiles" #endif -#if _MSC_VER >= 1400 && !defined(_WIN64) +#if _MSC_VER >= 1400 #define strdup _strdup #endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 5b01157e9a4..7a4f8289246 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -107,7 +107,7 @@ void CMBitMapRO::mostly_disjoint_range_union(BitMap* from_bitmap, #ifndef PRODUCT bool CMBitMapRO::covers(ReservedSpace rs) const { // assert(_bm.map() == _virtual_space.low(), "map inconsistency"); - assert(((size_t)_bm.size() * (1 << _shifter)) == _bmWordSize, + assert(((size_t)_bm.size() * (size_t)(1 << _shifter)) == _bmWordSize, "size inconsistency"); return _bmStartWord == (HeapWord*)(rs.base()) && _bmWordSize == rs.size()>>LogHeapWordSize; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 5e54b091976..dce96d8df77 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -508,7 +508,7 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) : typedef PosParPRT* PosParPRTPtr; if (_max_fine_entries == 0) { assert(_mod_max_fine_entries_mask == 0, "Both or none."); - _max_fine_entries = (1 << G1LogRSRegionEntries); + _max_fine_entries = (size_t)(1 << G1LogRSRegionEntries); _mod_max_fine_entries_mask = _max_fine_entries - 1; #if SAMPLE_FOR_EVICTION assert(_fine_eviction_sample_size == 0 diff --git a/hotspot/src/share/vm/memory/blockOffsetTable.hpp b/hotspot/src/share/vm/memory/blockOffsetTable.hpp index 670dd86d79b..b812a243190 100644 --- a/hotspot/src/share/vm/memory/blockOffsetTable.hpp +++ b/hotspot/src/share/vm/memory/blockOffsetTable.hpp @@ -235,7 +235,7 @@ class BlockOffsetArray: public BlockOffsetTable { }; static size_t power_to_cards_back(uint i) { - return 1 << (LogBase * i); + return (size_t)(1 << (LogBase * i)); } static size_t power_to_words_back(uint i) { return power_to_cards_back(i) * N_words; diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 653309db0ac..3e7a7e6e0fe 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -163,9 +163,11 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #elif _MSC_VER == 1200 #define HOTSPOT_BUILD_COMPILER "MS VC++ 6.0" #elif _MSC_VER == 1310 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 7.1" + #define HOTSPOT_BUILD_COMPILER "MS VC++ 7.1 (VS2003)" #elif _MSC_VER == 1400 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0" + #define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0 (VS2005)" + #elif _MSC_VER == 1500 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 9.0 (VS2008)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp index 6b4804ec565..3e3c861df8e 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp @@ -162,7 +162,7 @@ inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { } // Visual Studio 2005 deprecates POSIX names - use ISO C++ names instead -#if _MSC_VER >= 1400 && !defined(_WIN64) +#if _MSC_VER >= 1400 #define open _open #define close _close #define read _read From 736e8a2d4b1abde961f575032b68c6a6f2ffc310 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Mon, 16 Mar 2009 17:48:01 -0700 Subject: [PATCH 12/43] 6815683: G1: SEGV during marking We should mark the regions that continue humongous regions as live if the first region is live. Reviewed-by: tonyp --- .../share/vm/gc_implementation/g1/concurrentMark.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 5b01157e9a4..3bc288dd04f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1232,7 +1232,16 @@ public: if (!_final && _regions_done == 0) _start_vtime_sec = os::elapsedVTime(); - if (hr->continuesHumongous()) return false; + if (hr->continuesHumongous()) { + HeapRegion* hum_start = hr->humongous_start_region(); + // If the head region of the humongous region has been determined + // to be alive, then all the tail regions should be marked + // such as well. + if (_region_bm->at(hum_start->hrs_index())) { + _region_bm->par_at_put(hr->hrs_index(), 1); + } + return false; + } HeapWord* nextTop = hr->next_top_at_mark_start(); HeapWord* start = hr->top_at_conc_mark_count(); From 61485906a3089e840f40798d171cdb7216bafcb1 Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Tue, 17 Mar 2009 11:28:24 -0700 Subject: [PATCH 13/43] 6814592: Legal notice repair needed in langtools/test/tools/javap/T4884240.java Reviewed-by: jjg --- langtools/test/tools/javap/T4884240.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langtools/test/tools/javap/T4884240.java b/langtools/test/tools/javap/T4884240.java index 93d4cc9361c..f2f36167760 100644 --- a/langtools/test/tools/javap/T4884240.java +++ b/langtools/test/tools/javap/T4884240.java @@ -16,7 +16,7 @@ * * 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-15301 USA. + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or From 5e669551737bc113012e37be789a8fcde0279d38 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 18 Mar 2009 13:25:02 -0700 Subject: [PATCH 14/43] 6772368: REGRESSION:tomcat crashed twice with JDK 7 Call make_block_at() with the original handler limits. Reviewed-by: never --- hotspot/src/share/vm/ci/ciMethodBlocks.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp index 4f7e52559e6..934cca6d99d 100644 --- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp +++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp @@ -284,6 +284,11 @@ ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth), // int ex_start = handler->start(); int ex_end = handler->limit(); + // ensure a block at the start of exception range and start of following code + (void) make_block_at(ex_start); + if (ex_end < _code_size) + (void) make_block_at(ex_end); + if (eb->is_handler()) { // Extend old handler exception range to cover additional range. int old_ex_start = eb->ex_start_bci(); @@ -295,10 +300,6 @@ ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth), eb->clear_exception_handler(); // Reset exception information } eb->set_exception_range(ex_start, ex_end); - // ensure a block at the start of exception range and start of following code - (void) make_block_at(ex_start); - if (ex_end < _code_size) - (void) make_block_at(ex_end); } } From 25de21d6203d0a6c6e007732f38f93fde5f6a93d Mon Sep 17 00:00:00 2001 From: Karen Kinnear Date: Wed, 18 Mar 2009 17:20:57 -0400 Subject: [PATCH 15/43] 4766230: Hotspot vtable inconsistencies cause core dumps. 6579515. 6582242 Reviewed-by: kamg, coleenp --- .../share/vm/classfile/classFileParser.cpp | 7 +- hotspot/src/share/vm/oops/instanceKlass.cpp | 19 ++ hotspot/src/share/vm/oops/instanceKlass.hpp | 3 + hotspot/src/share/vm/oops/klassVtable.cpp | 293 +++++++++--------- hotspot/src/share/vm/oops/klassVtable.hpp | 13 +- 5 files changed, 178 insertions(+), 157 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index c49e4a62306..b1f61dcf69a 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -2747,9 +2747,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, super_klass(), methods(), access_flags, - class_loader(), - class_name(), - local_interfaces()); + class_loader, + class_name, + local_interfaces(), + CHECK_(nullHandle)); // Size of Java itable (in words) itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 12adb12aba6..383b023c580 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1859,6 +1859,25 @@ bool instanceKlass::is_same_class_package(oop class_loader1, symbolOop class_nam } } +// Returns true iff super_method can be overridden by a method in targetclassname +// See JSL 3rd edition 8.4.6.1 +// Assumes name-signature match +// "this" is instanceKlass of super_method which must exist +// note that the instanceKlass of the method in the targetclassname has not always been created yet +bool instanceKlass::is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS) { + // Private methods can not be overridden + if (super_method->is_private()) { + return false; + } + // If super method is accessible, then override + if ((super_method->is_protected()) || + (super_method->is_public())) { + return true; + } + // Package-private methods are not inherited outside of package + assert(super_method->is_package_private(), "must be package private"); + return(is_same_class_package(targetclassloader(), targetclassname())); +} jint instanceKlass::compute_modifier_flags(TRAPS) const { klassOop k = as_klassOop(); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 8586ecba03b..b2a5c4b287e 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -303,6 +303,9 @@ class instanceKlass: public Klass { inner_class_next_offset = 4 }; + // method override check + bool is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS); + // package bool is_same_class_package(klassOop class2); bool is_same_class_package(oop classloader2, symbolOop classname2); diff --git a/hotspot/src/share/vm/oops/klassVtable.cpp b/hotspot/src/share/vm/oops/klassVtable.cpp index 9411e76509b..1efd00f7513 100644 --- a/hotspot/src/share/vm/oops/klassVtable.cpp +++ b/hotspot/src/share/vm/oops/klassVtable.cpp @@ -45,9 +45,10 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, klassOop super, objArrayOop methods, AccessFlags class_flags, - oop classloader, - symbolOop classname, - objArrayOop local_interfaces + Handle classloader, + symbolHandle classname, + objArrayOop local_interfaces, + TRAPS ) { No_Safepoint_Verifier nsv; @@ -64,9 +65,9 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, int len = methods->length(); for (int i = 0; i < len; i++) { assert(methods->obj_at(i)->is_method(), "must be a methodOop"); - methodOop m = methodOop(methods->obj_at(i)); + methodHandle mh(THREAD, methodOop(methods->obj_at(i))); - if (needs_new_vtable_entry(m, super, classloader, classname, class_flags)) { + if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, THREAD)) { vtable_length += vtableEntry::size(); // we need a new entry } } @@ -117,6 +118,7 @@ int klassVtable::initialize_from_super(KlassHandle super) { superVtable->copy_vtable_to(table()); #ifndef PRODUCT if (PrintVtables && Verbose) { + ResourceMark rm; tty->print_cr("copy vtable from %s to %s size %d", sk->internal_name(), klass()->internal_name(), _length); } #endif @@ -159,13 +161,13 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { int len = methods()->length(); int initialized = super_vtable_len; - // update_super_vtable can stop for gc - ensure using handles + // update_inherited_vtable can stop for gc - ensure using handles for (int i = 0; i < len; i++) { HandleMark hm(THREAD); assert(methods()->obj_at(i)->is_method(), "must be a methodOop"); methodHandle mh(THREAD, (methodOop)methods()->obj_at(i)); - bool needs_new_entry = update_super_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); + bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); if (needs_new_entry) { put_method_at(mh(), initialized); @@ -177,7 +179,7 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { // add miranda methods; it will also update the value of initialized fill_in_mirandas(initialized); - // In class hierachieswhere the accesibility is not increasing (i.e., going from private -> + // In class hierarchies where the accessibility is not increasing (i.e., going from private -> // package_private -> publicprotected), the vtable might actually be smaller than our initial // calculation. assert(initialized <= _length, "vtable initialization failed"); @@ -188,26 +190,49 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { } } -// Interates through the vtables to find the broadest access level. This -// will always be monotomic for valid Java programs - but not neccesarily -// for incompatible class files. -klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) { - // This vtable is not implementing the specific method - if (i >= length()) return acc_private; +// Called for cases where a method does not override its superclass' vtable entry +// For bytecodes not produced by javac together it is possible that a method does not override +// the superclass's method, but might indirectly override a super-super class's vtable entry +// If none found, return a null superk, else return the superk of the method this does override +instanceKlass* klassVtable::find_transitive_override(instanceKlass* initialsuper, methodHandle target_method, + int vtable_index, Handle target_loader, symbolHandle target_classname, Thread * THREAD) { + instanceKlass* superk = initialsuper; + while (superk != NULL && superk->super() != NULL) { + instanceKlass* supersuperklass = instanceKlass::cast(superk->super()); + klassVtable* ssVtable = supersuperklass->vtable(); + if (vtable_index < ssVtable->length()) { + methodOop super_method = ssVtable->method_at(vtable_index); +#ifndef PRODUCT + symbolHandle name(THREAD,target_method()->name()); + symbolHandle signature(THREAD,target_method()->signature()); + assert(super_method->name() == name() && super_method->signature() == signature(), "vtable entry name/sig mismatch"); +#endif + if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) { +#ifndef PRODUCT + if (PrintVtables && Verbose) { + ResourceMark rm(THREAD); + tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ", + supersuperklass->internal_name(), + _klass->internal_name(), (target_method() != NULL) ? + target_method()->name()->as_C_string() : "", vtable_index); + super_method->access_flags().print_on(tty); + tty->print("overriders flags: "); + target_method->access_flags().print_on(tty); + tty->cr(); + } +#endif /*PRODUCT*/ + break; // return found superk + } + } else { + // super class has no vtable entry here, stop transitive search + superk = (instanceKlass*)NULL; + break; + } + // if no override found yet, continue to search up + superk = instanceKlass::cast(superk->super()); + } - // Compute AccessType for current method. public or protected we are done. - methodOop m = method_at(i); - if (m->is_protected() || m->is_public()) return acc_publicprotected; - - AccessType acc = m->is_package_private() ? acc_package_private : acc_private; - - // Compute AccessType for method in super classes - klassOop super = klass()->super(); - AccessType super_acc = (super != NULL) ? instanceKlass::cast(klass()->super())->vtable()->vtable_accessibility_at(i) - : acc_private; - - // Merge - return (AccessType)MAX2((int)acc, (int)super_acc); + return superk; } @@ -215,7 +240,8 @@ klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) { // OR return true if a new vtable entry is required // Only called for instanceKlass's, i.e. not for arrays // If that changed, could not use _klass as handle for klass -bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) { +bool klassVtable::update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, + bool checkconstraints, TRAPS) { ResourceMark rm; bool allocate_new = true; assert(klass->oop_is_instance(), "must be instanceKlass"); @@ -242,58 +268,35 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ } // private methods always have a new entry in the vtable + // specification interpretation since classic has + // private methods not overriding if (target_method()->is_private()) { return allocate_new; } // search through the vtable and update overridden entries // Since check_signature_loaders acquires SystemDictionary_lock - // which can block for gc, once we are in this loop, use handles, not - // unhandled oops unless they are reinitialized for each loop - // handles for name, signature, klass, target_method - // not for match_method, holder + // which can block for gc, once we are in this loop, use handles + // For classfiles built with >= jdk7, we now look for transitive overrides symbolHandle name(THREAD,target_method()->name()); symbolHandle signature(THREAD,target_method()->signature()); + Handle target_loader(THREAD, _klass->class_loader()); + symbolHandle target_classname(THREAD, _klass->name()); for(int i = 0; i < super_vtable_len; i++) { - methodOop match_method = method_at(i); + methodOop super_method = method_at(i); // Check if method name matches - if (match_method->name() == name() && match_method->signature() == signature()) { + if (super_method->name() == name() && super_method->signature() == signature()) { - instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder())); + // get super_klass for method_holder for the found method + instanceKlass* super_klass = instanceKlass::cast(super_method->method_holder()); - // Check if the match_method is accessable from current class - - bool same_package_init = false; - bool same_package_flag = false; - bool simple_match = match_method->is_public() || match_method->is_protected(); - if (!simple_match) { - same_package_init = true; - same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name()); - - simple_match = match_method->is_package_private() && same_package_flag; - } - // match_method is the superclass' method. Note we can't override - // and shouldn't access superclass' ACC_PRIVATE methods - // (although they have been copied into our vtable) - // A simple form of this statement is: - // if ( (match_method->is_public() || match_method->is_protected()) || - // (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) { - // - // The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive. - if (simple_match) { - // Check if target_method and match_method has same level of accessibility. The accesibility of the - // match method is the "most-general" visibility of all entries at it's particular vtable index for - // all superclasses. This check must be done before we override the current entry in the vtable. - AccessType at = vtable_accessibility_at(i); - bool same_access = false; - - if ( (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected()) - || (at == acc_package_private && (target_method()->is_package_private() && - (( same_package_init && same_package_flag) || - (!same_package_init && holder->is_same_class_package(_klass->class_loader(), _klass->name()))))))) { - same_access = true; - } + if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) || + ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) + && ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader, + target_classname, THREAD)) != (instanceKlass*)NULL))) { + // overriding, so no new entry + allocate_new = false; if (checkconstraints) { // Override vtable entry if passes loader constraint check @@ -302,15 +305,12 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ // have already made any needed loader constraints. // Since loader constraints are transitive, it is enough // to link to the first super, and we get all the others. - symbolHandle signature(THREAD, target_method()->signature()); - Handle this_loader(THREAD, _klass->class_loader()); - instanceKlassHandle super_klass(THREAD, _klass->super()); Handle super_loader(THREAD, super_klass->class_loader()); - if (this_loader() != super_loader()) { + if (target_loader() != super_loader()) { ResourceMark rm(THREAD); char* failed_type_name = - SystemDictionary::check_signature_loaders(signature, this_loader, + SystemDictionary::check_signature_loaders(signature, target_loader, super_loader, true, CHECK_(false)); if (failed_type_name != NULL) { @@ -320,7 +320,7 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ "(instance of %s), have different Class objects for the type " "%s used in the signature"; char* sig = target_method()->name_and_sig_as_C_string(); - const char* loader1 = SystemDictionary::loader_name(this_loader()); + const char* loader1 = SystemDictionary::loader_name(target_loader()); char* current = _klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(super_loader()); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + @@ -331,59 +331,46 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_ THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false); } } - } + } + put_method_at(target_method(), i); - - - if (same_access) { - // target and match has same accessiblity - share entry - allocate_new = false; - target_method()->set_vtable_index(i); + target_method()->set_vtable_index(i); #ifndef PRODUCT - if (PrintVtables && Verbose) { - AccessType targetacc; - if (target_method()->is_protected() || - target_method()->is_public()) { - targetacc = acc_publicprotected; - } else { - targetacc = target_method()->is_package_private() ? acc_package_private : acc_private; - } - tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x", - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", i, - at, targetacc); - } -#endif /*PRODUCT*/ - } else { -#ifndef PRODUCT - if (PrintVtables && Verbose) { - AccessType targetacc; - if (target_method()->is_protected() || - target_method()->is_public()) { - targetacc = acc_publicprotected; - } else { - targetacc = target_method()->is_package_private() ? acc_package_private : acc_private; - } - tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x", - allocate_new ? "+ new" : "only", - _klass->internal_name(), (target_method() != NULL) ? - target_method()->name()->as_C_string() : "", i, - at, targetacc); - } -#endif /*PRODUCT*/ + if (PrintVtables && Verbose) { + tty->print("overriding with %s::%s index %d, original flags: ", + _klass->internal_name(), (target_method() != NULL) ? + target_method()->name()->as_C_string() : "", i); + super_method->access_flags().print_on(tty); + tty->print("overriders flags: "); + target_method->access_flags().print_on(tty); + tty->cr(); } +#endif /*PRODUCT*/ + } else { + // allocate_new = true; default. We might override one entry, + // but not override another. Once we override one, not need new +#ifndef PRODUCT + if (PrintVtables && Verbose) { + tty->print("NOT overriding with %s::%s index %d, original flags: ", + _klass->internal_name(), (target_method() != NULL) ? + target_method()->name()->as_C_string() : "", i); + super_method->access_flags().print_on(tty); + tty->print("overriders flags: "); + target_method->access_flags().print_on(tty); + tty->cr(); + } +#endif /*PRODUCT*/ } } } return allocate_new; } - - void klassVtable::put_method_at(methodOop m, int index) { assert(m->is_oop_or_null(), "Not an oop or null"); #ifndef PRODUCT if (PrintVtables && Verbose) { + ResourceMark rm; tty->print_cr("adding %s::%s at index %d", _klass->internal_name(), (m != NULL) ? m->name()->as_C_string() : "", index); } @@ -397,19 +384,23 @@ void klassVtable::put_method_at(methodOop m, int index) { // by "classloader" and "classname". // NOTE: The logic used here is very similar to the one used for computing // the vtables indices for a method. We cannot directly use that function because, -// when the Universe is boostrapping, a super's vtable might not be initialized. -bool klassVtable::needs_new_vtable_entry(methodOop target_method, +// we allocate the instanceKlass at load time, and that requires that the +// superclass has been loaded. +// However, the vtable entries are filled in at link time, and therefore +// the superclass' vtable may not yet have been filled in. +bool klassVtable::needs_new_vtable_entry(methodHandle target_method, klassOop super, - oop classloader, - symbolOop classname, - AccessFlags class_flags) { - if ((class_flags.is_final() || target_method->is_final()) || + Handle classloader, + symbolHandle classname, + AccessFlags class_flags, + TRAPS) { + if ((class_flags.is_final() || target_method()->is_final()) || // a final method never needs a new entry; final methods can be statically // resolved and they have to be present in the vtable only if they override // a super's method, in which case they re-use its entry - (target_method->is_static()) || + (target_method()->is_static()) || // static methods don't need to be in vtable - (target_method->name() == vmSymbols::object_initializer_name()) + (target_method()->name() == vmSymbols::object_initializer_name()) // is never called dynamically-bound ) { return false; @@ -421,55 +412,58 @@ bool klassVtable::needs_new_vtable_entry(methodOop target_method, } // private methods always have a new entry in the vtable - if (target_method->is_private()) { + // specification interpretation since classic has + // private methods not overriding + if (target_method()->is_private()) { return true; } // search through the super class hierarchy to see if we need // a new entry - symbolOop name = target_method->name(); - symbolOop signature = target_method->signature(); + ResourceMark rm; + symbolOop name = target_method()->name(); + symbolOop signature = target_method()->signature(); klassOop k = super; - methodOop match_method = NULL; + methodOop super_method = NULL; instanceKlass *holder = NULL; + methodOop recheck_method = NULL; while (k != NULL) { // lookup through the hierarchy for a method with matching name and sign. - match_method = instanceKlass::cast(k)->lookup_method(name, signature); - if (match_method == NULL) { + super_method = instanceKlass::cast(k)->lookup_method(name, signature); + if (super_method == NULL) { break; // we still have to search for a matching miranda method } // get the class holding the matching method - holder = instanceKlass::cast(match_method->method_holder()); - - if (!match_method->is_static()) { // we want only instance method matches - if ((target_method->is_public() || target_method->is_protected()) && - (match_method->is_public() || match_method->is_protected())) { - // target and match are public/protected; we do not need a new entry - return false; - } - - if (target_method->is_package_private() && - match_method->is_package_private() && - holder->is_same_class_package(classloader, classname)) { - // target and match are P private; we do not need a new entry + // make sure you use that class for is_override + instanceKlass* superk = instanceKlass::cast(super_method->method_holder()); + // we want only instance method matches + // pretend private methods are not in the super vtable + // since we do override around them: e.g. a.m pub/b.m private/c.m pub, + // ignore private, c.m pub does override a.m pub + // For classes that were not javac'd together, we also do transitive overriding around + // methods that have less accessibility + if ((!super_method->is_static()) && + (!super_method->is_private())) { + if (superk->is_override(super_method, classloader, classname, THREAD)) { return false; + // else keep looking for transitive overrides } } - k = holder->super(); // haven't found a match yet; continue to look + // Start with lookup result and continue to search up + k = superk->super(); // haven't found an override match yet; continue to look } // if the target method is public or protected it may have a matching // miranda method in the super, whose entry it should re-use. - if (target_method->is_public() || target_method->is_protected()) { - instanceKlass *sk = instanceKlass::cast(super); - if (sk->has_miranda_methods()) { - if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) { - return false; // found a matching miranda; we do not need a new entry - } + // Actually, to handle cases that javac would not generate, we need + // this check for all access permissions. + instanceKlass *sk = instanceKlass::cast(super); + if (sk->has_miranda_methods()) { + if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) { + return false; // found a matching miranda; we do not need a new entry } } - return true; // found no match; we need a new entry } @@ -884,7 +878,7 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) { _klass->name()->as_C_string()); - // Interate through all interfaces + // Iterate through all interfaces int i; for(i = 0; i < num_interfaces; i++) { itableOffsetEntry* ioe = offset_entry(i); @@ -1012,6 +1006,7 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } + break; } ime++; } diff --git a/hotspot/src/share/vm/oops/klassVtable.hpp b/hotspot/src/share/vm/oops/klassVtable.hpp index 2ef1848f59e..889d9733646 100644 --- a/hotspot/src/share/vm/oops/klassVtable.hpp +++ b/hotspot/src/share/vm/oops/klassVtable.hpp @@ -70,8 +70,9 @@ class klassVtable : public ResourceObj { // conputes vtable length (in words) and the number of miranda methods static void compute_vtable_size_and_num_mirandas(int &vtable_length, int &num_miranda_methods, klassOop super, objArrayOop methods, - AccessFlags class_flags, oop classloader, - symbolOop classname, objArrayOop local_interfaces); + AccessFlags class_flags, Handle classloader, + symbolHandle classname, objArrayOop local_interfaces, + TRAPS); // RedefineClasses() API support: // If any entry of this vtable points to any of old_methods, @@ -111,14 +112,16 @@ class klassVtable : public ResourceObj { protected: friend class vtableEntry; private: + enum { VTABLE_TRANSITIVE_OVERRIDE_VERSION = 51 } ; void copy_vtable_to(vtableEntry* start); int initialize_from_super(KlassHandle super); int index_of(methodOop m, int len) const; // same as index_of, but search only up to len void put_method_at(methodOop m, int index); - static bool needs_new_vtable_entry(methodOop m, klassOop super, oop classloader, symbolOop classname, AccessFlags access_flags); - AccessType vtable_accessibility_at(int i); + static bool needs_new_vtable_entry(methodHandle m, klassOop super, Handle classloader, symbolHandle classname, AccessFlags access_flags, TRAPS); - bool update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS); + bool update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS); + instanceKlass* find_transitive_override(instanceKlass* initialsuper, methodHandle target_method, int vtable_index, + Handle target_loader, symbolHandle target_classname, Thread* THREAD); // support for miranda methods bool is_miranda_entry_at(int i); From fd5bc7200533a2c35dcaafd04df7008dcb9c64fd Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Thu, 19 Mar 2009 19:00:54 -0700 Subject: [PATCH 16/43] 6786688: Javadoc HTML WCAG 2.0 accessibility issues in standard doclet - Table must have captions and headers Reviewed-by: jjg --- .../formats/html/AbstractMemberWriter.java | 32 +- .../html/AbstractPackageIndexWriter.java | 12 +- ...nnotationTypeOptionalMemberWriterImpl.java | 24 +- ...nnotationTypeRequiredMemberWriterImpl.java | 24 +- .../doclets/formats/html/ClassUseWriter.java | 133 ++--- .../html/ConstantsSummaryWriterImpl.java | 21 +- .../formats/html/ConstructorWriterImpl.java | 31 +- .../formats/html/DeprecatedListWriter.java | 34 +- .../formats/html/EnumConstantWriterImpl.java | 20 +- .../doclets/formats/html/FieldWriterImpl.java | 21 +- .../formats/html/HtmlDocletWriter.java | 43 ++ .../formats/html/MethodWriterImpl.java | 21 +- .../formats/html/NestedClassWriterImpl.java | 32 +- .../formats/html/PackageIndexFrameWriter.java | 2 +- .../formats/html/PackageIndexWriter.java | 17 +- .../formats/html/PackageUseWriter.java | 21 +- .../formats/html/PackageWriterImpl.java | 27 +- .../formats/html/StylesheetWriter.java | 8 + .../formats/html/SubWriterHolderWriter.java | 10 +- .../formats/html/markup/HtmlWriter.java | 96 ++++ .../html/resources/standard.properties | 12 + .../toolkit/PackageSummaryWriter.java | 2 +- .../builders/PackageSummaryBuilder.java | 79 ++- .../toolkit/resources/doclets.properties | 33 ++ .../javadoc/testHeadings/TestHeadings.java | 31 +- .../testHtmlStrongTag/TestHtmlStrongTag.java | 13 +- .../testHtmlTableTags/TestHtmlTableTags.java | 478 ++++++++++++++++++ .../javadoc/testHtmlTableTags/pkg1/C1.java | 81 +++ .../javadoc/testHtmlTableTags/pkg1/I1.java | 48 ++ .../testHtmlTableTags/pkg1/package-info.java | 27 + .../javadoc/testHtmlTableTags/pkg2/C2.java | 73 +++ .../javadoc/testHtmlTableTags/pkg2/C3.java | 40 ++ .../javadoc/testHtmlTableTags/pkg2/C4.java | 35 ++ .../testHtmlTableTags/pkg2/package-info.java | 27 + .../TestNewLanguageFeatures.java | 274 +++++++--- .../TestSummaryHeading.java | 3 +- 36 files changed, 1659 insertions(+), 226 deletions(-) create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java create mode 100644 langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java index d6c298f13da..273b42558ed 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java @@ -60,7 +60,11 @@ public abstract class AbstractMemberWriter { /*** abstracts ***/ - public abstract void printSummaryLabel(ClassDoc cd); + public abstract void printSummaryLabel(); + + public abstract void printTableSummary(); + + public abstract void printSummaryTableHeader(ProgramElementDoc member); public abstract void printInheritedSummaryLabel(ClassDoc cd); @@ -342,12 +346,13 @@ public abstract class AbstractMemberWriter { * format for listing the API. Call methods from the sub-class to complete * the generation. */ - protected void printDeprecatedAPI(List deprmembers, String headingKey) { + protected void printDeprecatedAPI(List deprmembers, String headingKey, String tableSummary, String[] tableHeader) { if (deprmembers.size() > 0) { - writer.tableIndexSummary(); - writer.tableHeaderStart("#CCCCFF"); - writer.strongText(headingKey); - writer.tableHeaderEnd(); + writer.tableIndexSummary(tableSummary); + writer.tableCaptionStart(); + writer.printText(headingKey); + writer.tableCaptionEnd(); + writer.summaryTableHeader(tableHeader, "col"); for (int i = 0; i < deprmembers.size(); i++) { ProgramElementDoc member =(ProgramElementDoc)deprmembers.get(i); writer.trBgcolorStyle("white", "TableRowColor"); @@ -370,19 +375,26 @@ public abstract class AbstractMemberWriter { /** * Print use info. */ - protected void printUseInfo(List mems, String heading) { + protected void printUseInfo(List mems, String heading, String tableSummary) { if (mems == null) { return; } List members = mems; + boolean printedUseTableHeader = false; if (members.size() > 0) { - writer.tableIndexSummary(); - writer.tableUseInfoHeaderStart("#CCCCFF"); + writer.tableIndexSummary(tableSummary); + writer.tableSubCaptionStart(); writer.print(heading); - writer.tableHeaderEnd(); + writer.tableCaptionEnd(); for (Iterator it = members.iterator(); it.hasNext(); ) { ProgramElementDoc pgmdoc = it.next(); ClassDoc cd = pgmdoc.containingClass(); + if (!printedUseTableHeader) { + // Passing ProgramElementDoc helps decides printing + // interface or class header in case of nested classes. + this.printSummaryTableHeader(pgmdoc); + printedUseTableHeader = true; + } writer.printSummaryLinkType(this, pgmdoc); if (cd != null && !(pgmdoc instanceof ConstructorDoc) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java index 36742cf7f95..b743aeacd2d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java @@ -35,6 +35,7 @@ import java.util.*; * generate overview-frame.html as well as overview-summary.html. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { @@ -61,7 +62,7 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { protected abstract void printOverviewHeader(); - protected abstract void printIndexHeader(String text); + protected abstract void printIndexHeader(String text, String tableSummary); protected abstract void printIndexRow(PackageDoc pkg); @@ -101,7 +102,10 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * Generate the frame or non-frame package index. */ protected void generateIndex() { - printIndexContents(packages, "doclet.Package_Summary"); + printIndexContents(packages, "doclet.Package_Summary", + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Package_Summary"), + configuration.getText("doclet.packages"))); } /** @@ -111,10 +115,10 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * @param packages Array of packages to be documented. * @param text String which will be used as the heading. */ - protected void printIndexContents(PackageDoc[] packages, String text) { + protected void printIndexContents(PackageDoc[] packages, String text, String tableSummary) { if (packages.length > 0) { Arrays.sort(packages); - printIndexHeader(text); + printIndexHeader(text, tableSummary); printAllClassesPackagesLink(); for(int i = 0; i < packages.length; i++) { if (packages[i] != null) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java index 1442e3ccf0c..5bf2f8e19fe 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java @@ -34,6 +34,7 @@ import com.sun.tools.doclets.internal.toolkit.*; * Writes annotation type optional member documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class AnnotationTypeOptionalMemberWriterImpl extends AnnotationTypeRequiredMemberWriterImpl @@ -89,8 +90,27 @@ public class AnnotationTypeOptionalMemberWriterImpl extends /** * {@inheritDoc} */ - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Annotation_Type_Optional_Member_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Annotation_Type_Optional_Member_Summary"); + } + + /** + * {@inheritDoc} + */ + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Annotation_Type_Optional_Member_Summary"), + configuration().getText("doclet.annotation_type_optional_members"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Annotation_Type_Optional_Member"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java index 01e517ce426..9b745c68187 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java @@ -34,6 +34,7 @@ import com.sun.tools.doclets.internal.toolkit.*; * Writes annotation type required member documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter implements AnnotationTypeRequiredMemberWriter, MemberSummaryWriter { @@ -178,8 +179,27 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter /** * {@inheritDoc} */ - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Annotation_Type_Required_Member_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Annotation_Type_Required_Member_Summary"); + } + + /** + * {@inheritDoc} + */ + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Annotation_Type_Required_Member_Summary"), + configuration().getText("doclet.annotation_type_required_members"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Annotation_Type_Required_Member"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java index 73d957e3c4e..6baec7af9d8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java @@ -34,6 +34,7 @@ import java.util.*; * Generate class usage information. * * @author Robert G. Field + * @author Bhavesh Patel (Modified) */ public class ClassUseWriter extends SubWriterHolderWriter { @@ -65,6 +66,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { final ConstructorWriterImpl constrSubWriter; final FieldWriterImpl fieldSubWriter; final NestedClassWriterImpl classSubWriter; + // Summary for various use tables. + final String classUseTableSummary; + final String subclassUseTableSummary; + final String subinterfaceUseTableSummary; + final String fieldUseTableSummary; + final String methodUseTableSummary; + final String constructorUseTableSummary; /** @@ -116,6 +124,18 @@ public class ClassUseWriter extends SubWriterHolderWriter { constrSubWriter = new ConstructorWriterImpl(this); fieldSubWriter = new FieldWriterImpl(this); classSubWriter = new NestedClassWriterImpl(this); + classUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes")); + subclassUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subclasses")); + subinterfaceUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subinterfaces")); + fieldUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.fields")); + methodUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.methods")); + constructorUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.constructors")); } /** @@ -213,12 +233,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { } protected void generatePackageList() throws IOException { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_Packages.that.use.0", getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false))); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); for (Iterator it = pkgSet.iterator(); it.hasNext();) { PackageDoc pkg = it.next(); @@ -234,12 +255,13 @@ public class ClassUseWriter extends SubWriterHolderWriter { pkgToPackageAnnotations == null || pkgToPackageAnnotations.size() == 0) return; - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_PackageAnnotation", getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false))); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); for (Iterator it = pkgToPackageAnnotations.iterator(); it.hasNext();) { PackageDoc pkg = it.next(); trBgcolorStyle("white", "TableRowColor"); @@ -300,83 +322,68 @@ public class ClassUseWriter extends SubWriterHolderWriter { LinkInfoImpl.CONTEXT_CLASS_USE_HEADER, classdoc, false)); String pkgLink = getPackageLink(pkg, Util.getPackageName(pkg), false); classSubWriter.printUseInfo(pkgToClassAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_Annotation", classLink, - pkgLink)); - + configuration.getText("doclet.ClassUse_Annotation", classLink, + pkgLink), classUseTableSummary); classSubWriter.printUseInfo(pkgToClassTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_TypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_TypeParameter", classLink, + pkgLink), classUseTableSummary); classSubWriter.printUseInfo(pkgToSubclass.get(pkg.name()), - configuration.getText("doclet.ClassUse_Subclass", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Subclass", classLink, + pkgLink), subclassUseTableSummary); classSubWriter.printUseInfo(pkgToSubinterface.get(pkg.name()), - configuration.getText("doclet.ClassUse_Subinterface", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Subinterface", classLink, + pkgLink), subinterfaceUseTableSummary); classSubWriter.printUseInfo(pkgToImplementingClass.get(pkg.name()), - configuration.getText("doclet.ClassUse_ImplementingClass", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ImplementingClass", classLink, + pkgLink), classUseTableSummary); fieldSubWriter.printUseInfo(pkgToField.get(pkg.name()), - configuration.getText("doclet.ClassUse_Field", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_Field", classLink, + pkgLink), fieldUseTableSummary); fieldSubWriter.printUseInfo(pkgToFieldAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_FieldAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_FieldAnnotations", classLink, + pkgLink), fieldUseTableSummary); fieldSubWriter.printUseInfo(pkgToFieldTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_FieldTypeParameter", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_FieldTypeParameter", classLink, + pkgLink), fieldUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodAnnotations", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodAnnotations", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodParameterAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodParameterAnnotations", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodParameterAnnotations", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodTypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodTypeParameter", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodReturn.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodReturn", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodReturn", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodReturnTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodReturnTypeParameter", classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodReturnTypeParameter", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodArgs.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodArgs", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodArgs", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodArgTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodArgsTypeParameters", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodArgsTypeParameters", classLink, + pkgLink), methodUseTableSummary); methodSubWriter.printUseInfo(pkgToMethodThrows.get(pkg.name()), - configuration.getText("doclet.ClassUse_MethodThrows", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_MethodThrows", classLink, + pkgLink), methodUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorAnnotations", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorParameterAnnotations.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorParameterAnnotations", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorParameterAnnotations", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorArgs.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorArgs", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorArgs", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorArgTypeParameter.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorArgsTypeParameters", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorArgsTypeParameters", classLink, + pkgLink), constructorUseTableSummary); constrSubWriter.printUseInfo(pkgToConstructorThrows.get(pkg.name()), - configuration.getText("doclet.ClassUse_ConstructorThrows", - classLink, - pkgLink)); + configuration.getText("doclet.ClassUse_ConstructorThrows", classLink, + pkgLink), constructorUseTableSummary); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java index d64b2656d59..ddf51063a0a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -35,6 +35,7 @@ import java.util.*; * Write the Constants Summary Page in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.4 */ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter @@ -50,6 +51,10 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter */ private ClassDoc currentClassDoc; + private final String constantsTableSummary; + + private final String[] constantsTableHeader; + /** * Construct a ConstantsSummaryWriter. * @param configuration the configuration used in this run @@ -59,6 +64,13 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter throws IOException { super(configuration, ConfigurationImpl.CONSTANTS_FILE_NAME); this.configuration = configuration; + constantsTableSummary = configuration.getText("doclet.Constants_Table_Summary", + configuration.getText("doclet.Constants_Summary")); + constantsTableHeader = new String[] { + getModifierTypeHeader(), + configuration.getText("doclet.ConstantField"), + configuration.getText("doclet.Value") + }; } /** @@ -151,12 +163,11 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter * @param classStr the heading to print. */ protected void writeClassName(String classStr) { - table(1, 3, 0); - trBgcolorStyle("#EEEEFF", "TableSubHeadingColor"); - thAlignColspan("left", 3); + table(1, 3, 0, constantsTableSummary); + tableSubCaptionStart(); write(classStr); - thEnd(); - trEnd(); + tableCaptionEnd(); + summaryTableHeader(constantsTableHeader, "col"); } private void tableFooter(boolean isHeader) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java index cb5adbdeeaf..cc38edd8f2c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * * @author Robert Field * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter implements ConstructorWriter, MemberSummaryWriter { @@ -211,8 +212,34 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter this.foundNonPubConstructor = foundNonPubConstructor; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Constructor_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Constructor_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Constructor_Summary"), + configuration().getText("doclet.constructors"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header; + if (foundNonPubConstructor) { + header = new String[] { + configuration().getText("doclet.Modifier"), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Constructor"), + configuration().getText("doclet.Description")) + }; + } + else { + header = new String[] { + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Constructor"), + configuration().getText("doclet.Description")) + }; + } + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java index 68b04a7d72a..46c257b4b47 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/DeprecatedListWriter.java @@ -35,6 +35,7 @@ import java.io.*; * * @see java.util.List * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class DeprecatedListWriter extends SubWriterHolderWriter { @@ -55,6 +56,28 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { "doclet.Deprecated_Annotation_Type_Members" }; + private static final String[] SUMMARY_KEYS = new String[] { + "doclet.deprecated_interfaces", "doclet.deprecated_classes", + "doclet.deprecated_enums", "doclet.deprecated_exceptions", + "doclet.deprecated_errors", + "doclet.deprecated_annotation_types", + "doclet.deprecated_fields", + "doclet.deprecated_methods", "doclet.deprecated_constructors", + "doclet.deprecated_enum_constants", + "doclet.deprecated_annotation_type_members" + }; + + private static final String[] HEADER_KEYS = new String[] { + "doclet.Interface", "doclet.Class", + "doclet.Enum", "doclet.Exceptions", + "doclet.Errors", + "doclet.AnnotationType", + "doclet.Field", + "doclet.Method", "doclet.Constructor", + "doclet.Enum_Constant", + "doclet.Annotation_Type_Member" + }; + private AbstractMemberWriter[] writers; private ConfigurationImpl configuration; @@ -119,11 +142,20 @@ public class DeprecatedListWriter extends SubWriterHolderWriter { ulEnd(); println(); + String memberTableSummary; + String[] memberTableHeader = new String[1]; for (int i = 0; i < DeprecatedAPIListBuilder.NUM_TYPES; i++) { if (deprapi.hasDocumentation(i)) { writeAnchor(deprapi, i); + memberTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText(HEADING_KEYS[i]), + configuration.getText(SUMMARY_KEYS[i])); + memberTableHeader[0] = configuration.getText("doclet.0_and_1", + configuration.getText(HEADER_KEYS[i]), + configuration.getText("doclet.Description")); writers[i].printDeprecatedAPI(deprapi.getList(i), - HEADING_KEYS[i]); + HEADING_KEYS[i], memberTableSummary, memberTableHeader); } } printDeprecatedFooter(); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java index 1d5b4ffbd29..2e7c08bcfb5 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/EnumConstantWriterImpl.java @@ -35,6 +35,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * Writes enum constant documentation in HTML format. * * @author Jamie Ho + * @author Bhavesh Patel (Modified) */ public class EnumConstantWriterImpl extends AbstractMemberWriter implements EnumConstantWriter, MemberSummaryWriter { @@ -194,8 +195,23 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter return VisibleMemberMap.ENUM_CONSTANTS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Enum_Constant_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Enum_Constant_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Enum_Constant_Summary"), + configuration().getText("doclet.enum_constants"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Enum_Constant"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java index bd97166b8ab..0f3b1cc0ef3 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/FieldWriterImpl.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class FieldWriterImpl extends AbstractMemberWriter implements FieldWriter, MemberSummaryWriter { @@ -236,8 +237,24 @@ public class FieldWriterImpl extends AbstractMemberWriter return VisibleMemberMap.FIELDS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Field_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Field_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Field_Summary"), + configuration().getText("doclet.fields"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Field"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 689661b2e54..74d287dd79b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -784,6 +784,15 @@ public class HtmlDocletWriter extends HtmlDocWriter { table(1, "100%", 3, 0); } + /** + * Print the Html table tag for the index summary tables. + * + * @param summary the summary for the table tag summary attribute. + */ + public void tableIndexSummary(String summary) { + table(1, "100%", 3, 0, summary); + } + /** * Same as {@link #tableIndexSummary()}. */ @@ -799,6 +808,40 @@ public class HtmlDocletWriter extends HtmlDocWriter { print(""); } + /** + * Print table caption. + */ + public void tableCaptionStart() { + captionStyle("TableCaption"); + } + + /** + * Print table sub-caption. + */ + public void tableSubCaptionStart() { + captionStyle("TableSubCaption"); + } + + /** + * Print table caption end tags. + */ + public void tableCaptionEnd() { + captionEnd(); + } + + /** + * Print summary table header. + */ + public void summaryTableHeader(String[] header, String scope) { + tr(); + for ( int i=0; i < header.length; i++ ) { + thScopeNoWrap("TableHeader", scope); + print(header[i]); + thEnd(); + } + trEnd(); + } + /** * Prine table header information about color, column span and the font. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java index a74283179b3..c5500a34e4c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java @@ -38,6 +38,7 @@ import com.sun.tools.doclets.internal.toolkit.taglets.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class MethodWriterImpl extends AbstractExecutableMemberWriter implements MethodWriter, MemberSummaryWriter { @@ -255,8 +256,24 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter return VisibleMemberMap.METHODS; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Method_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Method_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Method_Summary"), + configuration().getText("doclet.methods"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Method"), + configuration().getText("doclet.Description")) + }; + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java index 23803455ad1..c133708c108 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/NestedClassWriterImpl.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * @author Robert Field * @author Atul M Dambalkar * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) */ public class NestedClassWriterImpl extends AbstractMemberWriter implements MemberSummaryWriter { @@ -147,8 +148,35 @@ public class NestedClassWriterImpl extends AbstractMemberWriter return VisibleMemberMap.INNERCLASSES; } - public void printSummaryLabel(ClassDoc cd) { - writer.strongText("doclet.Nested_Class_Summary"); + public void printSummaryLabel() { + writer.printText("doclet.Nested_Class_Summary"); + } + + public void printTableSummary() { + writer.tableIndexSummary(configuration().getText("doclet.Member_Table_Summary", + configuration().getText("doclet.Nested_Class_Summary"), + configuration().getText("doclet.nested_classes"))); + } + + public void printSummaryTableHeader(ProgramElementDoc member) { + String[] header; + if (member.isInterface()) { + header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Interface"), + configuration().getText("doclet.Description")) + }; + } + else { + header = new String[] { + writer.getModifierTypeHeader(), + configuration().getText("doclet.0_and_1", + configuration().getText("doclet.Class"), + configuration().getText("doclet.Description")) + }; + } + writer.summaryTableHeader(header, "col"); } public void printSummaryAnchor(ClassDoc cd) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java index ebc7118ab5d..035c48cfa80 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java @@ -114,7 +114,7 @@ public class PackageIndexFrameWriter extends AbstractPackageIndexWriter { * * @param text Text string will not be used in this method. */ - protected void printIndexHeader(String text) { + protected void printIndexHeader(String text, String tableSummary) { printTableHeader(false); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java index 4562e6e9354..b785bf67c42 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java @@ -36,6 +36,7 @@ import java.util.*; * with the "pacakge-summary.html" file for the clicked package. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class PackageIndexWriter extends AbstractPackageIndexWriter { @@ -123,7 +124,10 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { List list = groupPackageMap.get(groupname); if (list != null && list.size() > 0) { printIndexContents(list.toArray(new PackageDoc[list.size()]), - groupname); + groupname, + configuration.getText("doclet.Member_Table_Summary", + groupname, + configuration.getText("doclet.packages"))); } } } @@ -149,11 +153,12 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { /** * Print Html tags for the table for this package index. */ - protected void printIndexHeader(String text) { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); - strong(text); - tableHeaderEnd(); + protected void printIndexHeader(String text, String tableSummary) { + tableIndexSummary(tableSummary); + tableCaptionStart(); + print(text); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java index a83cc3d70a0..d817ca5ad3b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java @@ -34,6 +34,7 @@ import java.util.*; * Generate package usage information. * * @author Robert G. Field + * @author Bhavesh Patel (Modified) */ public class PackageUseWriter extends SubWriterHolderWriter { @@ -131,11 +132,12 @@ public class PackageUseWriter extends SubWriterHolderWriter { } protected void generatePackageList() throws IOException { - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(useTableSummary); + tableCaptionStart(); printText("doclet.ClassUse_Packages.that.use.0", getPackageLink(pkgdoc, Util.getPackageName(pkgdoc), false)); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(packageTableHeader, "col"); Iterator it = usingPackageToUsedClasses.keySet().iterator(); while (it.hasNext()) { PackageDoc pkg = configuration.root.packageNamed(it.next()); @@ -147,6 +149,11 @@ public class PackageUseWriter extends SubWriterHolderWriter { } protected void generateClassList() throws IOException { + String[] classTableHeader = new String[] { + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description")) + }; Iterator itp = usingPackageToUsedClasses.keySet().iterator(); while (itp.hasNext()) { String packageName = itp.next(); @@ -154,12 +161,14 @@ public class PackageUseWriter extends SubWriterHolderWriter { if (usingPackage != null) { anchor(usingPackage.name()); } - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); + tableIndexSummary(configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes"))); + tableCaptionStart(); printText("doclet.ClassUse_Classes.in.0.used.by.1", getPackageLink(pkgdoc, Util.getPackageName(pkgdoc), false), getPackageLink(usingPackage,Util.getPackageName(usingPackage), false)); - tableHeaderEnd(); + tableCaptionEnd(); + summaryTableHeader(classTableHeader, "col"); Iterator itc = usingPackageToUsedClasses.get(packageName).iterator(); while (itc.hasNext()) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java index eca6d49bbbf..60aa692ce0f 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java @@ -38,6 +38,7 @@ import java.util.*; * class-kind will update the frame with the clicked class-kind page. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class PackageWriterImpl extends HtmlDocletWriter implements PackageSummaryWriter { @@ -107,14 +108,15 @@ public class PackageWriterImpl extends HtmlDocletWriter /** * {@inheritDoc} */ - public void writeClassesSummary(ClassDoc[] classes, String label) { + public void writeClassesSummary(ClassDoc[] classes, String label, String tableSummary, String[] tableHeader) { if(classes.length > 0) { Arrays.sort(classes); - tableIndexSummary(); + tableIndexSummary(tableSummary); boolean printedHeading = false; for (int i = 0; i < classes.length; i++) { if (!printedHeading) { - printFirstRow(label); + printTableCaption(label); + printFirstRow(tableHeader); printedHeading = true; } if (!Util.isCoreClass(classes[i]) || @@ -148,15 +150,24 @@ public class PackageWriterImpl extends HtmlDocletWriter } } + /** + * Print the table caption for the class-listing. + * + * @param label label for the Class kind listing. + */ + protected void printTableCaption(String label) { + tableCaptionStart(); + print(label); + tableCaptionEnd(); + } + /** * Print the table heading for the class-listing. * - * @param label Label for the Class kind listing. + * @param tableHeader table header string for the Class listing. */ - protected void printFirstRow(String label) { - tableHeaderStart("#CCCCFF"); - strong(label); - tableHeaderEnd(); + protected void printFirstRow(String[] tableHeader) { + summaryTableHeader(tableHeader, "col"); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java index 1384bbb2bd5..f6664f94c1c 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/StylesheetWriter.java @@ -33,6 +33,7 @@ import java.io.*; * Writes the style sheet for the doclet output. * * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class StylesheetWriter extends HtmlDocletWriter { @@ -115,6 +116,13 @@ public class StylesheetWriter extends HtmlDocletWriter { println("background-color:#FFFFFF; color:#000000}"); print(".NavBarCell3 { font-family: Arial, Helvetica, sans-serif; "); println("background-color:#FFFFFF; color:#000000}"); + + print("/* "); printText("doclet.Style_line_12"); println(" */"); + print(".TableCaption { background: #CCCCFF; color:#000000; text-align: left; font-size: 150%; font-weight: bold; border-left: 2px ridge; border-right: 2px ridge; border-top: 2px ridge; padding-left: 5px; }"); + print(" /* "); printText("doclet.Style_line_5"); println(" */"); + print(".TableSubCaption { background: #EEEEFF; color:#000000; text-align: left; font-weight: bold; border-left: 2px ridge; border-right: 2px ridge; border-top: 2px ridge; padding-left: 5px; }"); + print(" /* "); printText("doclet.Style_line_6"); println(" */"); + print(".TableHeader { text-align: center; font-size: 80%; font-weight: bold; }"); println(""); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java index f6b6b98b6e5..b1a2f868687 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java @@ -43,6 +43,7 @@ import java.io.*; * * @author Robert Field * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { @@ -72,10 +73,11 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter { public void printSummaryHeader(AbstractMemberWriter mw, ClassDoc cd) { mw.printSummaryAnchor(cd); - tableIndexSummary(); - tableHeaderStart("#CCCCFF"); - mw.printSummaryLabel(cd); - tableHeaderEnd(); + mw.printTableSummary(); + tableCaptionStart(); + mw.printSummaryLabel(); + tableCaptionEnd(); + mw.printSummaryTableHeader(cd); } public void printTableHeadingBackground(String str) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java index 4df4f5d6a0e..cad683d9fa4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java @@ -37,6 +37,7 @@ import com.sun.tools.doclets.internal.toolkit.util.*; * * @since 1.2 * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) */ public class HtmlWriter extends PrintWriter { @@ -66,6 +67,21 @@ public class HtmlWriter extends PrintWriter { */ protected boolean memberDetailsListPrinted; + /** + * Header for tables displaying packages and description.. + */ + protected final String[] packageTableHeader; + + /** + * Summary for use tables displaying class and package use. + */ + protected final String useTableSummary; + + /** + * Column header for class docs displaying Modifier and Type header. + */ + protected final String modifierTypeHeader; + /** * Constructor. * @@ -86,6 +102,15 @@ public class HtmlWriter extends PrintWriter { this.configuration = configuration; htmlFilename = filename; this.memberDetailsListPrinted = false; + packageTableHeader = new String[] { + configuration.getText("doclet.Package"), + configuration.getText("doclet.Description") + }; + useTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.packages")); + modifierTypeHeader = configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Modifier"), + configuration.getText("doclet.Type")); } /** @@ -802,6 +827,26 @@ public class HtmlWriter extends PrintWriter { "\" SUMMARY=\"\">"); } + /** + * Print HTML <TABLE BORDER="border" WIDTH="width" + * CELLPADDING="cellpadding" CELLSPACING="cellspacing" SUMMARY="summary"> tag. + * + * @param border Border size. + * @param width Width of the table. + * @param cellpadding Cellpadding for the table cells. + * @param cellspacing Cellspacing for the table cells. + * @param summary Table summary. + */ + public void table(int border, String width, int cellpadding, + int cellspacing, String summary) { + println(DocletConstants.NL + + ""); + } + /** * Print HTML <TABLE BORDER="border" CELLPADDING="cellpadding" * CELLSPACING="cellspacing"> tag. @@ -818,6 +863,23 @@ public class HtmlWriter extends PrintWriter { "\" SUMMARY=\"\">"); } + /** + * Print HTML <TABLE BORDER="border" CELLPADDING="cellpadding" + * CELLSPACING="cellspacing" SUMMARY="summary"> tag. + * + * @param border Border size. + * @param cellpadding Cellpadding for the table cells. + * @param cellspacing Cellspacing for the table cells. + * @param summary Table summary. + */ + public void table(int border, int cellpadding, int cellspacing, String summary) { + println(DocletConstants.NL + + "
"); + } + /** * Print HTML <TABLE BORDER="border" WIDTH="width"> * @@ -912,6 +974,23 @@ public class HtmlWriter extends PrintWriter { println("-->"); } + /** + * Print <CAPTION CLASS="stylename"> tag. Adds a newline character + * at the end. + * + * @param stylename style to be applied. + */ + public void captionStyle(String stylename) { + println(""); + } + /** * Print <TR BGCOLOR="color" CLASS="stylename"> tag. Adds a newline character * at the end. @@ -952,6 +1031,23 @@ public class HtmlWriter extends PrintWriter { print("" + "" + NL + "" }, // Class documentation {BUG_ID + FS + "pkg1" + FS + "C1.html", - "" + "" + NL + "" }, {BUG_ID + FS + "pkg1" + FS + "C1.html", "" @@ -62,29 +64,32 @@ public class TestHeadings extends JavadocTester { // Class use documentation {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", - "" + "" + NL + "" }, {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", "" }, {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", - "" + "" + NL + "" }, // Deprecated {BUG_ID + FS + "deprecated-list.html", - "" + "" }, // Constant values {BUG_ID + FS + "constant-values.html", - "" - }, - {BUG_ID + FS + "constant-values.html", - "" + "" + NL + "" + NL + + "" }, // Serialized Form diff --git a/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java b/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java index 3bb26e83992..c1445255c42 100644 --- a/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java +++ b/langtools/test/com/sun/javadoc/testHtmlStrongTag/TestHtmlStrongTag.java @@ -38,14 +38,15 @@ public class TestHtmlStrongTag extends JavadocTester { private static final String BUG_ID = "6786028"; private static final String[][] TEST1 = { - {BUG_ID + FS + "pkg1" + FS + "C1.html", "Method Summary"}, - {BUG_ID + FS + "pkg1" + FS + "C1.html", "See Also:"}, - {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "Class Summary"}}; + {BUG_ID + FS + "pkg1" + FS + "C1.html", "See Also:"}}; private static final String[][] NEGATED_TEST1 = { - {BUG_ID + FS + "pkg1" + FS + "C1.html", ""}}; + {BUG_ID + FS + "pkg1" + FS + "C1.html", "Method Summary"}, + {BUG_ID + FS + "pkg1" + FS + "C1.html", ""}, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "Class Summary"}}; private static final String[][] TEST2 = { + {BUG_ID + FS + "pkg2" + FS + "C2.html", "Comments:"}}; + private static final String[][] NEGATED_TEST2 = { {BUG_ID + FS + "pkg2" + FS + "C2.html", "Method Summary"}, - {BUG_ID + FS + "pkg2" + FS + "C2.html", "Comments:"}, {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "Class Summary"}}; private static final String[] ARGS1 = @@ -62,7 +63,7 @@ public class TestHtmlStrongTag extends JavadocTester { public static void main(String[] args) { TestHtmlStrongTag tester = new TestHtmlStrongTag(); run(tester, ARGS1, TEST1, NEGATED_TEST1); - run(tester, ARGS2, TEST2, NO_TEST); + run(tester, ARGS2, TEST2, NEGATED_TEST2); tester.printSummary(); } diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java new file mode 100644 index 00000000000..f08ff5783d1 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java @@ -0,0 +1,478 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6786688 + * @summary HTML tables should have table summary, caption and table headers. + * @author Bhavesh Patel + * @library ../lib/ + * @build JavadocTester + * @build TestHtmlTableTags + * @run main TestHtmlTableTags + */ + +public class TestHtmlTableTags extends JavadocTester { + + //Test information. + private static final String BUG_ID = "6786688"; + + //Javadoc arguments. + private static final String[] ARGS = new String[] { + "-d", BUG_ID, "-sourcepath", SRC_DIR, "-use", "pkg1", "pkg2" + }; + + //Input for string tests for HTML table tags. + private static final String[][] TABLE_TAGS_TEST = { + /* + * Test for validating summary for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "
"); + } + + /** + * Print </CAPTION> tag. Add a newline character at the end. + */ + public void captionEnd() { + println("
"); } + /** + * Print <TH CLASS="stylename" SCOPE="scope" NOWRAP> tag. + * + * @param stylename style to be applied. + * @param scope the scope attribute. + */ + public void thScopeNoWrap(String stylename, String scope) { + print(""); + } + + /* + * Returns a header for Modifier and Type column of a table. + */ + public String getModifierTypeHeader() { + return modifierTypeHeader; + } + /** * Print <TH align="align" COLSPAN=i> tag. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties index 492a77e7fcc..f4d86e3d5d8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties @@ -83,6 +83,17 @@ doclet.Deprecated_Constructors=Deprecated Constructors doclet.Deprecated_Methods=Deprecated Methods doclet.Deprecated_Enum_Constants=Deprecated Enum Constants doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements +doclet.deprecated_classes=deprecated classes +doclet.deprecated_enums=deprecated enums +doclet.deprecated_interfaces=deprecated interfaces +doclet.deprecated_exceptions=deprecated exceptions +doclet.deprecated_annotation_types=deprecated annotation types +doclet.deprecated_errors=deprecated errors +doclet.deprecated_fields=deprecated fields +doclet.deprecated_constructors=deprecated constructors +doclet.deprecated_methods=deprecated methods +doclet.deprecated_enum_constants=deprecated enum constants +doclet.deprecated_annotation_type_members=deprecated annotation type elements doclet.Frame_Output=Frame Output doclet.Docs_generated_by_Javadoc=Documentation generated by Javadoc. doclet.Generated_Docs_Untitled=Generated Documentation (Untitled) @@ -171,6 +182,7 @@ doclet.Style_line_8=Font used in left-hand frame lists doclet.Style_line_9=Example of smaller, sans-serif font in frames doclet.Style_line_10=Navigation bar fonts and colors doclet.Style_line_11=Dark Blue +doclet.Style_line_12=Table caption style doclet.ClassUse_Packages.that.use.0=Packages that use {0} doclet.ClassUse_Uses.of.0.in.1=Uses of {0} in {1} doclet.ClassUse_Classes.in.0.used.by.1=Classes in {0} used by {1} diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java index eb86fbea2d9..d46807d02e4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PackageSummaryWriter.java @@ -64,7 +64,7 @@ public interface PackageSummaryWriter { * @param classes the array of classes to document. * @param label the label for this table. */ - public abstract void writeClassesSummary(ClassDoc[] classes, String label); + public abstract void writeClassesSummary(ClassDoc[] classes, String label, String tableSummary, String[] tableHeader); /** * Write the header for the summary. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java index c85b0b30b8d..ac25c257739 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java @@ -40,6 +40,7 @@ import java.lang.reflect.*; * Do not use it as an API * * @author Jamie Ho + * @author Bhavesh Patel (Modified) * @since 1.5 */ public class PackageSummaryBuilder extends AbstractBuilder { @@ -184,7 +185,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the classes in this package. */ public void buildClassSummary() { - ClassDoc[] classes = + String classTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Class_Summary"), + configuration.getText("doclet.classes")); + String[] classTableHeader = new String[] { + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description") + }; + ClassDoc[] classes = packageDoc.isIncluded() ? packageDoc.ordinaryClasses() : configuration.classDocCatalog.ordinaryClasses( @@ -192,7 +201,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (classes.length > 0) { packageWriter.writeClassesSummary( classes, - configuration.getText("doclet.Class_Summary")); + configuration.getText("doclet.Class_Summary"), + classTableSummary, classTableHeader); } } @@ -200,7 +210,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the interfaces in this package. */ public void buildInterfaceSummary() { - ClassDoc[] interfaces = + String interfaceTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Interface_Summary"), + configuration.getText("doclet.interfaces")); + String[] interfaceTableHeader = new String[] { + configuration.getText("doclet.Interface"), + configuration.getText("doclet.Description") + }; + ClassDoc[] interfaces = packageDoc.isIncluded() ? packageDoc.interfaces() : configuration.classDocCatalog.interfaces( @@ -208,7 +226,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (interfaces.length > 0) { packageWriter.writeClassesSummary( interfaces, - configuration.getText("doclet.Interface_Summary")); + configuration.getText("doclet.Interface_Summary"), + interfaceTableSummary, interfaceTableHeader); } } @@ -216,7 +235,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the enums in this package. */ public void buildAnnotationTypeSummary() { - ClassDoc[] annotationTypes = + String annotationtypeTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Annotation_Types_Summary"), + configuration.getText("doclet.annotationtypes")); + String[] annotationtypeTableHeader = new String[] { + configuration.getText("doclet.AnnotationType"), + configuration.getText("doclet.Description") + }; + ClassDoc[] annotationTypes = packageDoc.isIncluded() ? packageDoc.annotationTypes() : configuration.classDocCatalog.annotationTypes( @@ -224,7 +251,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (annotationTypes.length > 0) { packageWriter.writeClassesSummary( annotationTypes, - configuration.getText("doclet.Annotation_Types_Summary")); + configuration.getText("doclet.Annotation_Types_Summary"), + annotationtypeTableSummary, annotationtypeTableHeader); } } @@ -232,7 +260,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the enums in this package. */ public void buildEnumSummary() { - ClassDoc[] enums = + String enumTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Enum_Summary"), + configuration.getText("doclet.enums")); + String[] enumTableHeader = new String[] { + configuration.getText("doclet.Enum"), + configuration.getText("doclet.Description") + }; + ClassDoc[] enums = packageDoc.isIncluded() ? packageDoc.enums() : configuration.classDocCatalog.enums( @@ -240,7 +276,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (enums.length > 0) { packageWriter.writeClassesSummary( enums, - configuration.getText("doclet.Enum_Summary")); + configuration.getText("doclet.Enum_Summary"), + enumTableSummary, enumTableHeader); } } @@ -248,7 +285,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the exceptions in this package. */ public void buildExceptionSummary() { - ClassDoc[] exceptions = + String exceptionTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Exception_Summary"), + configuration.getText("doclet.exceptions")); + String[] exceptionTableHeader = new String[] { + configuration.getText("doclet.Exception"), + configuration.getText("doclet.Description") + }; + ClassDoc[] exceptions = packageDoc.isIncluded() ? packageDoc.exceptions() : configuration.classDocCatalog.exceptions( @@ -256,7 +301,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (exceptions.length > 0) { packageWriter.writeClassesSummary( exceptions, - configuration.getText("doclet.Exception_Summary")); + configuration.getText("doclet.Exception_Summary"), + exceptionTableSummary, exceptionTableHeader); } } @@ -264,7 +310,15 @@ public class PackageSummaryBuilder extends AbstractBuilder { * Build the summary for the errors in this package. */ public void buildErrorSummary() { - ClassDoc[] errors = + String errorTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Error_Summary"), + configuration.getText("doclet.errors")); + String[] errorTableHeader = new String[] { + configuration.getText("doclet.Error"), + configuration.getText("doclet.Description") + }; + ClassDoc[] errors = packageDoc.isIncluded() ? packageDoc.errors() : configuration.classDocCatalog.errors( @@ -272,7 +326,8 @@ public class PackageSummaryBuilder extends AbstractBuilder { if (errors.length > 0) { packageWriter.writeClassesSummary( errors, - configuration.getText("doclet.Error_Summary")); + configuration.getText("doclet.Error_Summary"), + errorTableSummary, errorTableHeader); } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties index 57382de9ab2..371bdf596f1 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties @@ -82,6 +82,7 @@ doclet.Exceptions=Exceptions doclet.Errors=Errors doclet.Classes=Classes doclet.Packages=Packages +doclet.packages=packages doclet.All_Classes=All Classes doclet.All_Superinterfaces=All Superinterfaces: doclet.All_Implemented_Interfaces=All Implemented Interfaces: @@ -92,14 +93,20 @@ doclet.Interface=Interface doclet.Class=Class doclet.AnnotationType=Annotation Type doclet.annotationtype=annotation type +doclet.annotationtypes=annotation types doclet.Enum=Enum doclet.enum=enum +doclet.enums=enums doclet.interface=interface +doclet.interfaces=interfaces doclet.class=class +doclet.classes=classes doclet.Error=Error doclet.error=error +doclet.errors=errors doclet.Exception=Exception doclet.exception=exception +doclet.exceptions=exceptions doclet.extended_by=extended by doclet.extends=extends doclet.Package_private=(package private) @@ -125,6 +132,32 @@ doclet.value_tag_invalid_reference={0} (referenced by @value tag) is an unknown doclet.value_tag_invalid_constant=@value tag (which references {0}) can only be used in constants. doclet.dest_dir_create=Creating destination directory: "{0}" doclet.in={0} in {1} +doclet.Use_Table_Summary=Use table, listing {0}, and an explanation +doclet.Constants_Table_Summary={0} table, listing constant fields, and values +doclet.Member_Table_Summary={0} table, listing {1}, and an explanation +doclet.fields=fields +doclet.constructors=constructors +doclet.methods=methods +doclet.annotation_type_optional_members=optional elements +doclet.annotation_type_required_members=required elements +doclet.enum_constants=enum constants +doclet.nested_classes=nested classes +doclet.subclasses=subclasses +doclet.subinterfaces=subinterfaces +doclet.Modifier=Modifier +doclet.Type=Type +doclet.Field=Field +doclet.Constructor=Constructor +doclet.Method=Method +doclet.Annotation_Type_Optional_Member=Optional Element +doclet.Annotation_Type_Required_Member=Required Element +doclet.Annotation_Type_Member=Annotation Type Element +doclet.Enum_Constant=Enum Constant +doclet.Class=Class +doclet.Description=Description +doclet.ConstantField=Constant Field +doclet.Value=Value +doclet.0_and_1={0} and {1} #Documentation for Enums doclet.enum_values_doc=\n\ diff --git a/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java b/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java index 1ed62c535db..eb82d715b91 100644 --- a/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java +++ b/langtools/test/com/sun/javadoc/testHeadings/TestHeadings.java @@ -47,14 +47,16 @@ public class TestHeadings extends JavadocTester { private static final String[][] TEST = { //Package summary {BUG_ID + FS + "pkg1" + FS + "package-summary.html", - "" + NL + - "Class Summary" + + "ClassDescription" + NL + - "Field Summary" + + "Modifier and TypeField and DescriptionMethods inherited from class " + "java.lang.Object" + NL + - "Packages that use C1" + + "PackageDescription" + NL + "Uses of C1 in " + "pkg2Fields in " + "pkg2 " + "declared as C1" + + "Modifier and TypeField and Description" + NL + - "Deprecated Methods" + + "Method and Descriptionpkg1.C1pkg1.C1" + + "Modifier and TypeConstant FieldValue
" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "
" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "
" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "
" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "
" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "
" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "
" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "
" + }, + {BUG_ID + FS + "deprecated-list.html", + "
" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "
" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "
" + }, + + /* + * Test for validating caption for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "" + }, + {BUG_ID + FS + "deprecated-list.html", + "" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "" + }, + + /* + * Test for validating headers for HTML tables + */ + + //Package summary + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-summary.html", + "" + NL + "" + }, + // Class documentation + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C2.ModalExclusionType.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C3.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "C4.html", + "" + NL + "" + }, + // Class use documentation + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "I1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "class-use" + FS + "C1.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "C2.ModalExclusionType.html", + "" + NL + "" + }, + // Package use documentation + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg1" + FS + "package-use.html", + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + NL + "" + }, + {BUG_ID + FS + "pkg2" + FS + "package-use.html", + "" + }, + // Deprecated + {BUG_ID + FS + "deprecated-list.html", + "" + }, + {BUG_ID + FS + "deprecated-list.html", + "" + }, + // Constant values + {BUG_ID + FS + "constant-values.html", + "" + NL + "" + NL + + "" + }, + // Overview Summary + {BUG_ID + FS + "overview-summary.html", + "" + NL + "" + } + }; + private static final String[][] NEGATED_TEST = NO_TEST; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestHtmlTableTags tester = new TestHtmlTableTags(); + run(tester, ARGS, TABLE_TAGS_TEST, NEGATED_TEST); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java new file mode 100644 index 00000000000..5f38d4f1f29 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/C1.java @@ -0,0 +1,81 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import pkg2.*; + +/** + * A test class. + * + * @author Bhavesh Patel + */ +public class C1 implements I1 { + + /** + * Test field for class. + */ + public C2 field; + + /** + * Constant value. + */ + public static final String CONSTANT1 = "C1"; + + /** + * A test constructor. + */ + C1() { + } + + /** + * Method thats does some processing. + * + * @param param some parameter that is passed. + * @return a sample object. + */ + public C2 method(C2 param) { + return param; + } + + /** + * Method that is implemented. + * + * @param a some random value. + * @param b some random value. + */ + public void method1(int a, int b) { + } + + /** + * Another inherited method. + * @param c some value. + */ + public void method2(int c) { + } + + /** + * @deprecated don't use this anymore. + */ + public void deprecatedMethod() {} +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java new file mode 100644 index 00000000000..509417825ac --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/I1.java @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +/** + * A sample interface used to test table tags. + * + * @author Bhavesh Patel + */ +public interface I1 { + + /** + * A test method. + * + * @param a blah. + * @param b blah. + */ + void method1(int a, int b); + + /** + * Another test method. + * + * @param c blah. + */ + void method2(int c); + +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java new file mode 100644 index 00000000000..024483be5a7 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg1/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Test package 1 used to test table tags. + */ +package pkg1; diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java new file mode 100644 index 00000000000..07992e2bad1 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C2.java @@ -0,0 +1,73 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg2; + +import pkg1.*; + +/** + * Another test class. + * + * @author Bhavesh Patel + */ +public class C2 { + + /** + * A test field. + */ + public C1 field; + + /** + * @deprecated don't use this field anymore. + */ + public C1 dep_field; + + /** + * A sample enum. + */ + public static enum ModalExclusionType { + /** + * Test comment. + */ + NO_EXCLUDE, + /** + * Another comment. + */ + APPLICATION_EXCLUDE + }; + + /** + * A string constant. + */ + public static final String CONSTANT1 = "C2"; + + /** + * A sample method. + * + * @param param some parameter. + * @return a test object. + */ + public C1 method(C1 param) { + return param; + } +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java new file mode 100644 index 00000000000..e410266b6a5 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C3.java @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg2; + +import java.lang.annotation.*; + +/** + * Test Annotation class. + * + * @author Bhavesh Patel + */ +public @interface C3 { + /** + * Comment. + */ + String[] value(); +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java new file mode 100644 index 00000000000..7eec427be53 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/C4.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg2; + +import java.lang.annotation.*; + +/* + * A sample interface. + */ +public @interface C4 { + boolean value() default true; +} diff --git a/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java new file mode 100644 index 00000000000..a1523b14326 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/pkg2/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Test package 2 used to test table tags. + */ +package pkg2; diff --git a/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java b/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java index 17eac18887a..5a5fb82b399 100644 --- a/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java +++ b/langtools/test/com/sun/javadoc/testNewLanguageFeatures/TestNewLanguageFeatures.java @@ -58,7 +58,8 @@ public class TestNewLanguageFeatures extends JavadocTester { "Coin>" }, //Check for enum constant section - {BUG_ID + FS + "pkg" + FS + "Coin.html", "Enum Constant Summary"}, + {BUG_ID + FS + "pkg" + FS + "Coin.html", ""}, //Detail for enum constant {BUG_ID + FS + "pkg" + FS + "Coin.html", "Dime"}, @@ -158,9 +159,11 @@ public class TestNewLanguageFeatures extends JavadocTester { "public @interface AnnotationType"}, //Make sure member summary headings are correct. {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "Required Element Summary"}, + ""}, {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", - "Optional Element Summary"}, + ""}, //Make sure element detail heading is correct {BUG_ID + FS + "pkg" + FS + "AnnotationType.html", "Element Detail"}, @@ -286,39 +289,57 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest1: {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", "ParamTest<Foo>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "ParamTest<Foo>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "ParamTest<Foo>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", "<T extends ParamTest<Foo3>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", "<T extends ParamTest<Foo3>>" @@ -371,38 +414,61 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest3: >> {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", "<T extends ParamTest2<java.util.List<? extends Foo4>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "" + "" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", "<T extends ParamTest2<java.util.List<? extends Foo4>>>" @@ -410,81 +476,147 @@ public class TestNewLanguageFeatures extends JavadocTester { //Type parameters in constructor and method args {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "" + NL + - "" + NL + - "" + NL + - "" + NL + - "" + NL + + "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + + "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + "Packages with annotations of type " + + "AnnotationType" + NL + + "" + NL + "" + NL + "" + NL + "" + NL + + "" + NL + + "" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Classes in pkg with annotations of type AnnotationType" + NL + - "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + "" + NL + - "" + NL + - "" + NL + "" + NL + "" + NL + + "" + NL + + ""} }; private static final String[][] NEGATED_TEST = NO_TEST; From fba4182589813159ab0fb85ab476eb12543ba41f Mon Sep 17 00:00:00 2001 From: Karen Kinnear Date: Fri, 20 Mar 2009 11:23:24 -0400 Subject: [PATCH 17/43] 6819853: VM does not detect JDK which supports parallel class loaders Reviewed-by: coleenp, pbk, xlu, alanb --- hotspot/src/share/vm/classfile/vmSymbols.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 338b14877a0..bfa94aabec1 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -376,7 +376,7 @@ template(unknown_class_name, "") \ \ /* used to identify class loaders handling parallel class loading */ \ - template(parallelCapable_name, "parallelLockMap;") \ + template(parallelCapable_name, "parallelLockMap") \ \ /* JVM monitoring and management support */ \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ From 34d8fbb5e26e14cea387c6cefbeaa0512d1376d8 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Fri, 20 Mar 2009 15:50:50 -0700 Subject: [PATCH 18/43] 6820360: Fix for definition list tags nesting adds an extra list tag for package summary page Reviewed-by: jjg --- .../formats/html/HtmlDocletWriter.java | 10 ++++--- .../TestHtmlDefinitionListTag.java | 12 ++++++-- .../pkg1/package-info.java | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 74d287dd79b..453b8e8e74a 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -236,17 +236,19 @@ public class HtmlDocletWriter extends HtmlDocWriter { configuration.tagletManager.getCustomTags(doc), getTagletWriterInstance(false), output); String outputString = output.toString().trim(); - // For RootDoc and ClassDoc, this section is not the definition description - // but the start of definition list. + // For RootDoc, ClassDoc and PackageDoc, this section is not the + // definition description but the start of definition list. if (!outputString.isEmpty()) { - if (!(doc instanceof RootDoc || doc instanceof ClassDoc)) { + if (!(doc instanceof RootDoc || doc instanceof ClassDoc || + doc instanceof PackageDoc)) { printMemberDetailsListStartTag(); dd(); } printTagsInfoHeader(); print(outputString); printTagsInfoFooter(); - if (!(doc instanceof RootDoc || doc instanceof ClassDoc)) + if (!(doc instanceof RootDoc || doc instanceof ClassDoc || + doc instanceof PackageDoc)) ddEnd(); } } diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java index 5fa8db63ca5..652de517cb5 100644 --- a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java @@ -25,7 +25,7 @@ /* * @test - * @bug 6786690 + * @bug 6786690 6820360 * @summary This test verifies the nesting of definition list tags. * @author Bhavesh Patel * @library ../lib/ @@ -36,7 +36,7 @@ public class TestHtmlDefinitionListTag extends JavadocTester { - private static final String BUG_ID = "6786690"; + private static final String BUG_ID = "6786690-6820360"; // Test common to all runs of javadoc. The class signature should print // properly enclosed definition list tags and the Annotation Type @@ -55,6 +55,9 @@ public class TestHtmlDefinitionListTag extends JavadocTester { // serialized form should have properly nested definition list tags // enclosing comments, tags and deprecated information. private static final String[][] TEST_CMNT_DEPR = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
" + NL + + "
Since:
" + NL + + "
JDK1.0
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
" + NL + "
Since:
" + NL + "
JDK1.0
" + NL + "
See Also:
" + @@ -193,6 +196,9 @@ public class TestHtmlDefinitionListTag extends JavadocTester { // should display properly nested definition list tags for comments, tags // and deprecated information. private static final String[][] TEST_NODEPR = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
" + NL + + "
Since:
" + NL + + "
JDK1.0
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
" + NL + "
Since:
" + NL + "
JDK1.0
" + NL + "
See Also:
" + @@ -302,6 +308,8 @@ public class TestHtmlDefinitionListTag extends JavadocTester { // Test for valid HTML generation which should not comprise of empty // definition list tags. private static final String[][] NEGATED_TEST = { + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
"}, + {BUG_ID + FS + "pkg1" + FS + "package-summary.html", "
" + NL + "
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
"}, {BUG_ID + FS + "pkg1" + FS + "C1.html", "
" + NL + "
"}, {BUG_ID + FS + "pkg1" + FS + "C1.ModalExclusionType.html", "
"}, diff --git a/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java new file mode 100644 index 00000000000..201ea4b6199 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testHtmlDefinitionListTag/pkg1/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * Test package 1. + * + * @since JDK1.0 + */ +package pkg1; From c8da21faa95ef0d691b02934e91c3f749f90243a Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 20 Mar 2009 22:08:48 -0400 Subject: [PATCH 19/43] 6805748: Assertion "don't reset to 0 -- could be mistaken for never-executed" in CompilationPolicy Resetting the invocation counter for a method invocation event was setting count to zero for CompileThreshold=1, making it look like a never executed method. Reviewed-by: phh, kamg, acorn, never --- hotspot/src/share/vm/interpreter/invocationCounter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hotspot/src/share/vm/interpreter/invocationCounter.cpp b/hotspot/src/share/vm/interpreter/invocationCounter.cpp index cb650778556..7ecc70d1997 100644 --- a/hotspot/src/share/vm/interpreter/invocationCounter.cpp +++ b/hotspot/src/share/vm/interpreter/invocationCounter.cpp @@ -47,6 +47,8 @@ void InvocationCounter::set_carry() { // executed many more times before re-entering the VM. int old_count = count(); int new_count = MIN2(old_count, (int) (CompileThreshold / 2)); + // prevent from going to zero, to distinguish from never-executed methods + if (new_count == 0) new_count = 1; if (old_count != new_count) set(state(), new_count); } From d5e5e5a3d155caf3558765355349d60ad312e872 Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Sat, 21 Mar 2009 22:53:04 -0400 Subject: [PATCH 20/43] 6820321: G1: Error: guarantee(check_nums(total, n, parts), "all seq lengths should match") Small fixes to sort out some verbosegc-related incorrectness and a failure Reviewed-by: apetrusenko --- .../vm/gc_implementation/g1/g1CollectorPolicy.cpp | 13 +++++++------ .../src/share/vm/gc_implementation/g1/g1RemSet.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index d66e382f9b4..6147c8b6c67 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -1637,7 +1637,9 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, double obj_copy_time = avg_value(_par_last_obj_copy_times_ms); double termination_time = avg_value(_par_last_termination_times_ms); - double parallel_other_time; + double parallel_other_time = _cur_collection_par_time_ms - + (update_rs_time + ext_root_scan_time + mark_stack_scan_time + + scan_only_time + scan_rs_time + obj_copy_time + termination_time); if (update_stats) { MainBodySummary* body_summary = summary->main_body_summary(); guarantee(body_summary != NULL, "should not be null!"); @@ -1656,9 +1658,6 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, body_summary->record_parallel_time_ms(_cur_collection_par_time_ms); body_summary->record_clear_ct_time_ms(_cur_clear_ct_time_ms); body_summary->record_termination_time_ms(termination_time); - parallel_other_time = _cur_collection_par_time_ms - - (update_rs_time + ext_root_scan_time + mark_stack_scan_time + - scan_only_time + scan_rs_time + obj_copy_time + termination_time); body_summary->record_parallel_other_time_ms(parallel_other_time); } body_summary->record_mark_closure_time_ms(_mark_closure_time_ms); @@ -1803,8 +1802,10 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular, gclog_or_tty->print_cr("]"); _all_pause_times_ms->add(elapsed_ms); - summary->record_total_time_ms(elapsed_ms); - summary->record_other_time_ms(other_time_ms); + if (update_stats) { + summary->record_total_time_ms(elapsed_ms); + summary->record_other_time_ms(other_time_ms); + } for (int i = 0; i < _aux_num; ++i) if (_cur_aux_times_set[i]) _all_aux_times_ms[i].add(_cur_aux_times_ms[i]); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 3c5a4a5b11f..d0482ea1054 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -511,9 +511,17 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, if (G1EnableParallelRSetUpdating || (worker_i == 0)) { updateRS(worker_i); scanNewRefsRS(oc, worker_i); + } else { + _g1p->record_update_rs_start_time(worker_i, os::elapsedTime()); + _g1p->record_update_rs_processed_buffers(worker_i, 0.0); + _g1p->record_update_rs_time(worker_i, 0.0); + _g1p->record_scan_new_refs_time(worker_i, 0.0); } if (G1EnableParallelRSetScanning || (worker_i == 0)) { scanRS(oc, worker_i); + } else { + _g1p->record_scan_rs_start_time(worker_i, os::elapsedTime()); + _g1p->record_scan_rs_time(worker_i, 0.0); } } else { assert(worker_i == 0, "invariant"); From 283deccd890a1e0f002c63b0bd956e715f0a1ac2 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Mon, 23 Mar 2009 17:43:15 -0700 Subject: [PATCH 21/43] 6695776: corba jscheme jar files in repository could be built from source Forward port of changes from the 6-open train. Reviewed-by: darcy, ohair, tbell --- corba/make/com/sun/corba/se/sources/Makefile | 10 +- corba/make/sun/rmi/corbalogsources/Makefile | 49 +- corba/make/tools/Makefile | 3 +- corba/make/tools/logutil/Makefile | 43 ++ .../se/logutil/IndentingPrintWriter.java | 15 +- .../com/sun/tools/corba/se/logutil/Input.java | 211 ++++++ .../sun/tools/corba/se/logutil/InputCode.java | 116 +++ .../corba/se/logutil/InputException.java | 94 +++ .../com/sun/tools/corba/se/logutil/MC.java | 559 +++++++++++++++ .../tools/corba/se/logutil/lib/jscheme.jar | Bin 382167 -> 0 bytes .../corba/se/logutil/lib/jschemelogutil.jar | Bin 2451 -> 0 bytes .../com/sun/tools/corba/se/logutil/scripts/mc | 2 - .../sun/tools/corba/se/logutil/scripts/mc.scm | 662 ------------------ .../sun/tools/corba/se/logutil/scripts/run | 2 - 14 files changed, 1059 insertions(+), 707 deletions(-) create mode 100644 corba/make/tools/logutil/Makefile create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java create mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jschemelogutil.jar delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm delete mode 100644 corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run diff --git a/corba/make/com/sun/corba/se/sources/Makefile b/corba/make/com/sun/corba/se/sources/Makefile index 164a4e65a93..9d945a29343 100644 --- a/corba/make/com/sun/corba/se/sources/Makefile +++ b/corba/make/com/sun/corba/se/sources/Makefile @@ -46,8 +46,6 @@ CORBA_JMK_DIRECTORY=$(TOPDIR)/make/com/sun/corba/minclude/ include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_PortableActivationIDL.jmk include $(CORBA_JMK_DIRECTORY)com_sun_corba_se_impl_logging.jmk -FILES_java += com/sun/corba/se/org/omg/CORBA/ORB.java - # # Dirs # @@ -80,11 +78,11 @@ ORBUTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/ORBUtil.mc POA.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/POA.mc UTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/Util.mc -MC_GENERATE_CLASS = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-class -MC_GENERATE_LOG_RB = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-resource +MC_GENERATE_CLASS = make-class +MC_GENERATE_LOG_RB = make-resource -JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) jscheme.REPL $(MC_GENERATE_CLASS) -JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) jscheme.REPL $(MC_GENERATE_LOG_RB) +JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_CLASS) +JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_LOG_RB) # diff --git a/corba/make/sun/rmi/corbalogsources/Makefile b/corba/make/sun/rmi/corbalogsources/Makefile index a7b995c1c51..0859c5ab2a9 100644 --- a/corba/make/sun/rmi/corbalogsources/Makefile +++ b/corba/make/sun/rmi/corbalogsources/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. 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 @@ -75,15 +75,14 @@ ORBUTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/ORBUtil.mc POA.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/POA.mc UTIL.MC = $(SRC_DIR)/com/sun/corba/se/spi/logging/data/Util.mc -MC_GENERATE_CLASS = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-class -MC_GENERATE_LOG_RB = $(SRC_DIR)/com/sun/tools/corba/se/logutil/scripts/mc.scm -main main make-resource +MC_GENERATE_CLASS = make-class +MC_GENERATE_LOG_RB = make-resource -JSCHEME_LIB_DIRECTORY=$(SRC_DIR)/com/sun/tools/corba/se/logutil/lib -JSCHEME_CLASSPATH=$(JSCHEME_LIB_DIRECTORY)/jscheme.jar$(CLASSPATH_SEPARATOR)$(JSCHEME_LIB_DIRECTORY)/jschemelogutil.jar -JSCHEME_GENERATE_CLASS = $(BOOT_JAVA_CMD) \ - -cp "$(JSCHEME_CLASSPATH)" jscheme.REPL $(MC_GENERATE_CLASS) -JSCHEME_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) \ - -cp "$(JSCHEME_CLASSPATH)" jscheme.REPL $(MC_GENERATE_LOG_RB) +MC_CLASSPATH=$(BUILDTOOLJARDIR)/MC.jar +MCJ_GENERATE_CLASS = $(BOOT_JAVA_CMD) \ + -cp "$(MC_CLASSPATH)" com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_CLASS) +MCJ_GENERATE_LOG_RB = $(BOOT_JAVA_CMD) \ + -cp "$(MC_CLASSPATH)" com.sun.tools.corba.se.logutil.MC $(MC_GENERATE_LOG_RB) # @@ -104,28 +103,28 @@ $(LOG_GENDIRECTORY): $(MKDIR) -p $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ActivationSystemException.java : $(ACTIVATION.MC) - $(JSCHEME_GENERATE_CLASS) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/IORSystemException.java : $(IOR.MC) - $(JSCHEME_GENERATE_CLASS) $(IOR.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(IOR.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/InterceptorsSystemException.java : $(INTERCEPTORS.MC) - $(JSCHEME_GENERATE_CLASS) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/NamingSystemException.java : $(NAMING.MC) - $(JSCHEME_GENERATE_CLASS) $(NAMING.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(NAMING.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/OMGSystemException.java : $(OMG.MC) - $(JSCHEME_GENERATE_CLASS) $(OMG.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(OMG.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ORBUtilSystemException.java : $(ORBUTIL.MC) - $(JSCHEME_GENERATE_CLASS) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/POASystemException.java : $(POA.MC) - $(JSCHEME_GENERATE_CLASS) $(POA.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(POA.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/UtilSystemException.java : $(UTIL.MC) - $(JSCHEME_GENERATE_CLASS) $(UTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_CLASS) $(UTIL.MC) $(LOG_GENDIRECTORY) logresource.generate: $(LOG_GENDIRECTORY)/LogStrings.properties @@ -142,28 +141,28 @@ $(LOG_GENDIRECTORY)/LogStrings.properties: \ $(CAT) $(LOG_GENDIRECTORY)/*.resource > $(LOG_GENDIRECTORY)/LogStrings.properties $(LOG_GENDIRECTORY)/ActivationSystemException.resource : $(ACTIVATION.MC) - $(JSCHEME_GENERATE_LOG_RB) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(ACTIVATION.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/IORSystemException.resource : $(IOR.MC) - $(JSCHEME_GENERATE_LOG_RB) $(IOR.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(IOR.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/InterceptorsSystemException.resource : $(INTERCEPTORS.MC) - $(JSCHEME_GENERATE_LOG_RB) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(INTERCEPTORS.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/NamingSystemException.resource : $(NAMING.MC) - $(JSCHEME_GENERATE_LOG_RB) $(NAMING.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(NAMING.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/OMGSystemException.resource : $(OMG.MC) - $(JSCHEME_GENERATE_LOG_RB) $(OMG.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(OMG.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/ORBUtilSystemException.resource : $(ORBUTIL.MC) - $(JSCHEME_GENERATE_LOG_RB) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(ORBUTIL.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/POASystemException.resource : $(POA.MC) - $(JSCHEME_GENERATE_LOG_RB) $(POA.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(POA.MC) $(LOG_GENDIRECTORY) $(LOG_GENDIRECTORY)/UtilSystemException.resource : $(UTIL.MC) - $(JSCHEME_GENERATE_LOG_RB) $(UTIL.MC) $(LOG_GENDIRECTORY) + $(MCJ_GENERATE_LOG_RB) $(UTIL.MC) $(LOG_GENDIRECTORY) # diff --git a/corba/make/tools/Makefile b/corba/make/tools/Makefile index 489c7b2f269..f0d95363b84 100644 --- a/corba/make/tools/Makefile +++ b/corba/make/tools/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1998-2009 Sun Microsystems, Inc. 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 @@ -33,6 +33,7 @@ include $(BUILDDIR)/common/Defs.gmk SUBDIRS = \ strip_properties \ idlj \ + logutil \ all build clean clobber:: $(SUBDIRS-loop) diff --git a/corba/make/tools/logutil/Makefile b/corba/make/tools/logutil/Makefile new file mode 100644 index 00000000000..2e19867f8d4 --- /dev/null +++ b/corba/make/tools/logutil/Makefile @@ -0,0 +1,43 @@ +# +# Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun in the LICENSE file that accompanied this code. +# +# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Makefile for building the idlj tool +# + +BUILDDIR = ../.. +PACKAGE = com.sun.tools.corba.se.logutil +PRODUCT = tools +PROGRAM = MC +include $(BUILDDIR)/common/Defs.gmk + +BUILDTOOL_SOURCE_ROOT = $(SHARE_SRC)/classes +BUILDTOOL_MAIN = $(PKGDIR)/MC.java + +# +# Build tool jar rules. +# +include $(BUILDDIR)/common/BuildToolJar.gmk + diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java index d8b31fc0f77..e618a7401fa 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/IndentingPrintWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 @@ -30,7 +30,6 @@ import java.io.Writer ; import java.io.OutputStream ; import java.io.BufferedWriter ; import java.io.OutputStreamWriter ; -import jsint.Pair ; import java.util.StringTokenizer ; public class IndentingPrintWriter extends PrintWriter { @@ -38,22 +37,20 @@ public class IndentingPrintWriter extends PrintWriter { private int indentWidth = 4 ; private String indentString = "" ; - public void printMsg( String msg, Pair data ) + public void printMsg( String msg, Object... data ) { // System.out.println( "printMsg called with msg=" + msg + " data=" + data ) ; StringTokenizer st = new StringTokenizer( msg, "@", true ) ; StringBuffer result = new StringBuffer() ; - Object head = data.first ; - Pair tail = (Pair)data.rest ; String token = null ; + int pos = 0; while (st.hasMoreTokens()) { token = st.nextToken() ; if (token.equals("@")) { - if (head != null) { - result.append( head ) ; - head = tail.first ; - tail = (Pair)tail.rest ; + if (pos < data.length) { + result.append( data[pos] ); + ++pos; } else { throw new Error( "List too short for message" ) ; } diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java new file mode 100644 index 00000000000..5431f0c7a17 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/Input.java @@ -0,0 +1,211 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.corba.se.logutil; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.io.IOException; + +import java.util.LinkedList; +import java.util.Queue; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Input { + + /** + * The name of the package this class will inhabit. + */ + private String packageName; + + /** + * The name of the generated class. + */ + private String className; + + /** + * The name of the group of exceptions handled by the class. + */ + private String groupName; + + /** + * The group of exceptions. + */ + private Queue exceptions; + + /** + * Represents the current state of parsing the input. + */ + private enum State + { + OUTER, + IN_CLASS, + IN_EXCEPTION_LIST + }; + + /** + * Regular expression to match each code line. + */ + private static final Pattern EXCEPTION_INFO_REGEX = + Pattern.compile("(\\w+)\\s*(\\d+)\\s*(\\w+)"); + + /** + * Parses the specified file to create a new {@link Input} + * object. + * + * @param filename the file to parse. + * @throws FileNotFoundException if the file can't be found. + * @throws IOException if an I/O error occurs. + */ + public Input(final String filename) + throws FileNotFoundException, IOException { + BufferedReader r = + new BufferedReader(new InputStreamReader(new FileInputStream(filename))); + State state = State.OUTER; + InputException current = null; + exceptions = new LinkedList(); + String line; + while ((line = r.readLine()) != null) { + // Skip ; comments + if (line.startsWith(";")) + continue; + + int index = line.indexOf("("); + if (index == -1) + continue; + + switch (state) { + case OUTER: + state = State.IN_CLASS; + String[] classInfo = line.substring(index).split(" "); + packageName = classInfo[0].substring(2, classInfo[0].length() - 1); + className = classInfo[1].substring(1, classInfo[1].length() - 1); + groupName = classInfo[2]; + break; + case IN_CLASS: + state = State.IN_EXCEPTION_LIST; + break; + case IN_EXCEPTION_LIST: + boolean inQuote = false; + boolean inCode = false; + boolean end = false; + int start = index + 1; + Queue lines = new LinkedList(); + for (int a = start; a < line.length(); ++a) { + if (line.charAt(a) == '(' && !inCode && !inQuote) { + if (current == null) + current = + new InputException(line.substring(start, a).trim()); + start = a + 1; + inCode = true; + } + if (line.charAt(a) == '"') + inQuote = !inQuote; + if (line.charAt(a) == ')' && !inQuote) { + if (inCode) { + lines.offer(line.substring(start, a)); + inCode = false; + } else + end = true; + } + if (!end && a == line.length() - 1) + line += r.readLine(); + } + for (String l : lines) { + int stringStart = l.indexOf("\"") + 1; + int stringEnd = l.indexOf("\"", stringStart); + Matcher matcher = EXCEPTION_INFO_REGEX.matcher(l.substring(0, stringStart)); + if (matcher.find()) + current.add(new InputCode(matcher.group(1), + Integer.parseInt(matcher.group(2)), + matcher.group(3), + l.substring(stringStart, stringEnd))); + } + exceptions.offer(current); + current = null; + break; + } + } + } + + /** + * Returns the name of this group of exceptions. + * + * @return the name of this group of exceptions. + */ + public String getGroupName() + { + return groupName; + } + + /** + * Returns the name of the package this class will go in. + * + * @return the name of the package. + */ + public String getPackageName() + { + return packageName; + } + + /** + * Returns the name of the generated class. + * + * @return the name of the class. + */ + public String getClassName() + { + return className; + } + + /** + * Returns the exceptions contained in this class. + * + * @return the exceptions. + */ + public Queue getExceptions() { + return exceptions; + } + + /** + * Returns a textual representation of this input. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[packageName=" + packageName + + ",className=" + className + + ",groupName=" + groupName + + ",exceptions=" + exceptions + + "]"; + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java new file mode 100644 index 00000000000..810a449f486 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputCode.java @@ -0,0 +1,116 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.tools.corba.se.logutil; + +public class InputCode { + + /** + * The name of this code. + */ + private final String name; + + /** + * The code. + */ + private final int code; + + /** + * The log level for this code. + */ + private final String logLevel; + + /** + * The error message for this code. + */ + private final String message; + + /** + * Creates a new error code with the specified name, code, + * log level and error message. + * + * @param name the name of the new code. + * @param code the code itself. + * @param logLevel the level of severity of this error. + * @param message the error message for this code. + */ + public InputCode(final String name, final int code, + final String logLevel, final String message) { + this.name = name; + this.code = code; + this.logLevel = logLevel; + this.message = message; + } + + /** + * Returns the name of this code. + * + * @return the name of the code. + */ + public String getName() { + return name; + } + + /** + * Returns the code. + * + * @return the code. + */ + public int getCode() { + return code; + } + + /** + * Returns the severity of this code. + * + * @return the log level severity of the code. + */ + public String getLogLevel() { + return logLevel; + } + + /** + * Returns the error message for this code. + * + * @return the error message for this code. + */ + public String getMessage() { + return message; + } + + /** + * Returns a textual representation of this code. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[name=" + name + + ",code=" + code + + ",logLevel=" + logLevel + + ",message=" + message + + "]"; + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java new file mode 100644 index 00000000000..5c1f4984e57 --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/InputException.java @@ -0,0 +1,94 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.tools.corba.se.logutil; + +import java.util.LinkedList; +import java.util.Queue; + +public class InputException { + + /** + * The name of this exception. + */ + private final String name; + + /** + * The codes associated with this exception. + */ + private final Queue codes; + + /** + * Constructs a new {@link InputException} with the + * specified name. + * + * @param name the name of the new exception; + */ + public InputException(final String name) { + this.name = name; + codes = new LinkedList(); + } + + /** + * Adds a new code to this exception. + * + * @param c the code to add. + */ + public void add(InputCode c) + { + codes.offer(c); + } + + /** + * Returns the name of this exception. + * + * @return the exception's name. + */ + public String getName() { + return name; + } + + /** + * Returns the codes associated with this exception. + * + * @return the exception's codes. + */ + public Queue getCodes() { + return codes; + } + + /** + * Returns a textual representation of this exception. + * + * @return a textual representation. + */ + public String toString() { + return getClass().getName() + + "[name=" + name + + ",codes=" + codes + + "]"; + } + +} + diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java b/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java new file mode 100644 index 00000000000..9246f70c3ab --- /dev/null +++ b/corba/src/share/classes/com/sun/tools/corba/se/logutil/MC.java @@ -0,0 +1,559 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.tools.corba.se.logutil; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Date; +import java.util.Formatter; +import java.util.List; +import java.util.Queue; + +public class MC { + + private static final String VERSION = "1.0"; + + private static final List SUN_EXCEPTION_GROUPS = Arrays.asList(new String[] + { "SUNBASE", "ORBUTIL", "ACTIVATION", "NAMING", "INTERCEPTORS", "POA", "IOR", "UTIL" }); + + private static final List EXCEPTIONS = Arrays.asList(new String[] + { "UNKNOWN", "BAD_PARAM", "NO_MEMORY", "IMP_LIMIT", "COMM_FAILURE", "INV_OBJREF", "NO_PERMISSION", + "INTERNAL", "MARSHAL", "INITIALIZE", "NO_IMPLEMENT", "BAD_TYPECODE", "BAD_OPERATION", "NO_RESOURCES", + "NO_RESPONSE", "PERSIST_STORE", "BAD_INV_ORDER", "TRANSIENT", "FREE_MEM", "INV_IDENT", "INV_FLAG", + "INTF_REPOS", "BAD_CONTEXT", "OBJ_ADAPTER", "DATA_CONVERSION", "OBJECT_NOT_EXIST", "TRANSACTION_REQUIRED", + "TRANSACTION_ROLLEDBACK", "INVALID_TRANSACTION", "INV_POLICY", "CODESET_INCOMPATIBLE", "REBIND", + "TIMEOUT", "TRANSACTION_UNAVAILABLE", "BAD_QOS", "INVALID_ACTIVITY", "ACTIVITY_COMPLETED", + "ACTIVITY_REQUIRED" }); + + /** + * Read the minor codes from the input file and + * write out a resource file. + * + * @param inFile the file to read the codes from. + * @param outDir the directory to write the resource file to. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + private void makeResource(String inFile, String outDir) + throws FileNotFoundException, IOException { + writeResource(outDir, new Input(inFile)); + } + + /** + * Create a new Java source file using the specified Scheme input file, + * and writing the result to the given output directory. + * + * @param inFile the file to read the data from. + * @param outDir the directory to write the Java class to. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + private void makeClass(String inFile, String outDir) + throws FileNotFoundException, IOException { + writeClass(inFile, outDir, new Input(inFile)); + } + + /** + * Writes out a Java source file using the data from the given + * {@link Input} object. The result is written to {@code outDir}. + * The name of the input file is just used in the header of the + * resulting source file. + * + * @param inFile the name of the file the data was read from. + * @param outDir the directory to write the Java class to. + * @param input the parsed input data. + * @throws FileNotFoundException if the output file can't be written. + */ + private void writeClass(String inFile, String outDir, Input input) + throws FileNotFoundException { + String packageName = input.getPackageName(); + String className = input.getClassName(); + String groupName = input.getGroupName(); + Queue exceptions = input.getExceptions(); + FileOutputStream file = new FileOutputStream(outDir + File.separator + className + ".java"); + IndentingPrintWriter pw = new IndentingPrintWriter(file); + + writeClassHeader(inFile, groupName, pw); + pw.printMsg("package @ ;", packageName); + pw.println(); + pw.println("import java.util.logging.Logger ;"); + pw.println("import java.util.logging.Level ;"); + pw.println(); + pw.println("import org.omg.CORBA.OMGVMCID ;"); + pw.println( "import com.sun.corba.se.impl.util.SUNVMCID ;"); + pw.println( "import org.omg.CORBA.CompletionStatus ;"); + pw.println( "import org.omg.CORBA.SystemException ;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.orb.ORB ;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.logging.LogWrapperFactory;"); + pw.println(); + pw.println( "import com.sun.corba.se.spi.logging.LogWrapperBase;"); + pw.println(); + writeImports(exceptions, pw); + pw.println(); + pw.indent(); + pw.printMsg("public class @ extends LogWrapperBase {", className); + pw.println(); + pw.printMsg("public @( Logger logger )", className); + pw.indent(); + pw.println( "{"); + pw.undent(); + pw.println( "super( logger ) ;"); + pw.println( "}"); + pw.println(); + pw.flush(); + writeFactoryMethod(className, groupName, pw); + writeExceptions(groupName, exceptions, className, pw); + pw.undent(); + pw.println( ); + pw.println( "}"); + pw.flush(); + pw.close(); + } + + /** + * Writes out the header of a Java source file. + * + * @param inFile the input file the file was generated from. + * @param groupName the group of exceptions the Java source file is for. + * @param pw the print writer used to write the output. + */ + private void writeClassHeader(String inFile, String groupName, + IndentingPrintWriter pw) { + if (groupName.equals("OMG")) + pw.println("// Log wrapper class for standard exceptions"); + else + pw.printMsg("// Log wrapper class for Sun private system exceptions in group @", + groupName); + pw.println("//"); + pw.printMsg("// Generated by MC.java version @, DO NOT EDIT BY HAND!", VERSION); + pw.printMsg("// Generated from input file @ on @", inFile, new Date()); + pw.println(); + } + + /** + * Write out the import list for the exceptions. + * + * @param groups the exceptions that were parsed. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeImports(Queue exceptions, + IndentingPrintWriter pw) { + if (exceptions == null) + return; + for (InputException e : exceptions) + pw.println("import org.omg.CORBA." + e.getName() + " ;"); + } + + /** + * Write out the factory method for this group of exceptions. + * + * @param className the name of the generated class. + * @param groupName the name of this group of exceptions. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeFactoryMethod(String className, String groupName, + IndentingPrintWriter pw) { + pw.indent(); + pw.println( "private static LogWrapperFactory factory = new LogWrapperFactory() {"); + pw.println( "public LogWrapperBase create( Logger logger )" ); + pw.indent(); + pw.println( "{"); + pw.undent(); + pw.printMsg("return new @( logger ) ;", className); + pw.undent(); + pw.println( "}" ); + pw.println( "} ;" ); + pw.println(); + pw.printMsg("public static @ get( ORB orb, String logDomain )", className); + pw.indent(); + pw.println( "{"); + pw.indent(); + pw.printMsg( "@ wrapper = ", className); + pw.indent(); + pw.printMsg( "(@) orb.getLogWrapper( logDomain, ", className); + pw.undent(); + pw.undent(); + pw.printMsg( "\"@\", factory ) ;", groupName); + pw.undent(); + pw.println( "return wrapper ;" ); + pw.println( "} " ); + pw.println(); + pw.printMsg( "public static @ get( String logDomain )", className); + pw.indent(); + pw.println( "{"); + pw.indent(); + pw.printMsg( "@ wrapper = ", className); + pw.indent(); + pw.printMsg( "(@) ORB.staticGetLogWrapper( logDomain, ", className); + pw.undent(); + pw.undent(); + pw.printMsg( "\"@\", factory ) ;", groupName); + pw.undent(); + pw.println( "return wrapper ;" ); + pw.println( "} " ); + pw.println(); + } + + /** + * Writes out the exceptions themselves. + * + * @param groupName the name of this group of exceptions. + * @param exceptions the exceptions to write out. + * @param className the name of the generated class. + * @param pw the {@link IndentingPrintWriter} for writing to the file. + */ + private void writeExceptions(String groupName, Queue exceptions, + String className, IndentingPrintWriter pw) { + for (InputException e : exceptions) { + pw.println("///////////////////////////////////////////////////////////"); + pw.printMsg("// @", e.getName()); + pw.println("///////////////////////////////////////////////////////////"); + pw.println(); + for (InputCode c : e.getCodes()) + writeMethods(groupName, e.getName(), c.getName(), c.getCode(), + c.getLogLevel(), className, StringUtil.countArgs(c.getMessage()), pw); + pw.flush(); + } + } + + /** + * Writes out the methods for a particular error. + * + * @param groupName the name of this group of exceptions. + * @param exceptionName the name of this particular exception. + * @param errorName the name of this particular error. + * @param code the minor code for this particular error. + * @param ident the name of the error in mixed-case identifier form. + * @param level the level at which to place log messages. + * @param className the name of the class for this group of exceptions. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethods(String groupName, String exceptionName, String errorName, + int code, String level, String className, int numParams, + IndentingPrintWriter pw) { + String ident = StringUtil.toMixedCase(errorName); + pw.printMsg("public static final int @ = @ ;", errorName, getBase(groupName, code)); + pw.println(); + pw.flush(); + writeMethodStatusCause(groupName, exceptionName, errorName, ident, level, + numParams, className, pw); + pw.println(); + pw.flush(); + writeMethodStatus(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + writeMethodCause(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + writeMethodNoArgs(exceptionName, ident, numParams, pw); + pw.println(); + pw.flush(); + } + + /** + * Writes out a method for an error that takes a + * {@link org.omg.CORBA.CompletionStatus} and a cause. + * + * @param groupName the name of this group of exceptions. + * @param exceptionName the name of this particular exception. + * @param errorName the name of this particular error. + * @param ident the name of the error in mixed-case identifier form. + * @param logLevel the level at which to place log messages. + * @param numParams the number of parameters the detail message takes. + * @param className the name of the class for this group of exceptions. + * @param pw the print writer for writing to the file. + */ + private void writeMethodStatusCause(String groupName, String exceptionName, + String errorName, String ident, + String logLevel, int numParams, + String className, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg( "public @ @( CompletionStatus cs, Throwable t@) {", exceptionName, + ident, makeDeclArgs(true, numParams)); + pw.printMsg( "@ exc = new @( @, cs ) ;", exceptionName, exceptionName, errorName); + pw.indent(); + pw.println( "if (t != null)" ); + pw.undent(); + pw.println( "exc.initCause( t ) ;" ); + pw.println(); + pw.indent(); + pw.printMsg( "if (logger.isLoggable( Level.@ )) {", logLevel); + if (numParams > 0) { + pw.printMsg( "Object[] parameters = new Object[@] ;", numParams); + for (int a = 0; a < numParams; ++a) + pw.printMsg("parameters[@] = arg@ ;", a, a); + } else + pw.println( "Object[] parameters = null ;"); + pw.indent(); + pw.printMsg( "doLog( Level.@, \"@.@\",", logLevel, groupName, ident); + pw.undent(); + pw.undent(); + pw.printMsg( "parameters, @.class, exc ) ;", className); + pw.println( "}"); + pw.println(); + + pw.undent(); + pw.println( "return exc ;"); + pw.println( "}"); + } + + /** + * Writes out a method for an error that takes a + * {@link org.omg.CORBA.CompletionStatus}. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodStatus(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg("public @ @( CompletionStatus cs@) {", exceptionName, + ident, makeDeclArgs(true, numParams)); + pw.undent(); + pw.printMsg("return @( cs, null@ ) ;", ident, makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Writes out a method for an error that takes a cause. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodCause(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + pw.indent(); + pw.printMsg("public @ @( Throwable t@) {", exceptionName, ident, + makeDeclArgs(true, numParams)); + pw.undent(); + pw.printMsg("return @( CompletionStatus.COMPLETED_NO, t@ ) ;", ident, + makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Writes out a method for an error that takes no arguments. + * + * @param exceptionName the name of this particular exception. + * @param ident the name of the error in mixed-case identifier form. + * @param numParams the number of parameters the detail message takes. + * @param pw the print writer for writing to the file. + */ + private void writeMethodNoArgs(String exceptionName, String ident, + int numParams, IndentingPrintWriter pw) { + + pw.indent(); + pw.printMsg("public @ @( @) {", exceptionName, ident, + makeDeclArgs(false, numParams)); + pw.undent(); + pw.printMsg("return @( CompletionStatus.COMPLETED_NO, null@ ) ;", + ident, makeCallArgs(true, numParams)); + pw.println("}"); + } + + /** + * Returns a list of comma-separated arguments with type declarations. + * + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeDeclArgs(boolean leadingComma, int numArgs) { + return makeArgString("Object arg", leadingComma, numArgs); + } + + /** + * Returns a list of comma-separated arguments without type declarations. + * + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeCallArgs(boolean leadingComma, int numArgs) { + return makeArgString("arg", leadingComma, numArgs); + } + + /** + * Returns a list of comma-separated arguments. + * + * @param prefixString the string with which to prefix each argument. + * @param leadingComma true if the list should start with a comma. + * @param numArgs the number of arguments to generate. + * @return the generated string. + */ + private String makeArgString(String prefixString, boolean leadingComma, + int numArgs) { + if (numArgs == 0) + return " "; + if (numArgs == 1) { + if (leadingComma) + return ", " + prefixString + (numArgs - 1); + else + return " " + prefixString + (numArgs - 1); + } + return makeArgString(prefixString, leadingComma, numArgs - 1) + + ", " + prefixString + (numArgs - 1); + } + + /** + * Returns the {@link String} containing the calculation of the + * error code. + * + * @param groupName the group of exception to which the code belongs. + * @param code the minor code number representing the exception within the group. + * @return the unique error code. + */ + private String getBase(String groupName, int code) { + if (groupName.equals("OMG")) + return "OMGVMCID.value + " + code; + else + return "SUNVMCID.value + " + (code + getSunBaseNumber(groupName)); + } + + /** + * Returns the base number for Sun-specific exceptions. + * + * @return the base number. + */ + private int getSunBaseNumber(String groupName) { + return 200 * SUN_EXCEPTION_GROUPS.indexOf(groupName); + } + + /** + * Writes out a resource file using the data from the given + * {@link Input} object. The result is written to {@code outDir}. + * + * @param outDir the directory to write the Java class to. + * @param input the parsed input data. + * @throws FileNotFoundException if the output file can't be written. + */ + private void writeResource(String outDir, Input input) + throws FileNotFoundException { + FileOutputStream file = new FileOutputStream(outDir + File.separator + + input.getClassName() + ".resource"); + IndentingPrintWriter pw = new IndentingPrintWriter(file); + String groupName = input.getGroupName(); + for (InputException e : input.getExceptions()) { + String exName = e.getName(); + for (InputCode c : e.getCodes()) { + String ident = StringUtil.toMixedCase(c.getName()); + pw.printMsg("@.@=\"@: (@) @\"", groupName, ident, + getMessageID(groupName, exName, c.getCode()), exName, c.getMessage()); + } + pw.flush(); + } + pw.close(); + } + + /** + * Returns the message ID corresponding to the given group name, + * exception name and error code. + * + * @param groupName the name of the group of exceptions. + * @param exception the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getMessageID(String groupName, String exceptionName, int code) { + if (groupName.equals("OMG")) + return getStandardMessageID(exceptionName, code); + else + return getSunMessageID(groupName, exceptionName, code); + } + + /** + * Returns the standard (OMG) message ID corresponding to the given + * exception name and error code. + * + * @param exceptionName the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getStandardMessageID(String exceptionName, int code) { + return new Formatter().format("IOP%s0%04d", getExceptionID(exceptionName), + code).toString(); + } + + /** + * Returns the Sun message ID corresponding to the given group name, + * exception name and error code. + * + * @param groupName the name of the group of exceptions. + * @param exceptionName the name of the particular exception. + * @param code an error code from the given exception. + * @return the message ID. + */ + private String getSunMessageID(String groupName, String exceptionName, int code) { + return new Formatter().format("IOP%s1%04d", getExceptionID(exceptionName), + getSunBaseNumber(groupName) + code).toString(); + } + + /** + * Returns the exception ID corresponding to the given exception name. + * + * @param exceptionName the name of the particular exception. + * @return the message ID. + */ + private String getExceptionID(String exceptionName) { + return new Formatter().format("%03d", EXCEPTIONS.indexOf(exceptionName)).toString(); + } + + /** + * Entry point for running the generator from the command + * line. Users can specify either "make-class" or "make-resource" + * as the first argument to generate the specified type of file. + * + * @param args the command-line arguments. + * @throws FileNotFoundException if the input file can not be found. + * @throws IOException if an I/O error occurs. + */ + public static void main(String[] args) + throws FileNotFoundException, IOException + { + if (args.length < 3) + { + System.err.println("(make-class|make-resource) "); + System.exit(-1); + } + if (args[0].equals("make-class")) + new MC().makeClass(args[1], args[2]); + else if (args[0].equals("make-resource")) + new MC().makeResource(args[1], args[2]); + else + System.err.println("Invalid command: " + args[0]); + } + +} diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar b/corba/src/share/classes/com/sun/tools/corba/se/logutil/lib/jscheme.jar deleted file mode 100644 index 5a2a0f1f44dff2c8bb40f08e382cb361852a1408..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 382167 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 z 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

UthMOiAwfddM#*0wgzl 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≪t`{T+x9Zlh|Fj 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 z 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 P;9xF2HUQwnAL{Dgsf6*5 diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc deleted file mode 100644 index 16df63d031f..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -java -cp lib/jscheme.jar:lib/util.jar jscheme.REPL mc.scm -main main $@ diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm deleted file mode 100644 index 3e9b51409ec..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/mc.scm +++ /dev/null @@ -1,662 +0,0 @@ -; Scheme program to produce CORBA standard exceptions class -; requires Jscheme Java extensions -; Makes use of some custom Java classes also - -(import "com.sun.tools.corba.se.logutil.IndentingPrintWriter" ) -(import "com.sun.tools.corba.se.logutil.StringUtil" ) -(import "java.io.FileOutputStream") - -(define version-string "1.3") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Utility functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; reload this file (convenience definition) -(define (reload) (load "mc.scm")) - -; Simple little function to report an error -(define (error msg) - (throw (Error. msg))) - -; some debug support -(define debug #f) - -(define (dprint msg) - (if debug - (.println System.out$ msg))) - -; Replace dprint with noprint to avoid seeing messages when debug is #t -(define (noprint msg) ()) - -; Helper function present so that a scheme method taking strings as args -; can be easily run from a command line. -; arg: vector containing argument strings. Element 0 is the function name -; to execute -(define (main arg) - (let* - ( - (arg-list (vector->list arg)) - (function-symbol (string->symbol (car arg-list))) - (args (cdr arg-list))) - (apply (eval function-symbol) args))) - -; Returns the position of key in lst, numbering from 0. key is matched using eqv? -(define (get-list-position key lst) - (letrec - ( - (helper (lambda (k l accum) - (cond - ((null? l) (error (string-append "Could not find " k))) - ((eqv? k (car l)) accum) - (else (helper k (cdr l) (+ accum 1))) )))) - (begin - (noprint (string-append "get-list-position called with key " key " lst " lst )) - (helper key lst 0)))) - -; Return a string representing number in decimal padded to length with leading 0s. -(define (pad-number-string number length) - (let* - ( - (number-string (number->string number)) - (pad-length (- length (string-length number-string))) - ) - (string-append (make-string pad-length #\0) number-string))) - -; Read an S-expression from a file that contains all of the data. -; -; The S-expression used for minor codes must have the structure -; (package-name class-name exception-group-name -; (exception -; (name value level explanation) -; ... -; ) -; ... -; ) -(define (read-file fname) - (read (open-input-file fname))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions for handling major system exceptions and exception groups -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Function to find the base ID given an exception group name. Result is a function that -; maps the minor code into the Java expression for that minor code's actual value. -(define (get-base group-name) - (if (eqv? group-name 'OMG) - (lambda (minor-code) - (string-append "OMGVMCID.value + " (number->string minor-code))) - (let ; bind base-number outside the lambda so it is only evaluated once - ( - (base-number (get-sun-base-number group-name))) - (lambda (minor-code) - (string-append "SUNVMCID.value + " (number->string (+ base-number minor-code))))))) - -; Function to get a base value for the group-name -(define (get-sun-base-number group-name) - (let* - ( - (lst (list 'SUNBASE 'ORBUTIL 'ACTIVATION 'NAMING 'INTERCEPTORS 'POA 'IOR 'UTIL)) - (subsystem-size 200)) - (* subsystem-size (get-list-position group-name lst)))) - -; Function to get a 3 digit number for a system exception -(define (get-exception-id exception-name) - (let - ( - (lst (list 'UNKNOWN 'BAD_PARAM 'NO_MEMORY 'IMP_LIMIT 'COMM_FAILURE 'INV_OBJREF 'NO_PERMISSION - 'INTERNAL 'MARSHAL 'INITIALIZE 'NO_IMPLEMENT 'BAD_TYPECODE 'BAD_OPERATION 'NO_RESOURCES - 'NO_RESPONSE 'PERSIST_STORE 'BAD_INV_ORDER 'TRANSIENT 'FREE_MEM 'INV_IDENT 'INV_FLAG - 'INTF_REPOS 'BAD_CONTEXT 'OBJ_ADAPTER 'DATA_CONVERSION 'OBJECT_NOT_EXIST 'TRANSACTION_REQUIRED - 'TRANSACTION_ROLLEDBACK 'INVALID_TRANSACTION 'INV_POLICY 'CODESET_INCOMPATIBLE 'REBIND - 'TIMEOUT 'TRANSACTION_UNAVAILABLE 'BAD_QOS 'INVALID_ACTIVITY 'ACTIVITY_COMPLETED - 'ACTIVITY_REQUIRED ))) - (pad-number-string (get-list-position exception-name lst) 3))) - -; Return the message id string for any system exception -; -(define (get-message-id exception-type group-name minor) - (if (eqv? group-name 'OMG) - (get-standard-message-id exception-type minor) - (get-sun-message-id exception-type group-name minor))) - -; Return the message id string for a particular standard exception -; -(define (get-standard-message-id exception-type minor) - (string-append - "IOP" - (get-exception-id exception-type) - "0" - (pad-number-string (number->string minor) 4))) - -; Return the sun message id for this exception-type, group-name, and minor code. -(define (get-sun-message-id exception-type group-name minor) - (string-append - "IOP" - (get-exception-id exception-type) - "1" - (pad-number-string (+ (get-sun-base-number group-name) minor) 4))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; visitor framework for the input file format -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define (visit-top obj func1) - (let* - ( - (package (car obj)) - (class (cadr obj)) - (group (caddr obj)) - (func2 (func1 package class group)) - (exceptions (cadddr obj))) - (visit-exceptions exceptions func2))) - -; visit the elements of an arbitrary list -; lst: the list to visit -; func: the function to apply to each element of lst -; next-level the function on lst element and func that visits the next level -(define (visit-list lst func next-level) - (if (null? (cdr lst)) - (next-level #t (car lst) func) - (begin - (next-level #f (car lst) func) - (visit-list (cdr lst) func next-level)))) - -(define (visit-exceptions exceptions func2) - (visit-list exceptions func2 (lambda (last-flag element func) (visit-exception last-flag element func)))) - -(define (visit-exception last-flag exception func2) - (let* - ( - (major (car exception)) - (minor-codes (cdr exception)) - (func3 (func2 last-flag major))) - (visit-minor-codes minor-codes func3))) - -(define (visit-minor-codes minor-codes func3) - (visit-list minor-codes func3 (lambda (last-flag element func) (visit-minor-code last-flag element func)))) - -(define (visit-minor-code last-flag minor-code func3) - (let* - ( - (name (car minor-code)) - (minor (cadr minor-code)) - (level (caddr minor-code)) - (msg (cadddr minor-code))) - (func3 last-flag name minor level msg))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The visitors -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; A simple visitor that just echoes the input for test purposes -(define (simple-visitor package class group) - (let* - ( - (pw (IndentingPrintWriter. System.out$))) - (begin - (.indent pw) - (.printMsg pw "package=@ class=@ group=@" (list package class group)) - (.flush pw) - (lambda (last-flag major) - (begin - (.indent pw) - (.printMsg pw "major=@" (list major)) - (.flush pw) - (lambda (last-flag name minor level message) - (begin - (if last-flag (.undent pw)) - (.printMsg pw "name=@ minor=@ level=@ message=@" (list name minor level message)) - (.flush pw)))))))) - -; Function that returns a visitor that writes out the resource file in the form: -; id="MSGID: explanation" -; outdir: Output directory -(define (resource-visitor outdir) - (lambda (package class group) - (let* - ( - (file-name (string-append outdir java.io.File.separator$ class ".resource")) - (pw (IndentingPrintWriter. (FileOutputStream. file-name)))) - (begin - (dprint (string-append "package= " package " class=" class " group=" group " file-name=" file-name)) - (lambda (last-flag1 major) - (begin - ; (dprint (string-append "last-flag1=" last-flag1 " major=" major)) - (lambda (last-flag2 name minor level message) - (begin - ; (dprint (string-append "last-flag2=" last-flag2 " name=" name - ; " minor=" minor " level=" level " message=" message)) - (let* - ( - (msgid (get-message-id major group minor)) - (ident (StringUtil.toMixedCase (symbol->string name)))) - (begin - ; (dprint (string-append "msgid=" msgid " ident=" ident)) - (.printMsg pw "@.@=\"@: (@) @\"" (list group ident msgid major message)) - (.flush pw) - (if (and last-flag1 last-flag2) - (begin - ; (dprint "closing file") - (.close pw))))))))))))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Top-level functions for creating the products. All have names of the form make-xxx -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Read the minor codes from the infile and write out a resource file. -(define (make-resource infile outdir) - (tryCatch - (visit-top (read-file infile) (resource-visitor outdir)) - (lambda (exc) - (begin - (.println System.out$ (string-append "make-resource failed with exception " (.toString exc))) - (System.exit 1))))) - -; Read the minor codes from the infile and write a Java implementation to -; handle them to outfile under outdir -(define (make-class infile outdir) - (tryCatch - (write-class infile outdir (read-file infile)) - (lambda (exc) - (begin - (.println System.out$ (string-append "make-class failed with exception " (.toString exc))) - (System.exit 1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; The original make-class implementation (this should be replaced by two visitors) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Write out the Java source code for the StandardExceptions class -; outdir: Output directory to write the generated files -; obj: the data from the input file -(define (write-class infile outdir obj) - (let* - ( - (package-name (car obj)) - (class-name (cadr obj)) - (exception-group-name (caddr obj)) - (exceptions (cadddr obj)) - (file (FileOutputStream. (string-append outdir java.io.File.separator$ class-name ".java"))) - (pw (IndentingPrintWriter. file)) - ) - (begin - (write-class-header infile package-name class-name exception-group-name pw) - (.printMsg pw "package @ ;" - (list package-name)) - (.println pw) - (.println pw "import java.util.logging.Logger ;") - (.println pw "import java.util.logging.Level ;") - (.println pw) - (.println pw "import org.omg.CORBA.OMGVMCID ;") - (.println pw "import com.sun.corba.se.impl.util.SUNVMCID ;") - (.println pw "import org.omg.CORBA.CompletionStatus ;") - (.println pw "import org.omg.CORBA.SystemException ;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.orb.ORB ;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.logging.LogWrapperFactory;") - (.println pw) - (.println pw "import com.sun.corba.se.spi.logging.LogWrapperBase;") - (.println pw) - (write-imports exceptions pw) - (.println pw) - (.indent pw) - (.printMsg pw "public class @ extends LogWrapperBase {" - (list class-name)) - (.println pw) - (.printMsg pw "public @( Logger logger )" - (list class-name)) - (.indent pw) - (.println pw "{") - (.undent pw) - (.println pw "super( logger ) ;") - (.println pw "}") - (.println pw) - (.flush pw) - (write-factory-method class-name exception-group-name pw) - (write-exceptions exception-group-name exceptions (get-base exception-group-name) class-name pw) - (.undent pw) - (.println pw ) - (.println pw "}") - (.flush pw) - (.close pw) - ))) - -; Write out the header for the resource file -(define (write-class-header infile package class group pw) - (begin - (if (eqv? group 'OMG) - (.println pw "// Log wrapper class for standard exceptions") - (.printMsg pw "// Log wrapper class for Sun private system exceptions in group @" (list group))) - (.println pw "//") - (.printMsg pw "// Generated by mc.scm version @, DO NOT EDIT BY HAND!" (list version-string)) - (.printMsg pw "// Generated from input file @ on @" (list infile (java.util.Date.))) - (.println pw))) - -(define (write-factory-method class-name exception-group-name pw) - (begin - (.indent pw) - (.println pw "private static LogWrapperFactory factory = new LogWrapperFactory() {") - (.println pw "public LogWrapperBase create( Logger logger )" ) - (.indent pw) - (.println pw "{") - (.undent pw) - (.printMsg pw "return new @( logger ) ;" (list class-name)) - (.undent pw) - (.println pw "}" ) - (.println pw "} ;" ) - (.println pw) - (.printMsg pw "public static @ get( ORB orb, String logDomain )" (list class-name)) - (.indent pw) - (.println pw "{") - (.indent pw) - (.printMsg pw "@ wrapper = " - (list class-name)) - (.indent pw) - (.printMsg pw "(@) orb.getLogWrapper( logDomain, " - (list class-name)) - (.undent pw) - (.undent pw) - (.printMsg pw "\"@\", factory ) ;" - (list exception-group-name)) - (.undent pw) - (.println pw "return wrapper ;" ) - (.println pw "} " ) - (.println pw) - (.printMsg pw "public static @ get( String logDomain )" (list class-name)) - (.indent pw) - (.println pw "{") - (.indent pw) - (.printMsg pw "@ wrapper = " - (list class-name)) - (.indent pw) - (.printMsg pw "(@) ORB.staticGetLogWrapper( logDomain, " - (list class-name)) - (.undent pw) - (.undent pw) - (.printMsg pw "\"@\", factory ) ;" - (list exception-group-name)) - (.undent pw) - (.println pw "return wrapper ;" ) - (.println pw "} " ) - (.println pw))) - -; Write out the import list for the exceptions listed in obj -; obj: the data from the input file -; pw: an IndentingPrintWriter for the output file -(define (write-imports obj pw) - (if (null? obj) - () - (let - ( - (exception (caar obj)) - ) - (begin - (.print pw "import org.omg.CORBA.") - (.print pw exception) - (.println pw " ;") - (write-imports (cdr obj) pw) - )))) - -; Write out the list of exceptions starting with the first one -; obj: the data from the input file -; base: the lambda that returns the string defining the minor code value -; pw: an IndentingPrintWriter for the output file -(define (write-exceptions group-name obj base class-name pw) - (if (null? obj) - () - (let* - ( - (record (car obj)) - (exception (car record)) - (minor-codes (cdr record)) - ) - (begin - (write-exception group-name exception minor-codes base class-name pw) - (write-exceptions group-name (cdr obj) base class-name pw) - )))) - -; Write out a single exception -; exception: the CORBA SystemException type -; base: the base for the minor code value -; minor-codes: a list of minor code data for each minor exception type -; pw: an IndentingPrintWriter for the output file -(define (write-exception group-name exception minor-codes base class-name pw) - (begin - (.println pw "///////////////////////////////////////////////////////////") - (.printMsg pw "// @" (list exception)) - (.println pw "///////////////////////////////////////////////////////////") - (.println pw) - (write-methods group-name exception minor-codes base class-name pw) - (.flush pw))) - -; Write all of the methods for a single exception -; exception: the CORBA SystemException type -; base: the base for the minor code value -; minor-codes: a list of minor code data for each minor exception type -; pw: an IndentingPrintWriter for the output file -(define (write-methods group-name exception minor-codes base class-name pw) - (if (null? minor-codes) - () - (begin - (write-method group-name exception (car minor-codes) base class-name pw) - (write-methods group-name exception (cdr minor-codes) base class-name pw) - ))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Code that writes out the Java methods for exception handling -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Write the methods for a single minor code within an exception -; exception: the CORBA SystemException type -; minor-code: minor code data for one minor exception type -; (name value level explanation) -; base: the base for the minor code value -; pw: an IndentingPrintWriter for the output file -(define (write-method group-name exception minor-code base class-name pw) - (let* - ( - (x (symbol->string (car minor-code))) - (ident (cons x (StringUtil.toMixedCase x))) - (value (cadr minor-code)) - (level (symbol->string (caddr minor-code))) - (explanation (cadddr minor-code)) - (num-params (StringUtil.countArgs explanation))) - (begin - (.printMsg pw "public static final int @ = @ ;" - (list x (base value))) - (.println pw ) - (.flush pw ) - (write-method-status-cause group-name exception ident level num-params class-name pw) - (.println pw) - (.flush pw) - (write-method-status exception ident level num-params pw) - (.println pw) - (.flush pw) - (write-method-cause exception ident level num-params pw) - (.println pw) - (.flush pw) - (write-method-no-args exception ident level num-params pw) - (.println pw) - (.flush pw)))) - -; Construct a string of the form arg1, ..., argn where n is num-params -(define (make-arg-string fixed leading-comma-flag num-args) - (let - ( - (helper (lambda (lcf n) - (let* - ( - (numstr (number->string (- n 1)))) - (if (or lcf (> n 1)) - (string-append ", " fixed numstr) - (string-append " " fixed numstr)))))) - (cond - ((eqv? num-args 0) " ") - ((eqv? num-args 1) (helper leading-comma-flag 1)) - (else (string-append - (make-arg-string fixed leading-comma-flag (- num-args 1)) - (helper leading-comma-flag num-args )))))) - -(define (make-decl-args leading-comma-flag num-args) - (make-arg-string "Object arg" leading-comma-flag num-args)) - -(define (make-call-args leading-comma-flag num-args) - (make-arg-string "arg" leading-comma-flag num-args)) - -; make-xxx-args patterns: -; leading-comma-flag #t -; -; 0 " " -; 1 ", arg0" -; 2 ", arg0, arg1" -; 3 ", arg0, arg1, arg2" -; -; 0 " " -; 1 ", Object arg0" -; 2 ", Object arg0, Object arg1" -; 3 ", Object arg0, Object arg1, Object arg2" -; -; leading-comma-flag #f -; -; 0 " " -; 1 " arg0" -; 2 " arg0, arg1" -; 3 " arg0, arg1, arg2" -; -; 0 " " -; 1 " Object arg0" -; 2 " Object arg0, Object arg1" -; 3 " Object arg0, Object arg1, Object arg2" - -(define (emit-assignments num pw) - (let - ( - (helper - (lambda (n) - (.printMsg pw "parameters[@] = arg@ ;" (list n n))))) - (if (= num 1) - (helper (- num 1)) - (begin - (emit-assignments (- num 1) pw) - (helper (- num 1)))))) - -; Write a method for an exception that takes a CompletionStatus and a cause -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-status-cause group-name exception id level num-params class-name pw) - (let* - ( - (ident (car id)) - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( CompletionStatus cs, Throwable t@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.printMsg pw "@ exc = new @( @, cs ) ;" - (list exception exception ident )) - - (.indent pw) - (.println pw "if (t != null)" ) - (.undent pw) - (.println pw "exc.initCause( t ) ;" ) - (.println pw) - - (.indent pw) - (.printMsg pw "if (logger.isLoggable( Level.@ )) {" - (list level)) - - (if (> num-params 0) - (begin - (.printMsg pw "Object[] parameters = new Object[@] ;" - (list (number->string num-params))) - (emit-assignments num-params pw) - ) - (begin - (.println pw "Object[] parameters = null ;" - ))) - - (.indent pw) - (.printMsg pw "doLog( Level.@, \"@.@\"," (list level group-name ident-mc)) - (.undent pw) - (.undent pw) - (.printMsg pw "parameters, @.class, exc ) ;" (list class-name)) - (.println pw "}") - (.println pw) - - (.undent pw) - (.println pw "return exc ;") - - (.println pw "}")))) - -; Write a method for an exception that takes a CompletionStatus. The cause is null. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-status exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( CompletionStatus cs@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.undent pw) - (.printMsg pw "return @( cs, null@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -; Write a method for an exception that takes a cause. The status is COMPLETED_NO. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-cause exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( Throwable t@) {" - (list exception ident-mc (make-decl-args #t num-params))) - (.undent pw) - (.printMsg pw "return @( CompletionStatus.COMPLETED_NO, t@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -; Write a method for an exception that takes no arguments. This is COMPLETED_NO and -; a null cause. -; -; exception: the CORBA system exception type -; id: the identifier for this exception in the form ( ident . mixed-case-ident ) -; level: the logging level -; num-params: number of parameters in the explanation string, which determines -; how many argn parameters we need -; pw: the indenting print writer we are using -(define (write-method-no-args exception id level num-params pw) - (let* - ( - (ident-mc (cdr id))) - (begin - (.indent pw) - (.printMsg pw "public @ @( @) {" - (list exception ident-mc (make-decl-args #f num-params))) - (.undent pw) - (.printMsg pw "return @( CompletionStatus.COMPLETED_NO, null@ ) ;" - (list ident-mc (make-call-args #t num-params))) - (.println pw "}")))) - -;;; end of file diff --git a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run b/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run deleted file mode 100644 index 81efed3479a..00000000000 --- a/corba/src/share/classes/com/sun/tools/corba/se/logutil/scripts/run +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -java -cp ${CLASSPATH}:lib/jscheme.jar:lib/util.jar jscheme.REPL mc.scm From 101468324dba1bc05323892cf8c0f8fa9b2312a7 Mon Sep 17 00:00:00 2001 From: Karen Kinnear Date: Wed, 25 Mar 2009 13:09:28 -0400 Subject: [PATCH 22/43] 6603316: Improve instrumentation for classes loaded at startup Reviewed-by: xlu, mchung --- .../share/vm/classfile/classFileParser.cpp | 4 +-- hotspot/src/share/vm/prims/jni.cpp | 15 ++++++++++- hotspot/src/share/vm/prims/jvm.cpp | 26 ++++++++++++++----- hotspot/src/share/vm/prims/jvm_misc.hpp | 1 + 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index b1f61dcf69a..119b95adf46 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -3230,7 +3230,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, // print out the superclass. const char * from = Klass::cast(this_klass())->external_name(); if (this_klass->java_super() != NULL) { - tty->print("RESOLVE %s %s\n", from, instanceKlass::cast(this_klass->java_super())->external_name()); + tty->print("RESOLVE %s %s (super)\n", from, instanceKlass::cast(this_klass->java_super())->external_name()); } // print out each of the interface classes referred to by this class. objArrayHandle local_interfaces(THREAD, this_klass->local_interfaces()); @@ -3240,7 +3240,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, klassOop k = klassOop(local_interfaces->obj_at(i)); instanceKlass* to_class = instanceKlass::cast(k); const char * to = to_class->external_name(); - tty->print("RESOLVE %s %s\n", from, to); + tty->print("RESOLVE %s %s (interface)\n", from, to); } } } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index bd4f1ec3223..bde5dba7771 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -301,6 +301,10 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader, Handle(), &st, CHECK_NULL); + if (TraceClassResolution && k != NULL) { + trace_class_resolution(k); + } + cls = (jclass)JNIHandles::make_local( env, Klass::cast(k)->java_mirror()); return cls; @@ -365,6 +369,10 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name)) result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, thread); + if (TraceClassResolution && result != NULL) { + trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); + } + // If we were the first invocation of jni_FindClass, we enable compilation again // rather than just allowing invocation counter to overflow and decay. // Controlled by flag DelayCompilationDuringStartup. @@ -2646,7 +2654,12 @@ static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) { Handle protection_domain; // null protection domain symbolHandle sym = oopFactory::new_symbol_handle(name, CHECK_NULL); - return find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); + jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); + + if (TraceClassResolution && result != NULL) { + trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); + } + return result; } // These lookups are done with the NULL (bootstrap) ClassLoader to diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index cf866df9f61..5d341330506 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -64,6 +64,7 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { ResourceMark rm; int line_number = -1; const char * source_file = NULL; + const char * trace = "explicit"; klassOop caller = NULL; JavaThread* jthread = JavaThread::current(); if (jthread->has_last_Java_frame()) { @@ -107,12 +108,21 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { (last_caller->name() == vmSymbols::loadClassInternal_name() || last_caller->name() == vmSymbols::loadClass_name())) { found_it = true; + } else if (!vfst.at_end()) { + if (vfst.method()->is_native()) { + // JNI call + found_it = true; + } } if (found_it && !vfst.at_end()) { // found the caller caller = vfst.method()->method_holder(); line_number = vfst.method()->line_number_from_bci(vfst.bci()); - symbolOop s = instanceKlass::cast(vfst.method()->method_holder())->source_file_name(); + if (line_number == -1) { + // show method name if it's a native method + trace = vfst.method()->name_and_sig_as_C_string(); + } + symbolOop s = instanceKlass::cast(caller)->source_file_name(); if (s != NULL) { source_file = s->as_C_string(); } @@ -124,15 +134,15 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) { const char * to = Klass::cast(to_class)->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - tty->print("RESOLVE %s %s %s:%d (explicit)\n", from, to, source_file, line_number); + tty->print("RESOLVE %s %s %s:%d (%s)\n", from, to, source_file, line_number, trace); } else { - tty->print("RESOLVE %s %s (explicit)\n", from, to); + tty->print("RESOLVE %s %s (%s)\n", from, to, trace); } } } } -static void trace_class_resolution(klassOop to_class) { +void trace_class_resolution(klassOop to_class) { EXCEPTION_MARK; trace_class_resolution_impl(to_class, THREAD); if (HAS_PENDING_EXCEPTION) { @@ -3213,8 +3223,12 @@ JVM_ENTRY(jclass, JVM_LoadClass0(JNIEnv *env, jobject receiver, } Handle h_loader(THREAD, loader); Handle h_prot (THREAD, protection_domain); - return find_class_from_class_loader(env, name, true, h_loader, h_prot, - false, thread); + jclass result = find_class_from_class_loader(env, name, true, h_loader, h_prot, + false, thread); + if (TraceClassResolution && result != NULL) { + trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); + } + return result; JVM_END diff --git a/hotspot/src/share/vm/prims/jvm_misc.hpp b/hotspot/src/share/vm/prims/jvm_misc.hpp index 7af47518c0f..50644842bbd 100644 --- a/hotspot/src/share/vm/prims/jvm_misc.hpp +++ b/hotspot/src/share/vm/prims/jvm_misc.hpp @@ -27,6 +27,7 @@ jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS); +void trace_class_resolution(klassOop to_class); /* * Support for Serialization and RMI. Currently used by HotSpot only. From cec3a034d180a3b3026d6760b3639e28620398b2 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 25 Mar 2009 14:19:20 -0400 Subject: [PATCH 23/43] 6541756: Reduce executable C-heap Add executable parameters to reserve_memory and commit_memory to reduce executable memory to only the Code Heap. Reviewed-by: xlu, kvn, acorn --- hotspot/src/os/linux/vm/os_linux.cpp | 22 ++++---- hotspot/src/os/solaris/vm/os_solaris.cpp | 15 +++--- hotspot/src/os/windows/vm/os_windows.cpp | 50 ++++++++++++------- hotspot/src/share/vm/memory/heap.cpp | 2 +- hotspot/src/share/vm/runtime/os.hpp | 9 ++-- hotspot/src/share/vm/runtime/virtualspace.cpp | 49 +++++++++++++----- hotspot/src/share/vm/runtime/virtualspace.hpp | 33 ++++++++---- 7 files changed, 122 insertions(+), 58 deletions(-) diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 1b892e7eafe..3788eac461e 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2269,15 +2269,16 @@ void linux_wrap_code(char* base, size_t size) { // All it does is to check if there are enough free pages // left at the time of mmap(). This could be a potential // problem. -bool os::commit_memory(char* addr, size_t size) { - uintptr_t res = (uintptr_t) ::mmap(addr, size, - PROT_READ|PROT_WRITE|PROT_EXEC, +bool os::commit_memory(char* addr, size_t size, bool exec) { + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; + uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); return res != (uintptr_t) MAP_FAILED; } -bool os::commit_memory(char* addr, size_t size, size_t alignment_hint) { - return commit_memory(addr, size); +bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, + bool exec) { + return commit_memory(addr, size, exec); } void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } @@ -2417,8 +2418,7 @@ os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory; unsigned long* os::Linux::_numa_all_nodes; bool os::uncommit_memory(char* addr, size_t size) { - return ::mmap(addr, size, - PROT_READ|PROT_WRITE|PROT_EXEC, + return ::mmap(addr, size, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0) != MAP_FAILED; } @@ -2441,7 +2441,9 @@ static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) { flags |= MAP_FIXED; } - addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE|PROT_EXEC, + // Map uncommitted pages PROT_READ and PROT_WRITE, change access + // to PROT_EXEC if executable when we commit the page. + addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE, flags, -1, 0); if (addr != MAP_FAILED) { @@ -2582,7 +2584,9 @@ bool os::large_page_init() { #define SHM_HUGETLB 04000 #endif -char* os::reserve_memory_special(size_t bytes, char* req_addr) { +char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { + // "exec" is passed in but not used. Creating the shared image for + // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages, "only for large pages"); key_t key = IPC_PRIVATE; diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 165c71e659f..23b4ff2f5f2 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -2623,15 +2623,16 @@ int os::vm_allocation_granularity() { return page_size; } -bool os::commit_memory(char* addr, size_t bytes) { +bool os::commit_memory(char* addr, size_t bytes, bool exec) { + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; size_t size = bytes; return - NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, - PROT_READ | PROT_WRITE | PROT_EXEC); + NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); } -bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint) { - if (commit_memory(addr, bytes)) { +bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint, + bool exec) { + if (commit_memory(addr, bytes, exec)) { if (UseMPSS && alignment_hint > (size_t)vm_page_size()) { // If the large page size has been set and the VM // is using large pages, use the large page size @@ -3220,7 +3221,9 @@ bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) { return true; } -char* os::reserve_memory_special(size_t bytes, char* addr) { +char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { + // "exec" is passed in but not used. Creating the shared image for + // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages && UseISM, "only for ISM large pages"); size_t size = bytes; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index dd280bb4fbf..cc3c6202d65 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2189,7 +2189,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base() ) { addr = (address)((uintptr_t)addr & (~((uintptr_t)os::vm_page_size() - (uintptr_t)1))); - os::commit_memory( (char *)addr, thread->stack_base() - addr ); + os::commit_memory((char *)addr, thread->stack_base() - addr, + false ); return EXCEPTION_CONTINUE_EXECUTION; } else @@ -2565,8 +2566,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { assert((size_t)addr % os::vm_allocation_granularity() == 0, "reserve alignment"); assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size"); - char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, - PAGE_EXECUTE_READWRITE); + char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE); assert(res == NULL || addr == NULL || addr == res, "Unexpected address from reserve."); return res; @@ -2595,7 +2595,7 @@ bool os::can_execute_large_page_memory() { return true; } -char* os::reserve_memory_special(size_t bytes, char* addr) { +char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { if (UseLargePagesIndividualAllocation) { if (TracePageSizes && Verbose) { @@ -2618,7 +2618,7 @@ char* os::reserve_memory_special(size_t bytes, char* addr) { p_buf = (char *) VirtualAlloc(addr, size_of_reserve, // size of Reserve MEM_RESERVE, - PAGE_EXECUTE_READWRITE); + PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; @@ -2659,7 +2659,13 @@ char* os::reserve_memory_special(size_t bytes, char* addr) { p_new = (char *) VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, - PAGE_EXECUTE_READWRITE); + PAGE_READWRITE); + if (p_new != NULL && exec) { + DWORD oldprot; + // Windows doc says to use VirtualProtect to get execute permissions + VirtualProtect(next_alloc_addr, bytes_to_rq, + PAGE_EXECUTE_READWRITE, &oldprot); + } } if (p_new == NULL) { @@ -2688,10 +2694,12 @@ char* os::reserve_memory_special(size_t bytes, char* addr) { } else { // normal policy just allocate it all at once DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; - char * res = (char *)VirtualAlloc(NULL, - bytes, - flag, - PAGE_EXECUTE_READWRITE); + char * res = (char *)VirtualAlloc(NULL, bytes, flag, PAGE_READWRITE); + if (res != NULL && exec) { + DWORD oldprot; + // Windows doc says to use VirtualProtect to get execute permissions + VirtualProtect(res, bytes, PAGE_EXECUTE_READWRITE, &oldprot); + } return res; } } @@ -2703,7 +2711,7 @@ bool os::release_memory_special(char* base, size_t bytes) { void os::print_statistics() { } -bool os::commit_memory(char* addr, size_t bytes) { +bool os::commit_memory(char* addr, size_t bytes, bool exec) { if (bytes == 0) { // Don't bother the OS with noops. return true; @@ -2712,11 +2720,19 @@ bool os::commit_memory(char* addr, size_t bytes) { assert(bytes % os::vm_page_size() == 0, "commit in page-sized chunks"); // Don't attempt to print anything if the OS call fails. We're // probably low on resources, so the print itself may cause crashes. - return VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE) != NULL; + bool result = VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) != 0; + if (result != NULL && exec) { + DWORD oldprot; + // Windows doc says to use VirtualProtect to get execute permissions + return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot) != 0; + } else { + return result; + } } -bool os::commit_memory(char* addr, size_t size, size_t alignment_hint) { - return commit_memory(addr, size); +bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, + bool exec) { + return commit_memory(addr, size, exec); } bool os::uncommit_memory(char* addr, size_t bytes) { @@ -2750,7 +2766,7 @@ bool os::protect_memory(char* addr, size_t bytes, ProtType prot, // Strange enough, but on Win32 one can change protection only for committed // memory, not a big deal anyway, as bytes less or equal than 64K - if (!is_committed && !commit_memory(addr, bytes)) { + if (!is_committed && !commit_memory(addr, bytes, prot == MEM_PROT_RWX)) { fatal("cannot commit protection page"); } // One cannot use os::guard_memory() here, as on Win32 guard page @@ -3248,10 +3264,10 @@ jint os::init_2(void) { #endif if (!UseMembar) { - address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_EXECUTE_READWRITE); + address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_READWRITE); guarantee( mem_serialize_page != NULL, "Reserve Failed for memory serialize page"); - return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_READWRITE); guarantee( return_page != NULL, "Commit Failed for memory serialize page"); os::set_memory_serialize_page( mem_serialize_page ); diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index b0986d1e3ff..ced1bf23c01 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -112,7 +112,7 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size, const size_t rs_align = page_size == (size_t) os::vm_page_size() ? 0 : MAX2(page_size, granularity); - ReservedSpace rs(r_size, rs_align, rs_align > 0); + ReservedCodeSpace rs(r_size, rs_align, rs_align > 0); os::trace_page_sizes("code heap", committed_size, reserved_size, page_size, rs.base(), rs.size()); if (!_memory.initialize(rs, c_size)) { diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index a245a56782f..e655d3e34b0 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -202,8 +202,10 @@ class os: AllStatic { static char* attempt_reserve_memory_at(size_t bytes, char* addr); static void split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool commit_memory(char* addr, size_t bytes); - static bool commit_memory(char* addr, size_t size, size_t alignment_hint); + static bool commit_memory(char* addr, size_t bytes, + bool executable = false); + static bool commit_memory(char* addr, size_t size, size_t alignment_hint, + bool executable = false); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); @@ -243,7 +245,8 @@ class os: AllStatic { static char* non_memory_address_word(); // reserve, commit and pin the entire memory region - static char* reserve_memory_special(size_t size, char* addr = NULL); + static char* reserve_memory_special(size_t size, char* addr = NULL, + bool executable = false); static bool release_memory_special(char* addr, size_t bytes); static bool large_page_init(); static size_t large_page_size(); diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index 8ade3eb6abe..e6e4b55a690 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -28,7 +28,7 @@ // ReservedSpace ReservedSpace::ReservedSpace(size_t size) { - initialize(size, 0, false, NULL, 0); + initialize(size, 0, false, NULL, 0, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, @@ -36,7 +36,13 @@ ReservedSpace::ReservedSpace(size_t size, size_t alignment, char* requested_address, const size_t noaccess_prefix) { initialize(size+noaccess_prefix, alignment, large, requested_address, - noaccess_prefix); + noaccess_prefix, false); +} + +ReservedSpace::ReservedSpace(size_t size, size_t alignment, + bool large, + bool executable) { + initialize(size, alignment, large, NULL, 0, executable); } char * @@ -132,7 +138,8 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, const bool try_reserve_special = UseLargePages && prefix_align == os::large_page_size(); if (!os::can_commit_large_page_memory() && try_reserve_special) { - initialize(size, prefix_align, true, requested_address, noaccess_prefix); + initialize(size, prefix_align, true, requested_address, noaccess_prefix, + false); return; } @@ -141,6 +148,7 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, _alignment = 0; _special = false; _noaccess_prefix = 0; + _executable = false; // Assert that if noaccess_prefix is used, it is the same as prefix_align. assert(noaccess_prefix == 0 || @@ -189,7 +197,8 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* requested_address, - const size_t noaccess_prefix) { + const size_t noaccess_prefix, + bool executable) { const size_t granularity = os::vm_allocation_granularity(); assert((size & granularity - 1) == 0, "size not aligned to os::vm_allocation_granularity()"); @@ -201,6 +210,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, _base = NULL; _size = 0; _special = false; + _executable = executable; _alignment = 0; _noaccess_prefix = 0; if (size == 0) { @@ -214,7 +224,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, if (special) { - base = os::reserve_memory_special(size, requested_address); + base = os::reserve_memory_special(size, requested_address, executable); if (base != NULL) { // Check alignment constraints @@ -284,7 +294,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, - bool special) { + bool special, bool executable) { assert((size % os::vm_allocation_granularity()) == 0, "size not allocation aligned"); _base = base; @@ -292,6 +302,7 @@ ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, _alignment = alignment; _noaccess_prefix = 0; _special = special; + _executable = executable; } @@ -299,9 +310,10 @@ ReservedSpace ReservedSpace::first_part(size_t partition_size, size_t alignment, bool split, bool realloc) { assert(partition_size <= size(), "partition failed"); if (split) { - os::split_reserved_memory(_base, _size, partition_size, realloc); + os::split_reserved_memory(base(), size(), partition_size, realloc); } - ReservedSpace result(base(), partition_size, alignment, special()); + ReservedSpace result(base(), partition_size, alignment, special(), + executable()); return result; } @@ -310,7 +322,7 @@ ReservedSpace ReservedSpace::last_part(size_t partition_size, size_t alignment) { assert(partition_size <= size(), "partition failed"); ReservedSpace result(base() + partition_size, size() - partition_size, - alignment, special()); + alignment, special(), executable()); return result; } @@ -348,6 +360,7 @@ void ReservedSpace::release() { _size = 0; _noaccess_prefix = 0; _special = false; + _executable = false; } } @@ -396,6 +409,14 @@ ReservedHeapSpace::ReservedHeapSpace(const size_t prefix_size, protect_noaccess_prefix(prefix_size+suffix_size); } +// Reserve space for code segment. Same as Java heap only we mark this as +// executable. +ReservedCodeSpace::ReservedCodeSpace(size_t r_size, + size_t rs_align, + bool large) : + ReservedSpace(r_size, rs_align, large, /*executable*/ true) { +} + // VirtualSpace VirtualSpace::VirtualSpace() { @@ -413,6 +434,7 @@ VirtualSpace::VirtualSpace() { _middle_alignment = 0; _upper_alignment = 0; _special = false; + _executable = false; } @@ -426,6 +448,7 @@ bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { _high = low(); _special = rs.special(); + _executable = rs.executable(); // When a VirtualSpace begins life at a large size, make all future expansion // and shrinking occur aligned to a granularity of large pages. This avoids @@ -483,6 +506,7 @@ void VirtualSpace::release() { _middle_alignment = 0; _upper_alignment = 0; _special = false; + _executable = false; } @@ -592,7 +616,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { assert(low_boundary() <= lower_high() && lower_high() + lower_needs <= lower_high_boundary(), "must not expand beyond region"); - if (!os::commit_memory(lower_high(), lower_needs)) { + if (!os::commit_memory(lower_high(), lower_needs, _executable)) { debug_only(warning("os::commit_memory failed")); return false; } else { @@ -603,7 +627,8 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { assert(lower_high_boundary() <= middle_high() && middle_high() + middle_needs <= middle_high_boundary(), "must not expand beyond region"); - if (!os::commit_memory(middle_high(), middle_needs, middle_alignment())) { + if (!os::commit_memory(middle_high(), middle_needs, middle_alignment(), + _executable)) { debug_only(warning("os::commit_memory failed")); return false; } @@ -613,7 +638,7 @@ bool VirtualSpace::expand_by(size_t bytes, bool pre_touch) { assert(middle_high_boundary() <= upper_high() && upper_high() + upper_needs <= upper_high_boundary(), "must not expand beyond region"); - if (!os::commit_memory(upper_high(), upper_needs)) { + if (!os::commit_memory(upper_high(), upper_needs, _executable)) { debug_only(warning("os::commit_memory failed")); return false; } else { diff --git a/hotspot/src/share/vm/runtime/virtualspace.hpp b/hotspot/src/share/vm/runtime/virtualspace.hpp index b6e5a71099b..f412d11ad55 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.hpp +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp @@ -32,12 +32,15 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { size_t _noaccess_prefix; size_t _alignment; bool _special; + bool _executable; // ReservedSpace - ReservedSpace(char* base, size_t size, size_t alignment, bool special); + ReservedSpace(char* base, size_t size, size_t alignment, bool special, + bool executable); void initialize(size_t size, size_t alignment, bool large, char* requested_address, - const size_t noaccess_prefix); + const size_t noaccess_prefix, + bool executable); // Release parts of an already-reserved memory region [addr, addr + len) to // get a new region that has "compound alignment." Return the start of the @@ -75,16 +78,16 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { const size_t suffix_size, const size_t suffix_align, char* requested_address, const size_t noaccess_prefix = 0); + ReservedSpace(size_t size, size_t alignment, bool large, bool executable); // Accessors - char* base() const { return _base; } - size_t size() const { return _size; } - size_t alignment() const { return _alignment; } - bool special() const { return _special; } - - size_t noaccess_prefix() const { return _noaccess_prefix; } - - bool is_reserved() const { return _base != NULL; } + char* base() const { return _base; } + size_t size() const { return _size; } + size_t alignment() const { return _alignment; } + bool special() const { return _special; } + bool executable() const { return _executable; } + size_t noaccess_prefix() const { return _noaccess_prefix; } + bool is_reserved() const { return _base != NULL; } void release(); // Splitting @@ -126,6 +129,13 @@ public: char* requested_address); }; +// Class encapsulating behavior specific memory space for Code +class ReservedCodeSpace : public ReservedSpace { + public: + // Constructor + ReservedCodeSpace(size_t r_size, size_t rs_align, bool large); +}; + // VirtualSpace is data structure for committing a previously reserved address range in smaller chunks. class VirtualSpace VALUE_OBJ_CLASS_SPEC { @@ -143,6 +153,9 @@ class VirtualSpace VALUE_OBJ_CLASS_SPEC { // os::commit_memory() or os::uncommit_memory(). bool _special; + // Need to know if commit should be executable. + bool _executable; + // MPSS Support // Each virtualspace region has a lower, middle, and upper region. // Each region has an end boundary and a high pointer which is the From ab419e86a9333761e8a5dac71174dddd8090d249 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:48:03 -0700 Subject: [PATCH 24/43] 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- jaxp/make/jprt.config | 241 ------------------------------------------ 1 file changed, 241 deletions(-) delete mode 100644 jaxp/make/jprt.config diff --git a/jaxp/make/jprt.config b/jaxp/make/jprt.config deleted file mode 100644 index 90200b1bc41..00000000000 --- a/jaxp/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 7bb1e5eae12579b28e9b82ba45d0b66ff5c968c3 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:48:29 -0700 Subject: [PATCH 25/43] 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- jaxws/make/jprt.config | 241 ----------------------------------------- 1 file changed, 241 deletions(-) delete mode 100644 jaxws/make/jprt.config diff --git a/jaxws/make/jprt.config b/jaxws/make/jprt.config deleted file mode 100644 index 90200b1bc41..00000000000 --- a/jaxws/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 69c8b43f099f6472a1018d84b2535d3ee9fb0437 Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:48:53 -0700 Subject: [PATCH 26/43] 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- langtools/make/jprt.config | 241 ------------------------------------- 1 file changed, 241 deletions(-) delete mode 100644 langtools/make/jprt.config diff --git a/langtools/make/jprt.config b/langtools/make/jprt.config deleted file mode 100644 index b112bcb1eda..00000000000 --- a/langtools/make/jprt.config +++ /dev/null @@ -1,241 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# Windows Only: -# PATH -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# -# Output environment variables: -# PATH -# Windows Only: -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Add basic solaris system paths - path4sdk=/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${slashjava}/devtools/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Add basic paths - path4sdk=/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk=${antbindir}:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - -else - - # Windows: Differs on CYGWIN vs. MKS - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${slashjava}/devtools/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Ant - ANT_HOME=${slashjava}/devtools/share/ant/1.7.0 - export ANT_HOME - antbindir=${ANT_HOME}/bin - fileMustExist "${antbindir}/ant" ant - path4sdk="${antbindir};${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 2ce9a96c0120c46a85b281d4cf92f002cc2aad2f Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Thu, 26 Mar 2009 16:52:00 -0700 Subject: [PATCH 27/43] 6822374: Windows: detect X64 when PROCESSOR_IDENTIFIER contains EM64T or Intel64 6822913: Consolidate make/jprt.config files, let JPRT manage this file make it optional in repos Reviewed-by: tbell --- jdk/make/common/shared/Platform.gmk | 18 +- jdk/make/jdk_generic_profile.sh | 3 +- jdk/make/jprt.config | 363 ---------------------------- 3 files changed, 16 insertions(+), 368 deletions(-) delete mode 100644 jdk/make/jprt.config diff --git a/jdk/make/common/shared/Platform.gmk b/jdk/make/common/shared/Platform.gmk index d343cdea1c3..e07de2499fb 100644 --- a/jdk/make/common/shared/Platform.gmk +++ b/jdk/make/common/shared/Platform.gmk @@ -229,11 +229,19 @@ ifeq ($(PLATFORM), windows) TEMP_DISK=C:/temp # GNU Make or MKS overrides $(PROCESSOR_ARCHITECTURE) to always # return "x86". Use the first word of $(PROCESSOR_IDENTIFIER) instead. + PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) + PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) + PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) ifndef ARCH_DATA_MODEL - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) + ifeq ($(PROC_ARCH),IA64) ARCH_DATA_MODEL=64 else - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),AMD64) + ifeq ($(PROC_ARCH),X64) ARCH_DATA_MODEL=64 else ARCH_DATA_MODEL=32 @@ -245,10 +253,12 @@ ifeq ($(PLATFORM), windows) # If the user wants to perform a cross compile build then they must # - set ARCH_DATA_MODEL=64 and either # + set ARCH to ia64 or amd64, or - ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)), AMD64) + ifeq ($(PROC_ARCH),X64) ARCH=amd64 else - ARCH=ia64 + ifeq ($(PROC_ARCH),IA64) + ARCH=ia64 + endif endif LIBARCH=$(ARCH) # Value of Java os.arch property diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 32dd86197ef..125198301ca 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -174,7 +174,8 @@ else # Check CYGWIN (should have already been done) # Assumption here is that you are in a shell window via cygwin. - if [ "$(echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64)" != "" ] ; then + proc_arch=`echo "$(PROCESSOR_IDENTIFIER)" | expand | cut -d' ' -f1 | sed -e 's@x86@X86@g' -e 's@Intel64@X64@g' -e 's@em64t@X64@g' -e 's@EM64T@X64@g' -e 's@amd64@X64@g' -e 's@AMD64@X64@g' -e 's@ia64@IA64@g'` + if [ "${proc_arch}" = "X64" ] ; then windows_arch=amd64 else windows_arch=i586 diff --git a/jdk/make/jprt.config b/jdk/make/jprt.config deleted file mode 100644 index d720475cecd..00000000000 --- a/jdk/make/jprt.config +++ /dev/null @@ -1,363 +0,0 @@ -#!echo "This is not a shell script" -############################################################################# -# -# Copyright 2006-2008 Sun Microsystems, Inc. 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. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# -############################################################################# -# -# JPRT shell configuration for building. -# -# Input environment variables: -# ALT_BOOTDIR -# ALT_SLASH_JAVA -# ALT_JDK_IMPORT_PATH -# OPENJDK -# Windows Only: -# PATH -# VS71COMNTOOLS -# PROCESSOR_IDENTIFIER -# ROOTDIR -# -# Output variable settings: -# make Full path to GNU make -# compiler_path Path to compiler bin directory -# compiler_name Unique name of this compiler -# -# Output environment variables: -# PATH -# ALT_COMPILER_PATH -# OPENJDK only: -# ALT_CLOSED_JDK_IMPORT_PATH -# ALT_JDK_DEVTOOLS_DIR -# Windows Only: -# ALT_MSDEVTOOLS_PATH -# ALT_DEVTOOLS_PATH (To avoid the C:/UTILS default) -# LIB -# INCLUDE -# -# After JDK6, most settings will be found via ALT_SLASH_JAVA or -# by way of other system environment variables. If this was JDK5 -# or an older JDK, you might need to export more ALT_* variables. -# -# On Windows AMD64, if MSSDK is not set, assumes Platform SDK is installed at: -# C:/Program Files/Microsoft Platform SDK -# -############################################################################# - -############################################################################# -# Error -error() # message -{ - echo "ERROR: $1" - exit 6 -} -# Directory must exist -dirMustExist() # dir name -{ - if [ ! -d "$1" ] ; then - error "Directory for $2 does not exist: $1" - fi -} -# File must exist -fileMustExist() # dir name -{ - if [ ! -f "$1" ] ; then - error "File for $2 does not exist: $1" - fi -} -############################################################################# - -# Should be set by JPRT as the 3 basic inputs -bootdir="${ALT_BOOTDIR}" -slashjava="${ALT_SLASH_JAVA}" -jdk_import="${ALT_JDK_IMPORT_PATH}" - -# The /java/devtools items -jdk_devtools="${slashjava}/devtools" -share="${jdk_devtools}/share" - -# Needed for langtools, maybe other parts of the build -ANT_HOME="${share}/ant/latest" -export ANT_HOME - -# The 3 bin directories in common to all platforms -sharebin="${share}/bin" -antbin="${ANT_HOME}/bin" - -# Check input -dirMustExist "${bootdir}" ALT_BOOTDIR -dirMustExist "${slashjava}" ALT_SLASH_JAVA -dirMustExist "${jdk_import}" ALT_JDK_IMPORT_PATH -dirMustExist "${ANT_HOME}" ANT_HOME - -# Use the JDK import for now (FIXME: use the binary plugs?) -if [ "${OPENJDK}" = true ] ; then - ALT_CLOSED_JDK_IMPORT_PATH="${jdk_import}" - export ALT_CLOSED_JDK_IMPORT_PATH -fi - -# Uses 'uname -s', but only expect SunOS or Linux, assume Windows otherwise. -osname=`uname -s` -if [ "${osname}" = SunOS ] ; then - - # SOLARIS: Sparc or X86 - osarch=`uname -p` - if [ "${osarch}" = sparc ] ; then - solaris_arch=sparc - else - solaris_arch=i386 - fi - - # Get the compilers into path (make sure it matches ALT setting) - if [ "${JPRT_SOLARIS_COMPILER_NAME}" != "" ] ; then - compiler_name=${JPRT_SOLARIS_COMPILER_NAME} - else - compiler_name=SS12 - fi - compiler_path=${jdk_devtools}/${solaris_arch}/SUNWspro/${compiler_name}/bin - ALT_COMPILER_PATH="${compiler_path}" - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin} - - # Add basic solaris system paths - path4sdk=${path4sdk}:/usr/ccs/bin:/usr/ccs/lib:/usr/bin:/bin:/usr/sfw/bin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=/opt/sfw/bin/gmake - if [ ! -f ${make} ] ; then - make=${jdk_devtools}/${solaris_arch}/bin/gnumake - fi - fi - fileMustExist "${make}" make - - # File creation mask - umask 002 - -elif [ "${osname}" = Linux ] ; then - - # LINUX: X86, AMD64 - osarch=`uname -m` - if [ "${osarch}" = i686 ] ; then - linux_arch=i586 - elif [ "${osarch}" = x86_64 ] ; then - linux_arch=amd64 - fi - - # Get the compilers into path (make sure it matches ALT setting) - compiler_path=/usr/bin - compiler_name=usr_bin - ALT_COMPILER_PATH="${compiler_path}" - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - path4sdk=${compiler_path}:${sharebin}:${antbin} - - # Add basic paths - path4sdk=${path4sdk}:/usr/bin:/bin:/usr/sbin:/sbin - - # Get the previous JDK to be used to bootstrap the build - path4sdk=${bootdir}/bin:${path4sdk} - - # Find GNU make - make=/usr/bin/make - fileMustExist "${make}" make - - umask 002 - - # Linux platform may be old, use motif files from the devtools area - if [ "${OPENJDK}" = true ] ; then - ALT_JDK_DEVTOOLS_DIR="${jdk_devtools}" - export ALT_JDK_DEVTOOLS_DIR - fi - - -else - - # Windows: Differs on CYGWIN vs. MKS, and the compiler available. - # Also, blanks in pathnames gives GNU make headaches, so anything placed - # in any ALT_* variable should be the short windows dosname. - - # WINDOWS: Install and use MKS or CYGWIN (should have already been done) - # Assumption here is that you are in a shell window via MKS or cygwin. - # MKS install should have defined the environment variable ROOTDIR. - # We also need to figure out which one we have: X86, AMD64 - if [ "`echo ${PROCESSOR_IDENTIFIER} | fgrep AMD64`" != "" ] ; then - windows_arch=amd64 - else - windows_arch=i586 - fi - - # We need to determine if we are running a CYGWIN shell or an MKS shell - # (if uname isn't available, then it will be unix_toolset=unknown) - unix_toolset=unknown - if [ "`uname -a | fgrep Cygwin`" = "" -a -d "${ROOTDIR}" ] ; then - # We kind of assume ROOTDIR is where MKS is and it's ok - unix_toolset=MKS - mkshome=`dosname -s "${ROOTDIR}"` - # Utility to convert to short pathnames without spaces - dosname="${mkshome}/mksnt/dosname -s" - # Most unix utilities are in the mksnt directory of ROOTDIR - unixcommand_path="${mkshome}/mksnt" - path4sdk="${sharebin};${antbin};${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - devtools_path="${jdk_devtools}/win32/bin" - path4sdk="${devtools_path};${path4sdk}" - # Normally this need not be set, but on Windows it's default is C:/UTILS - ALT_DEVTOOLS_PATH="${devtools_path}" - export ALT_DEVTOOLS_PATH - dirMustExist "${devtools_path}" ALT_DEVTOOLS_PATH - # Find GNU make - make="${devtools_path}/gnumake.exe" - fileMustExist "${make}" make - elif [ "`uname -a | fgrep Cygwin`" != "" -a -f /bin/cygpath ] ; then - # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist - unix_toolset=CYGWIN - # Utility to convert to short pathnames without spaces - dosname="/usr/bin/cygpath -a -m -s" - # Most unix utilities are in the /usr/bin - unixcommand_path="/usr/bin" - path4sdk="${sharebin};${antbin};${unixcommand_path}" - dirMustExist "${unixcommand_path}" ALT_UNIXCOMMAND_PATH - # Find GNU make - make="${unixcommand_path}/make.exe" - fileMustExist "${make}" make - else - echo "WARNING: Cannot figure out if this is MKS or CYGWIN" - fi - - # WINDOWS: Compiler setup (nasty part) - # NOTE: You can use vcvars32.bat to set PATH, LIB, and INCLUDE. - # NOTE: CYGWIN has a link.exe too, make sure the compilers are first - if [ "${windows_arch}" = i586 ] ; then - # 32bit Windows compiler settings - # VisualStudio .NET 2003 VC++ 7.1 (VS71COMNTOOLS should be defined) - vs_root=`${dosname} "${VS71COMNTOOLS}/../.."` - # Fill in PATH, LIB, and INCLUDE (unset all others to make sure) - msdev_root="${vs_root}/Common7/Tools" - msdevtools_path="${msdev_root}/bin" - vc7_root="${vs_root}/Vc7" - compiler_path="${vc7_root}/bin" - compiler_name=VS2003 - platform_sdk="${vc7_root}/PlatformSDK" - # LIB and INCLUDE must use ; as a separator - include4sdk="${vc7_root}/atlmfc/include" - include4sdk="${include4sdk};${vc7_root}/include" - include4sdk="${include4sdk};${platform_sdk}/include/prerelease" - include4sdk="${include4sdk};${platform_sdk}/include" - include4sdk="${include4sdk};${vs_root}/SDK/v1.1/include" - lib4sdk="${vc7_root}/atlmfc/lib" - lib4sdk="${lib4sdk};${vc7_root}/lib" - lib4sdk="${lib4sdk};${platform_sdk}/lib/prerelease" - lib4sdk="${lib4sdk};${platform_sdk}/lib" - lib4sdk="${lib4sdk};${vs_root}/SDK/v1.1/lib" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${vs_root}/Common7/Tools/bin;${path4sdk}" - path4sdk="${vs_root}/SDK/v1.1/bin;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools;${path4sdk}" - path4sdk="${vs_root}/Common7/Tools/bin/prerelease;${path4sdk}" - path4sdk="${vs_root}/Common7/IDE;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - elif [ "${windows_arch}" = amd64 ] ; then - # AMD64 64bit Windows compiler settings - if [ "${MSSDK}" != "" ] ; then - platform_sdk="${MSSDK}" - else - platform_sdk=`${dosname} "C:/Program Files/Microsoft Platform SDK/"` - fi - compiler_path="${platform_sdk}/Bin/win64/x86/AMD64" - compiler_name=VS2005_PSDK - msdevtools_path="${platform_sdk}/Bin" - # LIB and INCLUDE must use ; as a separator - include4sdk="${platform_sdk}/Include" - include4sdk="${include4sdk};${platform_sdk}/Include/crt/sys" - include4sdk="${include4sdk};${platform_sdk}/Include/mfc" - include4sdk="${include4sdk};${platform_sdk}/Include/atl" - include4sdk="${include4sdk};${platform_sdk}/Include/crt" - lib4sdk="${platform_sdk}/Lib/AMD64" - lib4sdk="${lib4sdk};${platform_sdk}/Lib/AMD64/atlmfc" - # Search path and DLL locating path - # WARNING: CYGWIN has a link.exe too, make sure compilers are first - path4sdk="${platform_sdk}/bin;${path4sdk}" - path4sdk="${compiler_path};${path4sdk}" - fi - # Export LIB and INCLUDE - unset lib - unset Lib - LIB="${lib4sdk}" - export LIB - unset include - unset Include - INCLUDE="${include4sdk}" - export INCLUDE - # Set the ALT variable - ALT_COMPILER_PATH=`${dosname} "${compiler_path}"` - export ALT_COMPILER_PATH - dirMustExist "${compiler_path}" ALT_COMPILER_PATH - ALT_MSDEVTOOLS_PATH=`${dosname} "${msdevtools_path}"` - export ALT_MSDEVTOOLS_PATH - dirMustExist "${msdevtools_path}" ALT_MSDEVTOOLS_PATH - - # WINDOWS: Get the previous JDK to be used to bootstrap the build - path4sdk="${bootdir}/bin;${path4sdk}" - - # Turn all \\ into /, remove duplicates and trailing / - slash_path="`echo ${path4sdk} | sed -e 's@\\\\@/@g' -e 's@//@/@g' -e 's@/$@@' -e 's@/;@;@g'`" - - # For windows, it's hard to know where the system is, so we just add this - # to PATH. - path4sdk="${slash_path};${PATH}" - - # Convert path4sdk to cygwin style - if [ "${unix_toolset}" = CYGWIN ] ; then - path4sdk="`/usr/bin/cygpath -p ${path4sdk}`" - fi - - # Set special windows ALT variables - ALT_ISHIELDDIR="C:/ishield802" - export ALT_ISHIELDDIR - - # Sponsors binaries - ALT_SPONSOR1DIR=C:/sponsor_binaries - export ALT_SPONSOR1DIR - ALT_SPONSOR2DIR=C:/sponsor_binaries - export ALT_SPONSOR2DIR - -fi - -# Export PATH setting -PATH="${path4sdk}" -export PATH - -# Things we need to unset -unset LD_LIBRARY_PATH -unset LD_LIBRARY_PATH_32 -unset LD_LIBRARY_PATH_64 -unset JAVA_HOME - From 595ff704c093ef83f81b8fef7653a2affa6a8291 Mon Sep 17 00:00:00 2001 From: Ivan P Krylov Date: Fri, 27 Mar 2009 01:35:39 -0500 Subject: [PATCH 28/43] 6812297: update project creation for Visual Studio 2005-2008 Add 2 news classes to create VC8 and VC9 projects Reviewed-by: apetrusenko, xlu --- hotspot/make/windows/build_vm_def.sh | 13 ++++ hotspot/make/windows/create.bat | 12 ++- hotspot/make/windows/makefiles/adlc.make | 1 + hotspot/make/windows/makefiles/compile.make | 4 - hotspot/make/windows/makefiles/makedeps.make | 4 +- hotspot/make/windows/makefiles/rules.make | 15 +++- .../tools/MakeDeps/WinGammaPlatformVC7.java | 75 +++++++++++++++---- .../tools/MakeDeps/WinGammaPlatformVC8.java | 66 ++++++++++++++++ .../tools/MakeDeps/WinGammaPlatformVC9.java | 35 +++++++++ .../vm/utilities/globalDefinitions_visCPP.hpp | 19 +++-- 10 files changed, 213 insertions(+), 31 deletions(-) create mode 100644 hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java create mode 100644 hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java diff --git a/hotspot/make/windows/build_vm_def.sh b/hotspot/make/windows/build_vm_def.sh index 6cc931963b2..99e30bb1b9e 100644 --- a/hotspot/make/windows/build_vm_def.sh +++ b/hotspot/make/windows/build_vm_def.sh @@ -52,6 +52,19 @@ CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +# When called from IDE the first param should contain the link version, otherwise may be nill +if [ "x$1" != "x" ]; then +LINK_VER="$1" +fi + +if [ "x$LINK_VER" != "x800" -a "x$LINK_VER" != "x900" ]; then $DUMPBIN /symbols *.obj | "$GREP" "??_7.*@@6B@" | "$AWK" '{print $7}' | "$SORT" | "$UNIQ" > vm2.def +else +# Can't use pipes when calling cl.exe or link.exe from IDE. Using transit file vm3.def +$DUMPBIN /OUT:vm3.def /symbols *.obj +"$CAT" vm3.def | "$GREP" "??_7.*@@6B@" | "$AWK" '{print $7}' | "$SORT" | "$UNIQ" > vm2.def +"$RM" -f vm3.def +fi + "$CAT" vm1.def vm2.def > vm.def "$RM" -f vm1.def vm2.def diff --git a/hotspot/make/windows/create.bat b/hotspot/make/windows/create.bat index 21f97033669..bdb1916107d 100644 --- a/hotspot/make/windows/create.bat +++ b/hotspot/make/windows/create.bat @@ -72,12 +72,20 @@ REM figure out MSC version for /F %%i in ('sh %HotSpotWorkSpace%/make/windows/get_msc_ver.sh') do set %%i echo ************************************************************** +set ProjectFile=vm.vcproj if "%MSC_VER%" == "1200" ( set ProjectFile=vm.dsp echo Will generate VC6 project {unsupported} ) else ( -set ProjectFile=vm.vcproj -echo Will generate VC7 project +if "%MSC_VER%" == "1400" ( +echo Will generate VC8 {Visual Studio 2005} +) else ( +if "%MSC_VER%" == "1500" ( +echo Will generate VC9 {Visual Studio 2008} +) else ( +echo Will generate VC7 project {Visual Studio 2003 .NET} +) +) ) echo %ProjectFile% echo ************************************************************** diff --git a/hotspot/make/windows/makefiles/adlc.make b/hotspot/make/windows/makefiles/adlc.make index b6feb0e78b9..e9af2f964bb 100644 --- a/hotspot/make/windows/makefiles/adlc.make +++ b/hotspot/make/windows/makefiles/adlc.make @@ -46,6 +46,7 @@ ADLCFLAGS=-q -T -D_LP64 ADLCFLAGS=-q -T -U_LP64 !endif +CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE CPP_INCLUDE_DIRS=\ /I "..\generated" \ diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make index 5869d7cb800..4906ab5a989 100644 --- a/hotspot/make/windows/makefiles/compile.make +++ b/hotspot/make/windows/makefiles/compile.make @@ -170,8 +170,6 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) $(BUFFEROVERFLOWLIB) # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. MT=mt.exe -# VS2005 and later restricts the use of certain libc functions without this -CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE !endif !if "$(COMPILER_NAME)" == "VS2008" @@ -183,8 +181,6 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) # Manifest Tool - used in VS2005 and later to adjust manifests stored # as resources inside build artifacts. MT=mt.exe -# VS2005 and later restricts the use of certain libc functions without this -CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE !endif # Compile for space above time. diff --git a/hotspot/make/windows/makefiles/makedeps.make b/hotspot/make/windows/makefiles/makedeps.make index 8bfe00737ab..43f25a4666d 100644 --- a/hotspot/make/windows/makefiles/makedeps.make +++ b/hotspot/make/windows/makefiles/makedeps.make @@ -48,6 +48,8 @@ MakeDepsSources=\ $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatform.java \ $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC6.java \ $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC7.java \ + $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC8.java \ + $(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC9.java \ $(WorkSpace)\src\share\tools\MakeDeps\Util.java \ $(WorkSpace)\src\share\tools\MakeDeps\BuildConfig.java \ $(WorkSpace)\src\share\tools\MakeDeps\ArgsParser.java @@ -121,7 +123,7 @@ MakeDepsIDEOptions=\ -additionalFile includeDB_gc_shared \ -additionalFile includeDB_gc_serial \ -additionalGeneratedFile $(HOTSPOTBUILDSPACE)\%f\%b vm.def \ - -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh" \ + -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \ $(MakeDepsIncludesPRIVATE) # Add in build-specific options diff --git a/hotspot/make/windows/makefiles/rules.make b/hotspot/make/windows/makefiles/rules.make index f07f84aee1d..064fb3f231d 100644 --- a/hotspot/make/windows/makefiles/rules.make +++ b/hotspot/make/windows/makefiles/rules.make @@ -42,10 +42,23 @@ COMPILE_RMIC=rmic BOOT_JAVA_HOME= !endif +ProjectFile=vm.vcproj + !if "$(MSC_VER)" == "1200" + VcVersion=VC6 ProjectFile=vm.dsp + +!elseif "$(MSC_VER)" == "1400" + +VcVersion=VC8 + +!elseif "$(MSC_VER)" == "1500" + +VcVersion=VC9 + !else + VcVersion=VC7 -ProjectFile=vm.vcproj + !endif diff --git a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java index 82159a41835..109613b45d7 100644 --- a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java +++ b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC7.java @@ -27,6 +27,8 @@ import java.util.*; public class WinGammaPlatformVC7 extends WinGammaPlatform { + String projectVersion() {return "7.10";}; + public void writeProjectFile(String projectFileName, String projectName, Vector allConfigs) throws IOException { System.out.println(); @@ -40,7 +42,7 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform { "VisualStudioProject", new String[] { "ProjectType", "Visual C++", - "Version", "7.10", + "Version", projectVersion(), "Name", projectName, "ProjectGUID", "{8822CB5C-1C41-41C2-8493-9F6E1994338B}", "SccProjectName", "", @@ -417,7 +419,9 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform { new String[] { "Name", "VCPreLinkEventTool", "Description", BuildConfig.getFieldString(null, "PrelinkDescription"), - "CommandLine", cfg.expandFormat(BuildConfig.getFieldString(null, "PrelinkCommand").replace('\t', '\n')) + //Caution: String.replace(String,String) is available from JDK5 onwards only + "CommandLine", cfg.expandFormat(BuildConfig.getFieldString(null, "PrelinkCommand").replace + ("\t", " ")) } ); @@ -542,25 +546,41 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform { } class CompilerInterfaceVC7 extends CompilerInterface { - Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { - Vector rv = new Vector(); + void getBaseCompilerFlags_common(Vector defines, Vector includes, String outDir,Vector rv) { // advanced M$ IDE (2003) can only recognize name if it's first or // second attribute in the tag - go guess addAttr(rv, "Name", "VCCLCompilerTool"); addAttr(rv, "AdditionalIncludeDirectories", Util.join(",", includes)); - addAttr(rv, "PreprocessorDefinitions", Util.join(";", defines).replace("\"",""")); - addAttr(rv, "UsePrecompiledHeader", "3"); - addAttr(rv, "PrecompiledHeaderThrough", "incls"+Util.sep+"_precompiled.incl"); + addAttr(rv, "PreprocessorDefinitions", + Util.join(";", defines).replace("\"",""")); + addAttr(rv, "PrecompiledHeaderThrough", + "incls"+Util.sep+"_precompiled.incl"); addAttr(rv, "PrecompiledHeaderFile", outDir+Util.sep+"vm.pch"); addAttr(rv, "AssemblerListingLocation", outDir); addAttr(rv, "ObjectFile", outDir+Util.sep); addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"vm.pdb"); + // Set /nologo optin addAttr(rv, "SuppressStartupBanner", "TRUE"); + // Surpass the default /Tc or /Tp. 0 is compileAsDefault addAttr(rv, "CompileAs", "0"); + // Set /W3 option. 3 is warningLevel_3 addAttr(rv, "WarningLevel", "3"); + // Set /WX option, addAttr(rv, "WarnAsError", "TRUE"); + // Set /GS option addAttr(rv, "BufferSecurityCheck", "FALSE"); + // Set /Zi option. 3 is debugEnabled + addAttr(rv, "DebugInformationFormat", "3"); + } + Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { + Vector rv = new Vector(); + + getBaseCompilerFlags_common(defines,includes, outDir, rv); + // Set /Yu option. 3 is pchUseUsingSpecific + // Note: Starting VC8 pchUseUsingSpecific is 2 !!! + addAttr(rv, "UsePrecompiledHeader", "3"); + // Set /EHsc- option addAttr(rv, "ExceptionHandling", "FALSE"); return rv; @@ -579,27 +599,39 @@ class CompilerInterfaceVC7 extends CompilerInterface { "/export:jio_vsnprintf "); addAttr(rv, "AdditionalDependencies", "Wsock32.lib winmm.lib"); addAttr(rv, "OutputFile", outDll); + // Set /INCREMENTAL option. 1 is linkIncrementalNo addAttr(rv, "LinkIncremental", "1"); addAttr(rv, "SuppressStartupBanner", "TRUE"); addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def"); addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"vm.pdb"); + // Set /SUBSYSTEM option. 2 is subSystemWindows addAttr(rv, "SubSystem", "2"); addAttr(rv, "BaseAddress", "0x8000000"); addAttr(rv, "ImportLibrary", outDir+Util.sep+"jvm.lib"); + // Set /MACHINE option. 1 is machineX86 addAttr(rv, "TargetMachine", "1"); return rv; } + void getDebugCompilerFlags_common(String opt,Vector rv) { + + // Set /On option + addAttr(rv, "Optimization", opt); + // Set /FR option. 1 is brAllInfo + addAttr(rv, "BrowseInformation", "1"); + addAttr(rv, "BrowseInformationFile", "$(IntDir)" + Util.sep); + // Set /MD option. 2 is rtMultiThreadedDLL + addAttr(rv, "RuntimeLibrary", "2"); + // Set /Oy- option + addAttr(rv, "OmitFramePointers", "FALSE"); + + } + Vector getDebugCompilerFlags(String opt) { Vector rv = new Vector(); - addAttr(rv, "Optimization", opt); - addAttr(rv, "OptimizeForProcessor", "1"); - addAttr(rv, "DebugInformationFormat", "3"); - addAttr(rv, "RuntimeLibrary", "2"); - addAttr(rv, "BrowseInformation", "1"); - addAttr(rv, "BrowseInformationFile", "$(IntDir)" + Util.sep); + getDebugCompilerFlags_common(opt,rv); return rv; } @@ -607,18 +639,29 @@ class CompilerInterfaceVC7 extends CompilerInterface { Vector getDebugLinkerFlags() { Vector rv = new Vector(); - addAttr(rv, "GenerateDebugInformation", "TRUE"); + addAttr(rv, "GenerateDebugInformation", "TRUE"); // == /DEBUG option return rv; } + void getProductCompilerFlags_common(Vector rv) { + // Set /O2 option. 2 is optimizeMaxSpeed + addAttr(rv, "Optimization", "2"); + // Set /Oy- option + addAttr(rv, "OmitFramePointers", "FALSE"); + } + Vector getProductCompilerFlags() { Vector rv = new Vector(); - addAttr(rv, "Optimization", "2"); + getProductCompilerFlags_common(rv); + // Set /Ob option. 1 is expandOnlyInline addAttr(rv, "InlineFunctionExpansion", "1"); + // Set /GF option. addAttr(rv, "StringPooling", "TRUE"); + // Set /MD option. 2 is rtMultiThreadedDLL addAttr(rv, "RuntimeLibrary", "2"); + // Set /Gy option addAttr(rv, "EnableFunctionLevelLinking", "TRUE"); return rv; @@ -627,7 +670,9 @@ class CompilerInterfaceVC7 extends CompilerInterface { Vector getProductLinkerFlags() { Vector rv = new Vector(); + // Set /OPT:REF option. 2 is optReferences addAttr(rv, "OptimizeReferences", "2"); + // Set /OPT:optFolding option. 2 is optFolding addAttr(rv, "EnableCOMDATFolding", "2"); return rv; diff --git a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java new file mode 100644 index 00000000000..a346b611560 --- /dev/null +++ b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +import java.io.*; +import java.util.*; + +public class WinGammaPlatformVC8 extends WinGammaPlatformVC7 { + + String projectVersion() {return "8.00";}; + +} + +class CompilerInterfaceVC8 extends CompilerInterfaceVC7 { + + Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { + Vector rv = new Vector(); + + getBaseCompilerFlags_common(defines,includes, outDir, rv); + // Set /Yu option. 2 is pchUseUsingSpecific + addAttr(rv, "UsePrecompiledHeader", "2"); + // Set /EHsc- option. 0 is cppExceptionHandlingNo + addAttr(rv, "ExceptionHandling", "0"); + + return rv; + } + + + Vector getDebugCompilerFlags(String opt) { + Vector rv = new Vector(); + + getDebugCompilerFlags_common(opt,rv); + + return rv; + } + + Vector getProductCompilerFlags() { + Vector rv = new Vector(); + + getProductCompilerFlags_common(rv); + + return rv; + } + + +} diff --git a/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java new file mode 100644 index 00000000000..4b64a555833 --- /dev/null +++ b/hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +import java.io.*; +import java.util.*; + +public class WinGammaPlatformVC9 extends WinGammaPlatformVC8 { + + String projectVersion() {return "9.00";}; + +} + +class CompilerInterfaceVC9 extends CompilerInterfaceVC8 { +} diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp index 3e3c861df8e..2b64dfc4662 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp @@ -153,14 +153,6 @@ const jlong max_jlong = CONST64(0x7fffffffffffffff); //---------------------------------------------------------------------------------------------------- // Miscellaneous -inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { - // If number of characters written == count, Windows doesn't write a - // terminating NULL, so we do it ourselves. - int ret = _vsnprintf(buf, count, fmt, argptr); - if (count > 0) buf[count-1] = '\0'; - return ret; -} - // Visual Studio 2005 deprecates POSIX names - use ISO C++ names instead #if _MSC_VER >= 1400 #define open _open @@ -180,6 +172,17 @@ inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union (needed in windows.h) #pragma warning( disable : 4511 ) // copy constructor could not be generated #pragma warning( disable : 4291 ) // no matching operator delete found; memory will not be freed if initialization thows an exception +#if _MSC_VER >= 1400 +#pragma warning( disable : 4996 ) // unsafe string functions. Same as define _CRT_SECURE_NO_WARNINGS/_CRT_SECURE_NO_DEPRICATE +#endif + +inline int vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { + // If number of characters written == count, Windows doesn't write a + // terminating NULL, so we do it ourselves. + int ret = _vsnprintf(buf, count, fmt, argptr); + if (count > 0) buf[count-1] = '\0'; + return ret; +} // Portability macros #define PRAGMA_INTERFACE From 9bac626c1a054c6921093bd2b275a6f6b8d2b3a0 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:31 -0700 Subject: [PATCH 29/43] Added tag jdk7-b52 for changeset 90eb5f83241a --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 52f1f706812..5ac8ad95712 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -26,3 +26,4 @@ d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47 aee93a8992d2389121eb610c00a86196f3e2b9b0 jdk7-b49 5111e13e44e542fe945b47ab154546daec36737d jdk7-b50 0f0189d55ce4a1f7840da7582ac7d970b3b7ab15 jdk7-b51 +4264c2fe66493e57c411045a1b61377796641e45 jdk7-b52 From a83e0c09252de5635a1a60eea3e44414758597c8 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:32 -0700 Subject: [PATCH 30/43] Added tag jdk7-b52 for changeset 8608524e334e --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 28a93dc8343..91ac5a1ccae 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -26,3 +26,4 @@ ccd6a16502e0650d91d85c4b86be05cbcd461a87 jdk7-b42 d70978bc64bc7a04be7797ab0dcd9b7b1b3a6bff jdk7-b49 0edbd0074b02b42b2b83cc47cb391d4869b7a8ec jdk7-b50 3eb8f1047a7402a9a79937d1c39560e931e91da2 jdk7-b51 +bec82237d694f9802b820fa11bbb4f7fa9bf8e77 jdk7-b52 From 422ea850e0a4475c8fdf86a44a125e7ade494527 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:35 -0700 Subject: [PATCH 31/43] Added tag jdk7-b52 for changeset 0d989c04422c --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 21dac82c44e..475bfa37988 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -26,3 +26,4 @@ bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48 8b22ccb5aba2c6c11bddf6488a7bb7ef5b4bf2be jdk7-b49 dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50 2581d90c6c9b2012da930eb4742add94a03069a0 jdk7-b51 +1b1e8f1a4fe8cebc01c022484f78148e17b62a0d jdk7-b52 From 93a90129b2ad174a8d6adb641eb786fc98814c8f Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:39 -0700 Subject: [PATCH 32/43] Added tag jdk7-b52 for changeset 37c56ec4ec7d --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index b479a50ab7b..8951b3d1ac5 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -26,3 +26,4 @@ d711ad1954b294957737ea386cfd4d3c05028a36 jdk7-b47 5c1f24531903573c1830775432276da567243f9c jdk7-b49 e8514e2be76d90889ebdb90d627aca2db5c150c6 jdk7-b50 ae890d80d5dffcd4dc77a1f17d768e192d1852c7 jdk7-b51 +69ad87dc25cbcaaaded4727199395ad0c78bc427 jdk7-b52 From d8cd1fc4329a3561f63b4b971e649b769111d6d5 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:40 -0700 Subject: [PATCH 33/43] Added tag jdk7-b52 for changeset 56b454d324bb --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 2869a6be543..62bf7fdbd4d 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -26,3 +26,4 @@ af4a3eeb7812a5d09a241c50b51b3c648a9d45c1 jdk7-b46 18ca864890f3d4ed942ecbffb78c936a57759921 jdk7-b49 5be52db581f1ea91ab6e0eb34ba7f439125bfb16 jdk7-b50 41a66a42791ba90bff489af72cbfea71be9b40a5 jdk7-b51 +e646890d18b770f625f14ed4ad5c50554d8d3d8b jdk7-b52 From ace77b0dc3f00908ba37a8bd89c43d1f28f42ec1 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:45 -0700 Subject: [PATCH 34/43] Added tag jdk7-b52 for changeset ea5331b4a192 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 4790ae52876..39ec72bb7a9 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -26,3 +26,4 @@ b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47 8311105ea7a3db7bcbcb2b696459127c7f2297a4 jdk7-b49 58ba2cd5a25053684ec53205d95edeeaa0006f13 jdk7-b50 fea0898259ae41c73620b1815aa48f036216155c jdk7-b51 +bcbeadb4a5d759b29e876ee2c83401e91ff22f60 jdk7-b52 From 0f23916d8bb90249cf5e7313abb731e47c67b2b6 Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Fri, 27 Mar 2009 14:11:53 -0700 Subject: [PATCH 35/43] Added tag jdk7-b52 for changeset a9071341dbea --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index a260d94e956..0ea2c411d86 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -26,3 +26,4 @@ c53007f34195f69223bdd4125ec6c0740f7d6736 jdk7-b48 d17d927ad9bdfafae32451645d182acb7bed7be6 jdk7-b49 46f2f6ed96f13fc49fec3d1b6aa616686128cb57 jdk7-b50 8c55d5b0ed71ed3a749eb97e4eab79b4831649b8 jdk7-b51 +29329051d483d39f66073752ba4afbf29d893cfe jdk7-b52 From 350ce4d28bee19bb97b883cca4b96575a4f8324b Mon Sep 17 00:00:00 2001 From: Erik Trimble Date: Fri, 27 Mar 2009 16:58:30 -0700 Subject: [PATCH 36/43] 6823377: Bump HS15 build number to 04 Update the HS15 Build number to 04 Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index d0da3b6ce8d..f3f6bc5d15b 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2008 HS_MAJOR_VER=15 HS_MINOR_VER=0 -HS_BUILD_NUMBER=03 +HS_BUILD_NUMBER=04 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 From 0a7ba6e27e3fd51a1a63c8a6692cedd03dda45f0 Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Tue, 31 Mar 2009 15:27:40 -0700 Subject: [PATCH 37/43] 6819847: build is broken for OpenJDK with plugs Reviewed-by: jjg, robilad, ohair --- jdk/make/Makefile | 5 ----- jdk/make/common/Defs.gmk | 9 +++++++++ jdk/make/common/shared/Sanity-Settings.gmk | 1 + jdk/make/java/redist/Makefile | 6 ++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/jdk/make/Makefile b/jdk/make/Makefile index c78e4c27e01..27781781f62 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -328,11 +328,6 @@ else $(ECHO) "Rule $@ does not apply on $(PLATFORM)-$(ARCH)" endif -# -# Binary Plug rules and macros -# -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk - # # Get top level sccs_get rule # diff --git a/jdk/make/common/Defs.gmk b/jdk/make/common/Defs.gmk index 33eedad16a4..d959123fdae 100644 --- a/jdk/make/common/Defs.gmk +++ b/jdk/make/common/Defs.gmk @@ -145,6 +145,11 @@ endif # 2. ALT_BINARY_PLUGS_PATH overrides all locations of classes and libraries # 3. ALT_BUILD_BINARY_PLUGS_PATH is used to find a ALT_BINARY_PLUGS_PATH # 4. ALT_CLOSED_JDK_IMPORT_PATH is used to locate classes and libraries +# Note: If any of the ALT_ variables are modified here, it is assumed +# that the build should be done with IMPORT_BINARY_PLUGS=true as +# well. Otherwise the default will be IMPORT_BINARY_PLUGS=false. +# Lastly, setting IMPORT_BINARY_PLUGS=false on the command line +# will override this logic, and plugs will not be imported. # # Always needed, defines the name of the imported/exported jarfile @@ -155,9 +160,11 @@ ifdef OPENJDK CLOSED_JDK_IMPORT_PATH = $(ALT_CLOSED_JDK_IMPORT_PATH) BINARY_PLUGS_PATH = $(CLOSED_JDK_IMPORT_PATH) BINARY_PLUGS_JARFILE = $(CLOSED_JDK_IMPORT_PATH)/jre/lib/rt.jar + IMPORT_BINARY_PLUGS=true endif ifdef ALT_BUILD_BINARY_PLUGS_PATH BUILD_BINARY_PLUGS_PATH = $(ALT_BUILD_BINARY_PLUGS_PATH) + IMPORT_BINARY_PLUGS=true else BUILD_BINARY_PLUGS_PATH = $(SLASH_JAVA)/re/jdk/$(JDK_VERSION)/promoted/latest/openjdk/binaryplugs endif @@ -166,9 +173,11 @@ ifdef OPENJDK ifdef ALT_BINARY_PLUGS_PATH BINARY_PLUGS_PATH = $(ALT_BINARY_PLUGS_PATH) BINARY_PLUGS_JARFILE = $(BINARY_PLUGS_PATH)/jre/lib/$(BINARY_PLUGS_JARNAME) + IMPORT_BINARY_PLUGS=true endif ifdef ALT_BINARY_PLUGS_JARFILE BINARY_PLUGS_JARFILE = $(ALT_BINARY_PLUGS_JARFILE) + IMPORT_BINARY_PLUGS=true endif endif # OPENJDK diff --git a/jdk/make/common/shared/Sanity-Settings.gmk b/jdk/make/common/shared/Sanity-Settings.gmk index 987ba93489a..b64e3b52a13 100644 --- a/jdk/make/common/shared/Sanity-Settings.gmk +++ b/jdk/make/common/shared/Sanity-Settings.gmk @@ -245,6 +245,7 @@ ifdef OPENJDK ALL_SETTINGS+=$(call addAltSetting,FREETYPE_HEADERS_PATH) ALL_SETTINGS+=$(call addAltSetting,FREETYPE_LIB_PATH) ALL_SETTINGS+=$(call addHeading,OPENJDK Import Binary Plug Settings) + ALL_SETTINGS+=$(call addOptionalSetting,IMPORT_BINARY_PLUGS) ALL_SETTINGS+=$(call addAltSetting,BINARY_PLUGS_JARFILE) ALL_SETTINGS+=$(call addAltSetting,BINARY_PLUGS_PATH) ALL_SETTINGS+=$(call addAltSetting,BUILD_BINARY_PLUGS_PATH) diff --git a/jdk/make/java/redist/Makefile b/jdk/make/java/redist/Makefile index 159c247b3f3..9ab884dd247 100644 --- a/jdk/make/java/redist/Makefile +++ b/jdk/make/java/redist/Makefile @@ -251,9 +251,11 @@ endif # INCLUDE_SA # ifdef OPENJDK -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk + ifeq ($(IMPORT_BINARY_PLUGS),true) + include $(BUILDDIR)/common/internal/BinaryPlugs.gmk -build: import-binary-plugs + build: import-binary-plugs + endif else # !OPENJDK From c81e6c29c17c27ad6c0a4e857582ba2f937a7aba Mon Sep 17 00:00:00 2001 From: Tim Bell Date: Wed, 1 Apr 2009 04:44:30 -0700 Subject: [PATCH 38/43] 6824595: OpenJDK fix breaks product build for jdk7 Reviewed-by: xdono, ohair --- jdk/make/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jdk/make/Makefile b/jdk/make/Makefile index 27781781f62..c78e4c27e01 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -328,6 +328,11 @@ else $(ECHO) "Rule $@ does not apply on $(PLATFORM)-$(ARCH)" endif +# +# Binary Plug rules and macros +# +include $(BUILDDIR)/common/internal/BinaryPlugs.gmk + # # Get top level sccs_get rule # From 8ed0a99cb648cf35658e32449104ae86cdcb8c7b Mon Sep 17 00:00:00 2001 From: Kelly O'Hair Date: Wed, 1 Apr 2009 16:49:43 -0700 Subject: [PATCH 39/43] 6825175: Remove or disable sanity check on binary plugs Reviewed-by: xdono --- jdk/make/common/shared/Sanity.gmk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index 23e3818353b..180e52196a9 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -502,13 +502,15 @@ endif ###################################################### ifdef OPENJDK sane-binary-plugs: + ifeq ($(IMPORT_BINARY_PLUGS),true) @if [ ! -d "$(BINARY_PLUGS_PATH)" ]; then \ - $(ECHO) "ERROR: Can't locate pre-built libraries. \n" \ + $(ECHO) "WARNING: Can't locate pre-built libraries. \n" \ " Please check your access to \n" \ " $(BINARY_PLUGS_PATH) \n" \ " and/or check your value of ALT_BINARY_PLUGS_PATH. \n" \ - "" >> $(ERROR_FILE); \ + "" >> $(WARNING_FILE); \ fi + endif endif ###################################################### From 21aa30606a26191e0418ab9fdfd04d9ecfe155a0 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Thu, 2 Apr 2009 15:35:46 -0700 Subject: [PATCH 40/43] 4681995: Add support for large (> 4GB) zip/jar files The ZIP64 format support is added for > 4GB jar/zip files Reviewed-by: alanb, martin --- .../classes/java/util/zip/ZipConstants64.java | 77 +++++++ .../share/classes/java/util/zip/ZipEntry.java | 8 +- .../classes/java/util/zip/ZipInputStream.java | 76 +++++-- .../java/util/zip/ZipOutputStream.java | 174 +++++++++++++--- .../share/classes/java/util/zip/package.html | 8 +- jdk/src/share/native/java/util/zip/zip_util.c | 104 +++++++++- jdk/src/share/native/java/util/zip/zip_util.h | 38 +++- .../native/java/util/zip/zlib-1.1.3/zlib.h | 4 +- jdk/test/java/util/zip/LargeZip.java | 193 ++++++++++++++++++ .../java/util/zip/ZipFile/LargeZipFile.java | 1 - 10 files changed, 629 insertions(+), 54 deletions(-) create mode 100644 jdk/src/share/classes/java/util/zip/ZipConstants64.java create mode 100644 jdk/test/java/util/zip/LargeZip.java diff --git a/jdk/src/share/classes/java/util/zip/ZipConstants64.java b/jdk/src/share/classes/java/util/zip/ZipConstants64.java new file mode 100644 index 00000000000..1bf3b1841b4 --- /dev/null +++ b/jdk/src/share/classes/java/util/zip/ZipConstants64.java @@ -0,0 +1,77 @@ +/* + * Copyright 1995-1996 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.util.zip; + +/* + * This class defines the constants that are used by the classes + * which manipulate Zip64 files. + */ + +class ZipConstants64 { + + /* + * ZIP64 constants + */ + static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" + static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" + static final int ZIP64_ENDHDR = 56; // ZIP64 end header size + static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size + static final int ZIP64_EXTHDR = 24; // EXT header size + static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID + + static final int ZIP64_MAGICCOUNT = 0xFFFF; + static final long ZIP64_MAGICVAL = 0xFFFFFFFFL; + + /* + * Zip64 End of central directory (END) header field offsets + */ + static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir + static final int ZIP64_ENDVEM = 12; // version made by + static final int ZIP64_ENDVER = 14; // version needed to extract + static final int ZIP64_ENDNMD = 16; // number of this disk + static final int ZIP64_ENDDSK = 20; // disk number of start + static final int ZIP64_ENDTOD = 24; // total number of entries on this disk + static final int ZIP64_ENDTOT = 32; // total number of entries + static final int ZIP64_ENDSIZ = 40; // central directory size in bytes + static final int ZIP64_ENDOFF = 48; // offset of first CEN header + static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector + + /* + * Zip64 End of central directory locator field offsets + */ + static final int ZIP64_LOCDSK = 4; // disk number start + static final int ZIP64_LOCOFF = 8; // offset of zip64 end + static final int ZIP64_LOCTOT = 16; // total number of disks + + /* + * Zip64 Extra local (EXT) header field offsets + */ + static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value + static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte + static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte + + private ZipConstants64() {} +} diff --git a/jdk/src/share/classes/java/util/zip/ZipEntry.java b/jdk/src/share/classes/java/util/zip/ZipEntry.java index bcc27e63a0f..6c16a9adb15 100644 --- a/jdk/src/share/classes/java/util/zip/ZipEntry.java +++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2009 Sun Microsystems, Inc. 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 @@ -144,11 +144,13 @@ class ZipEntry implements ZipConstants, Cloneable { * Sets the uncompressed size of the entry data. * @param size the uncompressed size in bytes * @exception IllegalArgumentException if the specified size is less - * than 0 or greater than 0xFFFFFFFF bytes + * than 0, is greater than 0xFFFFFFFF when + * ZIP64 format is not supported, + * or is less than 0 when ZIP64 is supported * @see #getSize() */ public void setSize(long size) { - if (size < 0 || size > 0xFFFFFFFFL) { + if (size < 0) { throw new IllegalArgumentException("invalid entry size"); } this.size = size; diff --git a/jdk/src/share/classes/java/util/zip/ZipInputStream.java b/jdk/src/share/classes/java/util/zip/ZipInputStream.java index e8f0ebdc5d9..1b9b93415cb 100644 --- a/jdk/src/share/classes/java/util/zip/ZipInputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. 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,6 +29,7 @@ import java.io.InputStream; import java.io.IOException; import java.io.EOFException; import java.io.PushbackInputStream; +import static java.util.zip.ZipConstants64.*; /** * This class implements an input stream filter for reading files in the @@ -285,6 +286,29 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { byte[] bb = new byte[len]; readFully(bb, 0, len); e.setExtra(bb); + // extra fields are in "HeaderID(2)DataSize(2)Data... format + if (e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL) { + int off = 0; + while (off + 4 < len) { + int sz = get16(bb, off + 2); + if (get16(bb, off) == ZIP64_EXTID) { + off += 4; + // LOC extra zip64 entry MUST include BOTH original and + // compressed file size fields + if (sz < 16 || (off + sz) > len ) { + // Invalid zip64 extra fields, simply skip. Even it's + // rare, it's possible the entry size happens to be + // the magic value and it "accidnetly" has some bytes + // in extra match the id. + return e; + } + e.size = get64(bb, off); + e.csize = get64(bb, off + 8); + break; + } + off += (sz + 4); + } + } } return e; } @@ -375,18 +399,36 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { } if ((flag & 8) == 8) { /* "Data Descriptor" present */ - readFully(tmpbuf, 0, EXTHDR); - long sig = get32(tmpbuf, 0); - if (sig != EXTSIG) { // no EXTSIG present - e.crc = sig; - e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); - e.size = get32(tmpbuf, EXTLEN - EXTCRC); - ((PushbackInputStream)in).unread( - tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); + if (inf.getBytesWritten() > ZIP64_MAGICVAL || + inf.getBytesRead() > ZIP64_MAGICVAL) { + // ZIP64 format + readFully(tmpbuf, 0, ZIP64_EXTHDR); + long sig = get32(tmpbuf, 0); + if (sig != EXTSIG) { // no EXTSIG present + e.crc = sig; + e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC); + e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC); + ((PushbackInputStream)in).unread( + tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC); + } else { + e.crc = get32(tmpbuf, ZIP64_EXTCRC); + e.csize = get64(tmpbuf, ZIP64_EXTSIZ); + e.size = get64(tmpbuf, ZIP64_EXTLEN); + } } else { - e.crc = get32(tmpbuf, EXTCRC); - e.csize = get32(tmpbuf, EXTSIZ); - e.size = get32(tmpbuf, EXTLEN); + readFully(tmpbuf, 0, EXTHDR); + long sig = get32(tmpbuf, 0); + if (sig != EXTSIG) { // no EXTSIG present + e.crc = sig; + e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); + e.size = get32(tmpbuf, EXTLEN - EXTCRC); + ((PushbackInputStream)in).unread( + tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); + } else { + e.crc = get32(tmpbuf, EXTCRC); + e.csize = get32(tmpbuf, EXTSIZ); + e.size = get32(tmpbuf, EXTLEN); + } } } if (e.size != inf.getBytesWritten()) { @@ -433,6 +475,14 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { * The bytes are assumed to be in Intel (little-endian) byte order. */ private static final long get32(byte b[], int off) { - return get16(b, off) | ((long)get16(b, off+2) << 16); + return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL; + } + + /* + * Fetches signed 64-bit value from byte array at specified offset. + * The bytes are assumed to be in Intel (little-endian) byte order. + */ + private static final long get64(byte b[], int off) { + return get32(b, off) | (get32(b, off+4) << 32); } } diff --git a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java index 797a37392fe..bd44d3213cf 100644 --- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. 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,6 +29,7 @@ import java.io.OutputStream; import java.io.IOException; import java.util.Vector; import java.util.HashSet; +import static java.util.zip.ZipConstants64.*; /** * This class implements an output stream filter for writing files in the @@ -343,26 +344,52 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { private void writeLOC(XEntry xentry) throws IOException { ZipEntry e = xentry.entry; int flag = xentry.flag; + int elen = (e.extra != null) ? e.extra.length : 0; + boolean hasZip64 = false; + writeInt(LOCSIG); // LOC header signature - writeShort(version(e)); // version needed to extract - writeShort(flag); // general purpose bit flag - writeShort(e.method); // compression method - writeInt(e.time); // last modification time + if ((flag & 8) == 8) { + writeShort(version(e)); // version needed to extract + writeShort(flag); // general purpose bit flag + writeShort(e.method); // compression method + writeInt(e.time); // last modification time + // store size, uncompressed size, and crc-32 in data descriptor // immediately following compressed entry data writeInt(0); writeInt(0); writeInt(0); } else { - writeInt(e.crc); // crc-32 - writeInt(e.csize); // compressed size - writeInt(e.size); // uncompressed size + if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) { + hasZip64 = true; + writeShort(45); // ver 4.5 for zip64 + } else { + writeShort(version(e)); // version needed to extract + } + writeShort(flag); // general purpose bit flag + writeShort(e.method); // compression method + writeInt(e.time); // last modification time + writeInt(e.crc); // crc-32 + if (hasZip64) { + writeInt(ZIP64_MAGICVAL); + writeInt(ZIP64_MAGICVAL); + elen += 20; //headid(2) + size(2) + size(8) + csize(8) + } else { + writeInt(e.csize); // compressed size + writeInt(e.size); // uncompressed size + } } byte[] nameBytes = getUTF8Bytes(e.name); writeShort(nameBytes.length); - writeShort(e.extra != null ? e.extra.length : 0); + writeShort(elen); writeBytes(nameBytes, 0, nameBytes.length); + if (hasZip64) { + writeShort(ZIP64_EXTID); + writeShort(16); + writeLong(e.size); + writeLong(e.csize); + } if (e.extra != null) { writeBytes(e.extra, 0, e.extra.length); } @@ -375,8 +402,13 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { private void writeEXT(ZipEntry e) throws IOException { writeInt(EXTSIG); // EXT header signature writeInt(e.crc); // crc-32 - writeInt(e.csize); // compressed size - writeInt(e.size); // uncompressed size + if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) { + writeLong(e.csize); + writeLong(e.size); + } else { + writeInt(e.csize); // compressed size + writeInt(e.size); // uncompressed size + } } /* @@ -387,18 +419,49 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ZipEntry e = xentry.entry; int flag = xentry.flag; int version = version(e); + + long csize = e.csize; + long size = e.size; + long offset = xentry.offset; + int e64len = 0; + boolean hasZip64 = false; + if (e.csize >= ZIP64_MAGICVAL) { + csize = ZIP64_MAGICVAL; + e64len += 8; // csize(8) + hasZip64 = true; + } + if (e.size >= ZIP64_MAGICVAL) { + size = ZIP64_MAGICVAL; // size(8) + e64len += 8; + hasZip64 = true; + } + if (xentry.offset >= ZIP64_MAGICVAL) { + offset = ZIP64_MAGICVAL; + e64len += 8; // offset(8) + hasZip64 = true; + } writeInt(CENSIG); // CEN header signature - writeShort(version); // version made by - writeShort(version); // version needed to extract + if (hasZip64) { + writeShort(45); // ver 4.5 for zip64 + writeShort(45); + } else { + writeShort(version); // version made by + writeShort(version); // version needed to extract + } writeShort(flag); // general purpose bit flag writeShort(e.method); // compression method writeInt(e.time); // last modification time writeInt(e.crc); // crc-32 - writeInt(e.csize); // compressed size - writeInt(e.size); // uncompressed size + writeInt(csize); // compressed size + writeInt(size); // uncompressed size byte[] nameBytes = getUTF8Bytes(e.name); writeShort(nameBytes.length); - writeShort(e.extra != null ? e.extra.length : 0); + if (hasZip64) { + // + headid(2) + datasize(2) + writeShort(e64len + 4 + (e.extra != null ? e.extra.length : 0)); + } else { + writeShort(e.extra != null ? e.extra.length : 0); + } byte[] commentBytes; if (e.comment != null) { commentBytes = getUTF8Bytes(e.comment); @@ -410,8 +473,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { writeShort(0); // starting disk number writeShort(0); // internal file attributes (unused) writeInt(0); // external file attributes (unused) - writeInt(xentry.offset); // relative offset of local header + writeInt(offset); // relative offset of local header writeBytes(nameBytes, 0, nameBytes.length); + if (hasZip64) { + writeShort(ZIP64_EXTID);// Zip64 extra + writeShort(e64len); + if (size == ZIP64_MAGICVAL) + writeLong(e.size); + if (csize == ZIP64_MAGICVAL) + writeLong(e.csize); + if (offset == ZIP64_MAGICVAL) + writeLong(xentry.offset); + } if (e.extra != null) { writeBytes(e.extra, 0, e.extra.length); } @@ -424,15 +497,50 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { * Writes end of central directory (END) header. */ private void writeEND(long off, long len) throws IOException { + boolean hasZip64 = false; + long xlen = len; + long xoff = off; + if (xlen >= ZIP64_MAGICVAL) { + xlen = ZIP64_MAGICVAL; + hasZip64 = true; + } + if (xoff >= ZIP64_MAGICVAL) { + xoff = ZIP64_MAGICVAL; + hasZip64 = true; + } int count = xentries.size(); - writeInt(ENDSIG); // END record signature - writeShort(0); // number of this disk - writeShort(0); // central directory start disk - writeShort(count); // number of directory entries on disk - writeShort(count); // total number of directory entries - writeInt(len); // length of central directory - writeInt(off); // offset of central directory - if (comment != null) { // zip file comment + if (count >= ZIP64_MAGICCOUNT) { + count = ZIP64_MAGICCOUNT; + hasZip64 = true; + } + if (hasZip64) { + long off64 = written; + //zip64 end of central directory record + writeInt(ZIP64_ENDSIG); // zip64 END record signature + writeLong(ZIP64_ENDHDR - 12); // size of zip64 end + writeShort(45); // version made by + writeShort(45); // version needed to extract + writeInt(0); // number of this disk + writeInt(0); // central directory start disk + writeLong(xentries.size()); // number of directory entires on disk + writeLong(xentries.size()); // number of directory entires + writeLong(len); // length of central directory + writeLong(off); // offset of central directory + + //zip64 end of central directory locator + writeInt(ZIP64_LOCSIG); // zip64 END locator signature + writeInt(0); // zip64 END start disk + writeLong(off64); // offset of zip64 END + writeInt(1); // total number of disks (?) + } + writeInt(ENDSIG); // END record signature + writeShort(0); // number of this disk + writeShort(0); // central directory start disk + writeShort(count); // number of directory entries on disk + writeShort(count); // total number of directory entries + writeInt(xlen); // length of central directory + writeInt(xoff); // offset of central directory + if (comment != null) { // zip file comment byte[] b = getUTF8Bytes(comment); writeShort(b.length); writeBytes(b, 0, b.length); @@ -463,6 +571,22 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { written += 4; } + /* + * Writes a 64-bit int to the output stream in little-endian byte order. + */ + private void writeLong(long v) throws IOException { + OutputStream out = this.out; + out.write((int)((v >>> 0) & 0xff)); + out.write((int)((v >>> 8) & 0xff)); + out.write((int)((v >>> 16) & 0xff)); + out.write((int)((v >>> 24) & 0xff)); + out.write((int)((v >>> 32) & 0xff)); + out.write((int)((v >>> 40) & 0xff)); + out.write((int)((v >>> 48) & 0xff)); + out.write((int)((v >>> 56) & 0xff)); + written += 8; + } + /* * Writes an array of bytes to the output stream. */ diff --git a/jdk/src/share/classes/java/util/zip/package.html b/jdk/src/share/classes/java/util/zip/package.html index d32e0fa0f4a..d4b59263678 100644 --- a/jdk/src/share/classes/java/util/zip/package.html +++ b/jdk/src/share/classes/java/util/zip/package.html @@ -45,6 +45,13 @@ input streams. Info-ZIP Application Note 970311 - a detailed description of the Info-ZIP format upon which the java.util.zip classes are based. +

+ +

  • An implementation may optionally support the ZIP64(tm) format extensions + defined by the + + PKWARE ZIP File Format Specification. The ZIP64(tm) format extensions + are used to overcome the size limitations of the original ZIP format.

  • ZLIB Compressed Data Format Specification version 3.3 @@ -70,7 +77,6 @@ input streams.
  • CRC-32 checksum is described in RFC 1952 (above)

  • Adler-32 checksum is described in RFC 1950 (above) - diff --git a/jdk/src/share/native/java/util/zip/zip_util.c b/jdk/src/share/native/java/util/zip/zip_util.c index f381629712c..89f52ae3bcc 100644 --- a/jdk/src/share/native/java/util/zip/zip_util.c +++ b/jdk/src/share/native/java/util/zip/zip_util.c @@ -312,6 +312,38 @@ findEND(jzfile *zip, void *endbuf) return -1; /* END header not found */ } +/* + * Searches for the ZIP64 end of central directory (END) header. The + * contents of the ZIP64 END header will be read and placed in end64buf. + * Returns the file position of the ZIP64 END header, otherwise returns + * -1 if the END header was not found or an error occurred. + * + * The ZIP format specifies the "position" of each related record as + * ... + * [central directory] + * [zip64 end of central directory record] + * [zip64 end of central directory locator] + * [end of central directory record] + * + * The offset of zip64 end locator can be calculated from endpos as + * "endpos - ZIP64_LOCHDR". + * The "offset" of zip64 end record is stored in zip64 end locator. + */ +static jlong +findEND64(jzfile *zip, void *end64buf, jlong endpos) +{ + char loc64[ZIP64_LOCHDR]; + jlong end64pos; + if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) { + return -1; // end64 locator not found + } + end64pos = ZIP64_LOCOFF(loc64); + if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) { + return -1; // end64 record not found + } + return end64pos; +} + /* * Returns a hash code value for a C-style NUL-terminated string. */ @@ -463,7 +495,7 @@ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ - jlong endpos, cenpos, cenlen; + jlong endpos, end64pos, cenpos, cenlen, cenoff; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; @@ -474,6 +506,7 @@ readCEN(jzfile *zip, jint knownTotal) jlong offset; #endif unsigned char endbuf[ENDHDR]; + jint endhdrlen = ENDHDR; jzcell *entries; jint *table; @@ -490,13 +523,27 @@ readCEN(jzfile *zip, jint knownTotal) /* Get position and length of central directory */ cenlen = ENDSIZ(endbuf); + cenoff = ENDOFF(endbuf); + total = ENDTOT(endbuf); + if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL || + total == ZIP64_MAGICCOUNT) { + unsigned char end64buf[ZIP64_ENDHDR]; + if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { + cenlen = ZIP64_ENDSIZ(end64buf); + cenoff = ZIP64_ENDOFF(end64buf); + total = (jint)ZIP64_ENDTOT(end64buf); + endpos = end64pos; + endhdrlen = ZIP64_ENDHDR; + } + } + if (cenlen > endpos) ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); cenpos = endpos - cenlen; /* Get position of first local file (LOC) header, taking into * account that there may be a stub prefixed to the zip file. */ - zip->locpos = cenpos - ENDOFF(endbuf); + zip->locpos = cenpos - cenoff; if (zip->locpos < 0) ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); @@ -527,7 +574,7 @@ readCEN(jzfile *zip, jint knownTotal) out the page size in order to make offset to be multiples of page size. */ - zip->mlen = cenpos - offset + cenlen + ENDHDR; + zip->mlen = cenpos - offset + cenlen + endhdrlen; zip->offset = offset; mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : @@ -551,8 +598,13 @@ readCEN(jzfile *zip, jint knownTotal) * is a 2-byte field, but we (and other zip implementations) * support approx. 2**31 entries, we do not trust ENDTOT, but * treat it only as a strong hint. When we call ourselves - * recursively, knownTotal will have the "true" value. */ - total = (knownTotal != -1) ? knownTotal : ENDTOT(endbuf); + * recursively, knownTotal will have the "true" value. + * + * Keep this path alive even with the Zip64 END support added, just + * for zip files that have more than 0xffff entries but don't have + * the Zip64 enabled. + */ + total = (knownTotal != -1) ? knownTotal : total; entries = zip->entries = calloc(total, sizeof(entries[0])); tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions table = zip->table = malloc(tablelen * sizeof(table[0])); @@ -854,6 +906,7 @@ typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; static jzentry * newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) { + jlong locoff; jint nlen, elen, clen; jzentry *ze; char *cen; @@ -880,18 +933,55 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) ze->size = CENLEN(cen); ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); ze->crc = CENCRC(cen); - ze->pos = -(zip->locpos + CENOFF(cen)); + locoff = CENOFF(cen); + ze->pos = -(zip->locpos + locoff); if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; memcpy(ze->name, cen + CENHDR, nlen); ze->name[nlen] = '\0'; if (elen > 0) { + char *extra = cen + CENHDR + nlen; + /* This entry has "extra" data */ if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; ze->extra[0] = (unsigned char) elen; ze->extra[1] = (unsigned char) (elen >> 8); - memcpy(ze->extra+2, cen + CENHDR + nlen, elen); + memcpy(ze->extra+2, extra, elen); + if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || + locoff == ZIP64_MAGICVAL) { + jint off = 0; + while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data + jint sz = SH(extra, off + 2); + if (SH(extra, off) == ZIP64_EXTID) { + off += 4; + if (ze->size == ZIP64_MAGICVAL) { + // if invalid zip64 extra fields, just skip + if (sz < 8 || (off + 8) > elen) + break; + ze->size = LL(extra, off); + sz -= 8; + off += 8; + } + if (ze->csize == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > elen) + break; + ze->csize = LL(extra, off); + sz -= 8; + off += 8; + } + if (locoff == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > elen) + break; + ze->pos = -(zip->locpos + LL(extra, off)); + sz -= 8; + off += 8; + } + break; + } + off += (sz + 4); + } + } } if (clen > 0) { diff --git a/jdk/src/share/native/java/util/zip/zip_util.h b/jdk/src/share/native/java/util/zip/zip_util.h index 3814ad02d4f..7ad11715e5a 100644 --- a/jdk/src/share/native/java/util/zip/zip_util.h +++ b/jdk/src/share/native/java/util/zip/zip_util.h @@ -38,9 +38,13 @@ #define CENSIG 0x02014b50L /* "PK\001\002" */ #define ENDSIG 0x06054b50L /* "PK\005\006" */ +#define ZIP64_ENDSIG 0x06064b50L /* "PK\006\006" */ +#define ZIP64_LOCSIG 0x07064b50L /* "PK\006\007" */ + /* * Header sizes including signatures */ + #ifdef USE_MMAP #define SIGSIZ 4 #endif @@ -49,12 +53,22 @@ #define CENHDR 46 #define ENDHDR 22 +#define ZIP64_ENDHDR 56 // ZIP64 end header size +#define ZIP64_LOCHDR 20 // ZIP64 end loc header size +#define ZIP64_EXTHDR 24 // EXT header size +#define ZIP64_EXTID 1 // Extra field Zip64 header ID + +#define ZIP64_MAGICVAL 0xffffffffLL +#define ZIP64_MAGICCOUNT 0xffff + + /* * Header field access macros */ #define CH(b, n) (((unsigned char *)(b))[n]) #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) -#define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) +#define LG(b, n) ((SH(b, n) | (SH(b, n+2) << 16)) &0xffffffffUL) +#define LL(b, n) (((jlong)LG(b, n)) | (((jlong)LG(b, n+4)) << 32)) #define GETSIG(b) LG(b, 0) /* @@ -105,6 +119,26 @@ #define ENDOFF(b) LG(b, 16) /* central directory offset */ #define ENDCOM(b) SH(b, 20) /* size of zip file comment */ +/* + * Macros for getting Zip64 end of central directory header fields + */ +#define ZIP64_ENDLEN(b) LL(b, 4) /* size of zip64 end of central dir */ +#define ZIP64_ENDVEM(b) SH(b, 12) /* version made by */ +#define ZIP64_ENDVER(b) SH(b, 14) /* version needed to extract */ +#define ZIP64_ENDNMD(b) LG(b, 16) /* number of this disk */ +#define ZIP64_ENDDSK(b) LG(b, 20) /* disk number of start */ +#define ZIP64_ENDTOD(b) LL(b, 24) /* total number of entries on this disk */ +#define ZIP64_ENDTOT(b) LL(b, 32) /* total number of entries */ +#define ZIP64_ENDSIZ(b) LL(b, 40) /* central directory size in bytes */ +#define ZIP64_ENDOFF(b) LL(b, 48) /* offset of first CEN header */ + +/* + * Macros for getting Zip64 end of central directory locator fields + */ +#define ZIP64_LOCDSK(b) LG(b, 4) /* disk number start */ +#define ZIP64_LOCOFF(b) LL(b, 8) /* offset of zip64 end */ +#define ZIP64_LOCTOT(b) LG(b, 16) /* total number of disks */ + /* * Supported compression methods */ @@ -145,7 +179,7 @@ typedef struct jzentry { /* Zip file entry */ */ typedef struct jzcell { unsigned int hash; /* 32 bit hashcode on name */ - unsigned int cenpos; /* Offset of central directory file header */ + jlong cenpos; /* Offset of central directory file header */ unsigned int next; /* hash chain: index into jzfile->entries */ } jzcell; diff --git a/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h b/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h index 9576715b2fa..00fdf06007d 100644 --- a/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h +++ b/jdk/src/share/native/java/util/zip/zlib-1.1.3/zlib.h @@ -106,11 +106,11 @@ struct internal_state; typedef struct z_stream_s { Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ + long long total_in; /* total nb of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ + long long total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ diff --git a/jdk/test/java/util/zip/LargeZip.java b/jdk/test/java/util/zip/LargeZip.java new file mode 100644 index 00000000000..e49950261b6 --- /dev/null +++ b/jdk/test/java/util/zip/LargeZip.java @@ -0,0 +1,193 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.*; +import java.nio.*; +import java.util.*; +import java.util.zip.*; + +public class LargeZip { + // If true, don't delete large ZIP file created for test. + static final boolean debug = System.getProperty("debug") != null; + + //static final int DATA_LEN = 1024 * 1024; + static final int DATA_LEN = 80 * 1024; + static final int DATA_SIZE = 8; + + static long fileSize = 6L * 1024L * 1024L * 1024L; // 6GB + + static boolean userFile = false; + + static byte[] data; + static File largeFile; + static String lastEntryName; + + /* args can be empty, in which case check a 3 GB file which is created for + * this test (and then deleted). Or it can be a number, in which case + * that designates the size of the file that's created for this test (and + * then deleted). Or it can be the name of a file to use for the test, in + * which case it is *not* deleted. Note that in this last case, the data + * comparison might fail. + */ + static void realMain (String[] args) throws Throwable { + if (args.length > 0) { + try { + fileSize = Long.parseLong(args[0]); + System.out.println("Testing with file of size " + fileSize); + } catch (NumberFormatException ex) { + largeFile = new File(args[0]); + if (!largeFile.exists()) { + throw new Exception("Specified file " + args[0] + " does not exist"); + } + userFile = true; + System.out.println("Testing with user-provided file " + largeFile); + } + } + File testDir = null; + if (largeFile == null) { + testDir = new File(System.getProperty("test.scratch", "."), + "LargeZip"); + if (testDir.exists()) { + if (!testDir.delete()) { + throw new Exception("Cannot delete already-existing test directory"); + } + } + check(!testDir.exists() && testDir.mkdirs()); + largeFile = new File(testDir, "largezip.zip"); + createLargeZip(); + } + + readLargeZip1(); + readLargeZip2(); + + if (!userFile && !debug) { + check(largeFile.delete()); + check(testDir.delete()); + } + } + + static void createLargeZip() throws Throwable { + int iterations = DATA_LEN / DATA_SIZE; + ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < iterations; i++) { + bb.putDouble(0, Math.random()); + baos.write(bb.array(), 0, DATA_SIZE); + } + data = baos.toByteArray(); + + ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(largeFile))); + long length = 0; + while (length < fileSize) { + ZipEntry ze = new ZipEntry("entry-" + length); + lastEntryName = ze.getName(); + zos.putNextEntry(ze); + zos.write(data, 0, data.length); + zos.closeEntry(); + length = largeFile.length(); + } + System.out.println("Last entry written is " + lastEntryName); + zos.close(); + } + + static void readLargeZip1() throws Throwable { + ZipFile zipFile = new ZipFile(largeFile); + ZipEntry entry = null; + String entryName = null; + int count = 0; + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + entry = entries.nextElement(); + entryName = entry.getName(); + count++; + } + System.out.println("Number of entries read: " + count); + System.out.println("Last entry read is " + entryName); + check(!entry.isDirectory()); + if (check(entryName.equals(lastEntryName))) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = zipFile.getInputStream(entry); + byte buf[] = new byte[4096]; + int len; + while ((len = is.read(buf)) >= 0) { + baos.write(buf, 0, len); + } + baos.close(); + is.close(); + check(Arrays.equals(data, baos.toByteArray())); + } + } + + + static void readLargeZip2() throws Throwable { + ZipInputStream zis = new ZipInputStream( + new BufferedInputStream(new FileInputStream(largeFile))); + ZipEntry entry = null; + String entryName = null; + int count = 0; + while ((entry = zis.getNextEntry()) != null) { + entryName = entry.getName(); + if (entryName.equals(lastEntryName)) { + break; + } + count++; + } + System.out.println("Number of entries read: " + count); + System.out.println("Last entry read is " + entryName); + check(!entry.isDirectory()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte buf[] = new byte[4096]; + int len; + while ((len = zis.read(buf)) >= 0) { + baos.write(buf, 0, len); + } + baos.close(); + check(Arrays.equals(data, baos.toByteArray())); + check(zis.getNextEntry() == null); + zis.close(); + } + + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void pass(String msg) {System.out.println(msg); passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void unexpected(Throwable t, String msg) { + System.out.println(msg); failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/jdk/test/java/util/zip/ZipFile/LargeZipFile.java b/jdk/test/java/util/zip/ZipFile/LargeZipFile.java index 479bac48bef..d228a5f93e3 100644 --- a/jdk/test/java/util/zip/ZipFile/LargeZipFile.java +++ b/jdk/test/java/util/zip/ZipFile/LargeZipFile.java @@ -158,4 +158,3 @@ public class LargeZipFile { System.out.println("\nPassed = " + passed + " failed = " + failed); if (failed > 0) throw new AssertionError("Some tests failed");} } - From fd20a6a950c588757419824103aff4d0f2b636a4 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 16:49:29 +0200 Subject: [PATCH 41/43] Added tag jdk7-b52 for changeset 7a90e89e36d1 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 89f5f016035..6d54fecdbfa 100644 --- a/.hgtags +++ b/.hgtags @@ -26,3 +26,4 @@ caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42 6b84b04a80afe23262377c60913eebfc898f14c4 jdk7-b49 5da0e6b9f4f18ef483c977337214b12ee0e1fc8f jdk7-b50 a25c5ec5e40e07733d1ff9898a0abe36159288ff jdk7-b51 +7a90e89e36d103038f8667f6a7daae34ecfa1ad8 jdk7-b52 From 9d4aff2eaf2760e6c1b328e8a3552552b3e8ed2d Mon Sep 17 00:00:00 2001 From: Xiomara Jayasena Date: Thu, 2 Apr 2009 16:51:55 -0700 Subject: [PATCH 42/43] Added tag jdk7-b53 for changeset 05e04a29c589 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 39ec72bb7a9..a611fd31d77 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -27,3 +27,4 @@ b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47 58ba2cd5a25053684ec53205d95edeeaa0006f13 jdk7-b50 fea0898259ae41c73620b1815aa48f036216155c jdk7-b51 bcbeadb4a5d759b29e876ee2c83401e91ff22f60 jdk7-b52 +a2033addca678f9e4c0d92ffa1e389171cc9321d jdk7-b53 From b01525e89b428c9ef8e6712bc0cf2637f3b31172 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 3 Apr 2009 11:36:19 +0800 Subject: [PATCH 43/43] 6825352: support self-issued certificate in keytool Reviewed-by: xuelei --- .../classes/sun/security/tools/KeyTool.java | 41 +++++------ .../sun/security/tools/keytool/selfissued.sh | 69 +++++++++++++++++++ 2 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 jdk/test/sun/security/tools/keytool/selfissued.sh diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index 1ce3ab21a02..9b4b16fa11d 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -2545,7 +2545,19 @@ public final class KeyTool { * Returns true if the certificate is self-signed, false otherwise. */ private boolean isSelfSigned(X509Certificate cert) { - return cert.getSubjectDN().equals(cert.getIssuerDN()); + return signedBy(cert, cert); + } + + private boolean signedBy(X509Certificate end, X509Certificate ca) { + if (!ca.getSubjectDN().equals(end.getIssuerDN())) { + return false; + } + try { + end.verify(ca.getPublicKey()); + return true; + } catch (Exception e) { + return false; + } } /** @@ -2869,20 +2881,18 @@ public final class KeyTool { Certificate tmpCert = replyCerts[0]; replyCerts[0] = replyCerts[i]; replyCerts[i] = tmpCert; - Principal issuer = ((X509Certificate)replyCerts[0]).getIssuerDN(); + + X509Certificate thisCert = (X509Certificate)replyCerts[0]; for (i=1; i < replyCerts.length-1; i++) { - // find a cert in the reply whose "subject" is the same as the - // given "issuer" + // find a cert in the reply who signs thisCert int j; for (j=i; j chain, Hashtable> certs) { - Principal subject = certToVerify.getSubjectDN(); Principal issuer = certToVerify.getIssuerDN(); - if (subject.equals(issuer)) { + if (isSelfSigned(certToVerify)) { // reached self-signed root cert; // no verification needed because it's trusted. chain.addElement(certToVerify); diff --git a/jdk/test/sun/security/tools/keytool/selfissued.sh b/jdk/test/sun/security/tools/keytool/selfissued.sh new file mode 100644 index 00000000000..e6e06c040b3 --- /dev/null +++ b/jdk/test/sun/security/tools/keytool/selfissued.sh @@ -0,0 +1,69 @@ +# +# Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6825352 +# @summary support self-issued certificate in keytool +# +# @run shell selfissued.sh +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KS=selfsigned.jks +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS" + +rm $KS + +$KT -alias ca -dname CN=CA -genkeypair +$KT -alias me -dname CN=CA -genkeypair +$KT -alias e1 -dname CN=E1 -genkeypair +$KT -alias e2 -dname CN=E2 -genkeypair + +# me signed by ca, self-issued +$KT -alias me -certreq | $KT -alias ca -gencert | $KT -alias me -importcert + +# Import e1 signed by me, should add me and ca +$KT -alias e1 -certreq | $KT -alias me -gencert | $KT -alias e1 -importcert +$KT -alias e1 -list -v | grep '\[3\]' || { echo Bad E1; exit 1; } + +# Import (e2 signed by me,ca,me), should reorder to (e2,me,ca) +( $KT -alias e2 -certreq | $KT -alias me -gencert; $KT -exportcert -alias ca; $KT -exportcert -alias me ) | $KT -alias e2 -importcert +$KT -alias e2 -list -v | grep '\[3\]' || { echo Bad E2; exit 1; } + +echo Good +
  • " + NL + + "Class Summary" + NL + + "Interface Summary" + NL + + "Enum Summary" + NL + + "Annotation Types Summary" + NL + + "Field Summary" + NL + + "Method Summary" + NL + + "Nested Class Summary" + NL + + "Constructor Summary" + NL + + "Enum Constant Summary" + NL + + "Required Element Summary" + NL + + "Optional Element Summary" + NL + + "Packages that use I1" + NL + + "Fields in pkg2 " + + "declared as " + + "C1" + NL + + "Methods in pkg2 " + + "with parameters of type C1" + NL + + "Fields in pkg1 " + + "declared as " + + "C2" + NL + + "Methods in pkg1 " + + "with parameters of type C2" + NL + + "Methods in pkg2 " + + "that return C2.ModalExclusionType" + NL + + "Packages that use " + + "pkg1" + NL + + "Classes in pkg1 " + + "used by pkg1" + NL + + "Packages that use " + + "pkg2" + NL + + "Classes in pkg2 " + + "used by pkg1" + NL + + "Deprecated Fields" + NL + + "Deprecated Methods" + NL + + "pkg1.C1" + NL + + "Packages
    " + + "ClassDescription" + + "InterfaceDescription" + + "EnumDescription" + + "Annotation TypeDescription" + + "Modifier and TypeField and Description" + + "Modifier and TypeMethod and Description" + + "Modifier and TypeClass and Description" + + "Constructor and Description" + + "Enum Constant and Description" + + "Modifier and TypeRequired Element and Description" + + "Modifier and TypeOptional Element and Description" + + "PackageDescription" + + "Modifier and TypeField and Description" + + "Modifier and TypeMethod and Description" + + "Modifier and TypeField and Description" + + "Modifier and TypeMethod and Description" + + "PackageDescription" + + "Modifier and TypeMethod and Description" + + "PackageDescription" + + "Class and Description" + + "PackageDescription" + + "Class and Description" + + "Field and Description" + + "Method and Description" + + "Modifier and TypeConstant FieldValue" + + "PackageDescription
    " + NL + + "Enum Constant Summary" + NL + + "Required Element Summary" + NL + + "Optional Element Summary
    Classes in pkg2 with type parameters of type Foo
    " + NL + + "Classes in pkg2" + + " with type parameters of type Foo
    ClassUseTest1<T extends Foo & Foo2>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "Methods in pkg2 with type parameters of type Foo
    " + NL + + "Methods in pkg2" + + " with type parameters of type Foo
    ClassUseTest1.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo.html", - "Fields in pkg2 with type parameters of type Foo
    " + NL + + "Fields in pkg2" + + " with type parameters of type Foo
    Fields in pkg2 declared as ParamTest
    " + NL + + "Fields in pkg2" + + " declared as ParamTest
    Classes in pkg2 with type parameters of type Foo2
    " + NL + + "Classes in pkg2" + + " with type parameters of type Foo2
    ClassUseTest1<T extends Foo & Foo2>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo2.html", - "Methods in pkg2 with type parameters of type Foo2
    " + NL + + "Methods in pkg2" + + " with type parameters of type Foo2
    ClassUseTest1.method(T t)" @@ -326,44 +347,66 @@ public class TestNewLanguageFeatures extends JavadocTester { //ClassUseTest2: > {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "Classes in pkg2 with type parameters of type ParamTest
    " + NL + + "Classes in pkg2" + + " with type parameters of type ParamTest
    ClassUseTest2<T extends ParamTest<Foo3>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "Methods in pkg2 with type parameters of type ParamTest
    " + NL + + "Methods in pkg2" + + " with type parameters of type ParamTest
    ClassUseTest2.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest.html", - "Fields in pkg2 declared as ParamTest
    " + NL + + "Fields in pkg2" + + " declared as ParamTest
    Methods in pkg2 with type parameters of type ParamTest
    " + NL + + "Methods in pkg2" + + " with type parameters of type ParamTest
    Classes in pkg2 with type parameters of type Foo3
    " + NL + + "Classes in pkg2" + + " with type parameters of type Foo3
    ClassUseTest2<T extends ParamTest<Foo3>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "Methods in pkg2 with type parameters of type Foo3
    " + NL + + "Methods in pkg2" + + " with type parameters of type Foo3
    ClassUseTest2.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo3.html", - "Methods in pkg2 that return types with arguments of type Foo3
    " + NL + + "Methods in pkg2" + + " that return types with arguments of type " + + "" + + "Foo3
    Classes in pkg2 with type parameters of type ParamTest2
    " + NL + + "Classes in pkg2" + + " with type parameters of type " + + "" + + "ParamTest2
    ClassUseTest3<T extends ParamTest2<java.util.List<? extends Foo4>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "Methods in pkg2 with type parameters of type ParamTest2
    " + NL + + "Methods in pkg2" + + " with type parameters of type " + + "" + + "ParamTest2
    ClassUseTest3.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "ParamTest2.html", - "Methods in pkg2 with type parameters of type ParamTest2
    " + NL + + "Methods in pkg2" + + " with type parameters of type " + + "" + + "ParamTest2
    Classes in pkg2 with type parameters of type Foo4
    " + NL + + "Classes in pkg2" + + " with type parameters of type " + + "" + + "Foo4
    ClassUseTest3<T extends ParamTest2<java.util.List<? extends Foo4>>>" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "Methods in pkg2 with type parameters of type Foo4
    " + NL + + "Methods in pkg2" + + " with type parameters of type Foo4
    ClassUseTest3.method(T t)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "Methods in pkg2 that return types with arguments of type Foo4
    " + NL + + "Methods in pkg2" + + " that return types with arguments of type " + + "" + + "Foo4
    Method parameters in pkg2 with type arguments of type Foo4
    " + NL + - " voidClassUseTest3.method(java.util.Set<Foo4> p)" + "
    " + NL + + "Method parameters in pkg2" + + " with type arguments of type Foo4
    Modifier and Type" + + "Method and Description
    " + NL + + " voidClassUseTest3." + + "" + + "method(java.util.Set<Foo4> p)" }, {BUG_ID + FS + "pkg2" + FS + "class-use" + FS + "Foo4.html", - "Constructor parameters in pkg2 with type arguments of type Foo4
    ClassUseTest3(java.util.Set<Foo4> p)" + "
    " + NL + + "Constructor parameters in " + + "pkg2 with type arguments of type Foo4
    Constructor and Description" + + "
    ClassUseTest3(java.util.Set<" + + "" + + "Foo4> p)" }, //================================= // Annotatation Type Usage //================================= {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "" + NL + - "Packages with annotations of type AnnotationType" + NL + - "
    pkg
    Package" + + "Description
    pkg" + + "
    " + NL + - " classAnnotationTypeUsage" + "Classes in pkg" + + " with annotations of type AnnotationType" + NL + + "
    Modifier and Type" + + "Class and Description
    " + NL + + " classAnnotationTypeUsage" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Fields in pkg with annotations of type AnnotationType" + NL + - "
    " + NL + - " intAnnotationTypeUsage.field" + "Fields in pkg" + + " with annotations of type AnnotationType" + NL + + "
    Modifier and Type" + + "Field and Description
    " + NL + + " intAnnotationTypeUsage." + + "field" + + "" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Methods in pkg with annotations of type AnnotationType" + NL + - "
    " + NL + - " voidAnnotationTypeUsage.method()" + "Methods in pkg" + + " with annotations of type AnnotationType" + NL + + "
    Modifier and Type" + + "Method and Description
    " + NL + + " voidAnnotationTypeUsage." + + "" + + "method()" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Method parameters in pkg with annotations of type AnnotationType" + NL + - "
    " + NL + - " voidAnnotationTypeUsage.methodWithParams(int documented," + NL + - " int undocmented)" + "Method parameters in pkg" + + " with annotations of type AnnotationType" + NL + + "
    Modifier and Type" + + "Method and Description
    " + NL + + " voidAnnotationTypeUsage." + + "methodWithParams(int documented," + NL + + " int undocmented)" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Constructors in pkg with annotations of type AnnotationType" + NL + - "
    AnnotationTypeUsage()" + "Constructors in pkg" + + " with annotations of type AnnotationType" + NL + + "
    Constructor and Description" + + "
    " + + "AnnotationTypeUsage()" }, {BUG_ID + FS + "pkg" + FS + "class-use" + FS + "AnnotationType.html", - "Constructor parameters in pkg with annotations of type AnnotationType" + NL + - "
    AnnotationTypeUsage(int documented," + NL + - " int undocmented)" + "Constructor parameters in pkg" + + " with annotations of type AnnotationType" + NL + + "
    Constructor and Description" + + "
    " + + "AnnotationTypeUsage(int documented," + NL + + " int undocmented)" }, //================================= diff --git a/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java b/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java index 36cd089c32f..49aafe21ffc 100644 --- a/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java +++ b/langtools/test/com/sun/javadoc/testSummaryHeading/TestSummaryHeading.java @@ -46,7 +46,8 @@ public class TestSummaryHeading extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { - {BUG_ID + FS + "C.html", "Method Summary"} + {BUG_ID + FS + "C.html", "
    " + NL + + "Method Summary