diff --git a/.hgtags b/.hgtags index ba39eb7d401..982132f3729 100644 --- a/.hgtags +++ b/.hgtags @@ -209,3 +209,4 @@ d7ad0dfaa41151bd3a9ae46725b0aec3730a9cd0 jdk8-b84 1872c12529090e1c1dbf567f02ad7ae6231b8f0c jdk8-b85 da9a4c9312816451884aa6db6f18be51a07bff13 jdk8-b86 5ebf6c63714de2c9dcf831074086d31daec819df jdk8-b87 +e517701a4d0e25ae9c7945bca6e1762a8c5d8aa6 jdk8-b88 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index f4e2d650e69..b639be15de4 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -209,3 +209,4 @@ fd1a5574cf68af24bfd52decc37ac6361afb278a jdk8-b78 7fc358f5943676b82f1dccd3152b1ac07d92e38b jdk8-b85 df9b5240f0a76c91cfe1a5b39da4d08df56e05be jdk8-b86 b9415faa7066a4d3b16d466556d5428446918d95 jdk8-b87 +e1a929afcfc492470d50be0b6b0e8dc77d3760b9 jdk8-b88 diff --git a/common/makefiles/NativeCompilation.gmk b/common/makefiles/NativeCompilation.gmk index a7b41abc1d0..2e084ea410c 100644 --- a/common/makefiles/NativeCompilation.gmk +++ b/common/makefiles/NativeCompilation.gmk @@ -411,6 +411,8 @@ define SetupNativeCompilation $1_EXTRA_LDFLAGS+="-implib:$$($1_OBJECT_DIR)/$$($1_LIBRARY).lib" endif + $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX) + ifneq (,$$($1_DEBUG_SYMBOLS)) ifeq ($(ENABLE_DEBUG_SYMBOLS), true) ifeq ($(OPENJDK_TARGET_OS), windows) @@ -549,6 +551,8 @@ define SetupNativeCompilation endif endif + $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX) + $$($1_TARGET) : $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_GEN_MANIFEST) $$(call LINKING_EXE_MSG,$$($1_BASENAME)) $$($1_LDEXE) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(EXE_OUT_OPTION)$$($1_TARGET) \ diff --git a/common/makefiles/javadoc/CORE_PKGS.gmk b/common/makefiles/javadoc/CORE_PKGS.gmk index 43c7a274818..aede99422ff 100644 --- a/common/makefiles/javadoc/CORE_PKGS.gmk +++ b/common/makefiles/javadoc/CORE_PKGS.gmk @@ -142,6 +142,7 @@ CORE_PKGS = \ java.util.prefs \ java.util.regex \ java.util.spi \ + java.util.stream \ java.util.zip \ javax.accessibility \ javax.activation \ diff --git a/common/makefiles/javadoc/Javadoc.gmk b/common/makefiles/javadoc/Javadoc.gmk index f944a7e0f46..9fe25223fb8 100644 --- a/common/makefiles/javadoc/Javadoc.gmk +++ b/common/makefiles/javadoc/Javadoc.gmk @@ -390,6 +390,17 @@ $(COREAPI_OPTIONS_FILE): $(COREAPI_OVERVIEW) $(call OptionPair,-tag,specdefault:X) ; \ $(call OptionPair,-tag,Note:X) ; \ $(call OptionPair,-tag,ToDo:X) ; \ + $(call OptionPair,-tag,apiNote:a:API Note:) ; \ + $(call OptionPair,-tag,implSpec:a:Implementation Requirements:) ; \ + $(call OptionPair,-tag,implNote:a:Implementation Note:) ; \ + $(call OptionPair,-tag,param) ; \ + $(call OptionPair,-tag,return) ; \ + $(call OptionPair,-tag,throws) ; \ + $(call OptionPair,-tag,since) ; \ + $(call OptionPair,-tag,version) ; \ + $(call OptionPair,-tag,serialData) ; \ + $(call OptionPair,-tag,factory) ; \ + $(call OptionPair,-tag,see) ; \ $(call OptionPair,-tag,$(TAG_JLS)) ; \ $(call OptionOnly,-splitIndex) ; \ $(call OptionPair,-overview,$(COREAPI_OVERVIEW)) ; \ diff --git a/corba/.hgtags b/corba/.hgtags index 152c37569a8..75d19c1528f 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -209,3 +209,4 @@ a45bb25a67c7517b45f00c9682e317f46fecbba9 jdk8-b83 9583a6431596bac1959d2d8828f5ea217843dd12 jdk8-b85 44a8ce4a759f2668ff434661a93ff462ea472478 jdk8-b86 f1709874d55a06bc3d5dfa02dbcdfbc59f4cba34 jdk8-b87 +4e3a881ebb1ee96ce0872508b0066d74f310dbfa jdk8-b88 diff --git a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/UnionGen.java b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/UnionGen.java index d2ab946c3bb..89367e69ac2 100644 --- a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/UnionGen.java +++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/UnionGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,6 +258,19 @@ public class UnionGen implements com.sun.tools.corba.se.idl.UnionGen, JavaGenera { Vector labels = vectorizeLabels (u.branches (), true); + if (Util.javaName(utype).equals ("boolean")) { + stream.println( "" ) ; + stream.println( " private void verifyDefault (boolean discriminator)" ) ; + stream.println( " {" ) ; + if (labels.contains ("true")) + stream.println (" if ( discriminator )"); + else + stream.println (" if ( !discriminator )"); + stream.println( " throw new org.omg.CORBA.BAD_OPERATION();" ) ; + stream.println( " }" ) ; + return; + } + stream.println( "" ) ; stream.println( " private void verifyDefault( " + Util.javaName(utype) + " value )" ) ; @@ -763,7 +776,7 @@ public class UnionGen implements com.sun.tools.corba.se.idl.UnionGen, JavaGenera stream.println (indent + "if (" + disName + ')'); if (firstBranch == null) - stream.println (indent + " throw new org.omg.CORBA.BAD_OPERATION ();"); + stream.println (indent + " value._default(" + disName + ");"); else { stream.println (indent + '{'); index = readBranch (index, indent + " ", firstBranch.typedef.name (), @@ -774,7 +787,7 @@ public class UnionGen implements com.sun.tools.corba.se.idl.UnionGen, JavaGenera stream.println (indent + "else"); if (secondBranch == null) - stream.println (indent + " throw new org.omg.CORBA.BAD_OPERATION ();"); + stream.println (indent + " value._default(" + disName + ");"); else { stream.println (indent + '{'); index = readBranch (index, indent + " ", secondBranch.typedef.name (), @@ -924,23 +937,25 @@ public class UnionGen implements com.sun.tools.corba.se.idl.UnionGen, JavaGenera firstBranch = secondBranch; secondBranch = tmp; } - stream.println (indent + "if (" + disName + ')'); - if (firstBranch == null) - stream.println (indent + " throw new org.omg.CORBA.BAD_OPERATION ();"); - else - { - stream.println (indent + '{'); - index = writeBranch (index, indent + " ", name, firstBranch.typedef, stream); - stream.println (indent + '}'); - } - stream.println (indent + "else"); - if (secondBranch == null) - stream.println (indent + " throw new org.omg.CORBA.BAD_OPERATION ();"); - else - { - stream.println (indent + '{'); - index = writeBranch (index, indent + " ", name, secondBranch.typedef, stream); - stream.println (indent + '}'); + if (firstBranch != null && secondBranch != null) { + stream.println (indent + "if (" + disName + ')'); + stream.println (indent + '{'); + index = writeBranch (index, indent + " ", name, firstBranch.typedef, stream); + stream.println (indent + '}'); + stream.println (indent + "else"); + stream.println (indent + '{'); + index = writeBranch (index, indent + " ", name, secondBranch.typedef, stream); + stream.println (indent + '}'); + } else if (firstBranch != null) { + stream.println (indent + "if (" + disName + ')'); + stream.println (indent + '{'); + index = writeBranch (index, indent + " ", name, firstBranch.typedef, stream); + stream.println (indent + '}'); + } else { + stream.println (indent + "if (!" + disName + ')'); + stream.println (indent + '{'); + index = writeBranch (index, indent + " ", name, secondBranch.typedef, stream); + stream.println (indent + '}'); } } return index; diff --git a/hotspot/.hgtags b/hotspot/.hgtags index f433c6708ea..7fb76babd6f 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -337,3 +337,5 @@ a947f40fb536e5b9e0aa210cf26abb430f80887a hs25-b26 d4c2667846607042370760e23f64c3ab9350e60d jdk8-b87 01d5f04e64dc2d64625b2db2056f5ed4de918a45 hs25-b29 c4af77d2045476c56fbf3f914b336bb1b7cd18af hs25-b30 +8482058e74bc8c1a890e6f3be3eff192dba6ce67 jdk8-b88 +4ec91349972255650f97bedfd07e6423e02428cf hs25-b31 diff --git a/hotspot/agent/doc/c2replay.html b/hotspot/agent/doc/cireplay.html similarity index 53% rename from hotspot/agent/doc/c2replay.html rename to hotspot/agent/doc/cireplay.html index cf90e0e8f62..71da428e58e 100644 --- a/hotspot/agent/doc/c2replay.html +++ b/hotspot/agent/doc/cireplay.html @@ -1,22 +1,22 @@
-The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method
+The compiler replay is a function to repeat the compiling process from a crashed java process in compiled method
This function only exists in debug version of VM
-First, use SA to attach to the core file, if suceeded, do - clhsdb>dumpreplaydata | -a |*/ public int nextBit(int x) { + Assert.check(currentState != BitsState.UNKNOWN); int windex = x >>> wordshift; if (windex >= bits.length) return -1; int word = bits[windex] & ~((1 << (x & wordmask))-1); @@ -202,17 +369,20 @@ public class Bits { /** a string representation of this set. */ public String toString() { - char[] digits = new char[bits.length * wordlen]; - for (int i = 0; i < bits.length * wordlen; i++) - digits[i] = isMember(i) ? '1' : '0'; - return new String(digits); + if (bits.length > 0) { + char[] digits = new char[bits.length * wordlen]; + for (int i = 0; i < bits.length * wordlen; i++) + digits[i] = isMember(i) ? '1' : '0'; + return new String(digits); + } else { + return "[]"; + } } /** Test Bits.nextBit(int). */ public static void main(String[] args) { java.util.Random r = new java.util.Random(); Bits bits = new Bits(); - int dupCount = 0; for (int i=0; i<125; i++) { int k; do { diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java index da28e39a630..b6f7d66dc38 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java @@ -341,9 +341,14 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { * */ public String name() { - return getClassName(tsym, false); + if (name == null) { + name = getClassName(tsym, false); + } + return name; } + private String name; + /** * Return the qualified class name as a String. *[> replay.txt] + +First, use SA to attach to the core file, if succeeded, do + hsdb> dumpreplaydata <address> | -a | <thread_id> [> replay.txt] create file replay.txt, address is address of Method, or nmethod(CodeBlob) - clhsdb>buildreplayjars [all | boot | app] + hsdb> buildreplayjars [all | boot | app] create files: all: app.jar, boot.jar @@ -26,16 +26,16 @@ First, use SA to attach to the core file, if suceeded, do app.jar exit SA now. Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java - java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=--XX:+ReplayCompiles .... + java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles .... This will replay the compiling process. With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app. notes: 1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes. - 2) If encounter error as " " not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/ /proc/ + 2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform> Use this tool to dump VM type library: - vmstructsdump libjvm.so > .db + vmstructsdump libjvm.so > <type_name>.db - set env SA_TYPEDB= .db (refer different shell for set envs) + set env SA_TYPEDB=<type_name>.db (refer different shell for set envs) diff --git a/hotspot/agent/doc/clhsdb.html b/hotspot/agent/doc/clhsdb.html index f1c43fd1e5f..ad43bf7ee57 100644 --- a/hotspot/agent/doc/clhsdb.html +++ b/hotspot/agent/doc/clhsdb.html @@ -15,7 +15,7 @@ GUI tools. Command line HSDB (CLHSDB) tool is alternative to SA GUI tool HSDB. There is also JavaScript based SA command line interface called jsdb. But, CLHSDB supports Unix shell-like (or dbx/gdb-like) command line interface with -support for output redirection/appending (familiar >, >>), command history and so on. +support for output redirection/appending (familiar >, >>), command history and so on. Each CLHSDB command can have zero or more arguments and optionally end with output redirection (or append) to a file. Commands may be stored in a file and run using source command. help command prints usage message for all supported commands (or a specific command) @@ -49,7 +49,7 @@ Available commands: dumpheap [ file ] dump heap in hprof binary format dumpideal -a | id dump ideal graph like debug flag -XX:+PrintIdeal dumpilt -a | id dump inline tree for C2 compilation - dumpreplaydata
| -a |[>replay.txt] dump replay data into a file + dumpreplaydata <address> | -a | <thread_id> [>replay.txt] dump replay data into a file echo [ true | false ] turn on/off command echo mode examine [ address/count ] | [ address,address] show contents of memory from given address field [ type [ name fieldtype isStatic offset address ] ] print info about a field of HotSpot type @@ -96,11 +96,11 @@ Available commands: JavaScript integration
-Few CLHSDB commands are already implemented in JavaScript. It is possible to extend CLHSDB command set +
Few CLHSDB commands are already implemented in JavaScript. It is possible to extend CLHSDB command set by implementing more commands in a JavaScript file and by loading it by jsload command. jseval command may be used to evaluate arbitrary JavaScript expression from a string. Any JavaScript function may be exposed as a CLHSDB command by registering it using JavaScript
@@ -127,11 +127,11 @@ hsdb> jsload test.jsregisterCommand
-function. This function accepts command name, usage and name of the JavaScript implementation function +function. This function accepts command name, usage and name of the JavaScript implementation function as arguments.C2 Compilation Replay
+Compilation Replay
When a java process crashes in compiled method, usually a core file is saved. -The C2 replay function can reproduce the compiling process in the core. -c2replay.html +The replay function can reproduce the compiling process in the core. +cireplay.html diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java index 871ee414a44..c1e6d503196 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java @@ -93,10 +93,11 @@ public class ciEnv extends VMObject { CompileTask task = task(); Method method = task.method(); int entryBci = task.osrBci(); + int compLevel = task.compLevel(); Klass holder = method.getMethodHolder(); out.println("compile " + holder.getName().asString() + " " + OopUtilities.escapeString(method.getName().asString()) + " " + method.getSignature().asString() + " " + - entryBci); + entryBci + " " + compLevel); } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java index b0b370cef3c..243a5397a0d 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -78,6 +78,8 @@ public class NMethod extends CodeBlob { current sweep traversal index. */ private static CIntegerField stackTraversalMarkField; + private static CIntegerField compLevelField; + static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -113,7 +115,7 @@ public class NMethod extends CodeBlob { osrEntryPointField = type.getAddressField("_osr_entry_point"); lockCountField = type.getJIntField("_lock_count"); stackTraversalMarkField = type.getCIntegerField("_stack_traversal_mark"); - + compLevelField = type.getCIntegerField("_comp_level"); pcDescSize = db.lookupType("PcDesc").getSize(); } @@ -530,7 +532,7 @@ public class NMethod extends CodeBlob { out.println("compile " + holder.getName().asString() + " " + OopUtilities.escapeString(method.getName().asString()) + " " + method.getSignature().asString() + " " + - getEntryBCI()); + getEntryBCI() + " " + getCompLevel()); } @@ -551,4 +553,5 @@ public class NMethod extends CodeBlob { private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); } private int getNulChkTableOffset() { return (int) nulChkTableOffsetField .getValue(addr); } private int getNMethodEndOffset() { return (int) nmethodEndOffsetField .getValue(addr); } + private int getCompLevel() { return (int) compLevelField .getValue(addr); } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java index 45ef0a2d27a..0a4273f3ef8 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java @@ -46,10 +46,12 @@ public class CompileTask extends VMObject { Type type = db.lookupType("CompileTask"); methodField = type.getAddressField("_method"); osrBciField = new CIntField(type.getCIntegerField("_osr_bci"), 0); + compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); } private static AddressField methodField; private static CIntField osrBciField; + private static CIntField compLevelField; public CompileTask(Address addr) { super(addr); @@ -63,4 +65,8 @@ public class CompileTask extends VMObject { public int osrBci() { return (int)osrBciField.getValue(getAddress()); } + + public int compLevel() { + return (int)compLevelField.getValue(getAddress()); + } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java index 675edeba0d3..d9ea364edaa 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java @@ -117,8 +117,6 @@ public class JMap extends Tool { mode = MODE_HEAP_SUMMARY; } else if (modeFlag.equals("-histo")) { mode = MODE_HISTOGRAM; - } else if (modeFlag.equals("-permstat")) { - mode = MODE_CLSTATS; } else if (modeFlag.equals("-clstats")) { mode = MODE_CLSTATS; } else if (modeFlag.equals("-finalizerinfo")) { diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index df4d53fe621..a189566b812 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=31 +HS_BUILD_NUMBER=32 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make index 819aae43e22..ea16fca3dde 100644 --- a/hotspot/make/windows/makefiles/compile.make +++ b/hotspot/make/windows/makefiles/compile.make @@ -52,7 +52,7 @@ CXX=cl.exe # improving the quality of crash log stack traces involving jvm.dll. # These are always used in all compiles -CXX_FLAGS=/nologo /W3 /WX +CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX # Let's add debug information when Full Debug Symbols is enabled !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make index 4bee0afa8b0..acf4d24d7e0 100644 --- a/hotspot/make/windows/makefiles/defs.make +++ b/hotspot/make/windows/makefiles/defs.make @@ -193,7 +193,7 @@ ifdef COOKED_BUILD_NUMBER MAKE_ARGS += JDK_BUILD_NUMBER=$(COOKED_BUILD_NUMBER) endif -NMAKE= MAKEFLAGS= MFLAGS= nmake -NOLOGO +NMAKE= MAKEFLAGS= MFLAGS= EXTRA_CFLAGS="$(EXTRA_CFLAGS)" nmake -NOLOGO ifndef SYSTEM_UNAME SYSTEM_UNAME := $(shell uname) export SYSTEM_UNAME diff --git a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp new file mode 100644 index 00000000000..791331168d2 --- /dev/null +++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" +#include "code/icBuffer.hpp" +#include "code/nmethod.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/safepoint.hpp" +#ifdef COMPILER2 +#include "opto/matcher.hpp" +#endif + +// Release the CompiledICHolder* associated with this call site is there is one. +void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) { + // This call site might have become stale so inspect it carefully. + NativeCall* call = nativeCall_at(call_site->addr()); + if (is_icholder_entry(call->destination())) { + NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value()); + InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data()); + } +} + +bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { + // This call site might have become stale so inspect it carefully. + NativeCall* call = nativeCall_at(call_site->addr()); + return is_icholder_entry(call->destination()); +} + +//----------------------------------------------------------------------------- +// High-level access to an inline cache. Guaranteed to be MT-safe. + +CompiledIC::CompiledIC(nmethod* nm, NativeCall* call) + : _ic_call(call) +{ + address ic_call = call->instruction_address(); + + assert(ic_call != NULL, "ic_call address must be set"); + assert(nm != NULL, "must pass nmethod"); + assert(nm->contains(ic_call), "must be in nmethod"); + + // Search for the ic_call at the given address. + RelocIterator iter(nm, ic_call, ic_call+1); + bool ret = iter.next(); + assert(ret == true, "relocInfo must exist at this address"); + assert(iter.addr() == ic_call, "must find ic_call"); + if (iter.type() == relocInfo::virtual_call_type) { + virtual_call_Relocation* r = iter.virtual_call_reloc(); + _is_optimized = false; + _value = nativeMovConstReg_at(r->cached_value()); + } else { + assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call"); + _is_optimized = true; + _value = NULL; + } +} + +// ---------------------------------------------------------------------------- + +#define __ _masm. +void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +#ifdef COMPILER2 + // Stub is fixed up when the corresponding call is converted from calling + // compiled code to calling interpreted code. + // set (empty), G5 + // jmp -1 + + address mark = cbuf.insts_mark(); // Get mark within main instrs section. + + MacroAssembler _masm(&cbuf); + + address base = + __ start_a_stub(to_interp_stub_size()*2); + if (base == NULL) return; // CodeBuffer::expand failed. + + // Static stub relocation stores the instruction address of the call. + __ relocate(static_stub_Relocation::spec(mark)); + + __ set_metadata(NULL, as_Register(Matcher::inline_cache_reg_encode())); + + __ set_inst_mark(); + AddressLiteral addrlit(-1); + __ JUMP(addrlit, G3, 0); + + __ delayed()->nop(); + + // Update current stubs pointer and restore code_end. + __ end_a_stub(); +#else + ShouldNotReachHere(); +#endif +} +#undef __ + +int CompiledStaticCall::to_interp_stub_size() { + // This doesn't need to be accurate but it must be larger or equal to + // the real size of the stub. + return (NativeMovConstReg::instruction_size + // sethi/setlo; + NativeJump::instruction_size + // sethi; jmp; nop + (TraceJumps ? 20 * BytesPerInstWord : 0) ); +} + +// Relocation entries for call stub, compiled java to interpreter. +int CompiledStaticCall::reloc_to_interp_stub() { + return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call +} + +void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { + address stub = find_stub(); + guarantee(stub != NULL, "stub not found"); + + if (TraceICs) { + ResourceMark rm; + tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", + instruction_address(), + callee->name_and_sig_as_C_string()); + } + + // Creation also verifies the object. + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + + assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), + "a) MT-unsafe modification of inline cache"); + assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + "b) MT-unsafe modification of inline cache"); + + // Update stub. + method_holder->set_data((intptr_t)callee()); + jump->set_jump_destination(entry); + + // Update jump to call. + set_destination_mt_safe(stub); +} + +void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { + assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call"); + // Reset stub. + address stub = static_stub->addr(); + assert(stub != NULL, "stub not found"); + // Creation also verifies the object. + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + method_holder->set_data(0); + jump->set_jump_destination((address)-1); +} + +//----------------------------------------------------------------------------- +// Non-product mode code +#ifndef PRODUCT + +void CompiledStaticCall::verify() { + // Verify call. + NativeCall::verify(); + if (os::is_MP()) { + verify_alignment(); + } + + // Verify stub. + address stub = find_stub(); + assert(stub != NULL, "no stub found for static call"); + // Creation also verifies the object. + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + + // Verify state. + assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); +} + +#endif // !PRODUCT diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 4107392e6b4..ebbce2e7741 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1655,53 +1655,6 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const { return ra_->C->scratch_emit_size(this); } -//============================================================================= - -// emit call stub, compiled java to interpretor -void emit_java_to_interp(CodeBuffer &cbuf ) { - - // Stub is fixed up when the corresponding call is converted from calling - // compiled code to calling interpreted code. - // set (empty), G5 - // jmp -1 - - address mark = cbuf.insts_mark(); // get mark within main instrs section - - MacroAssembler _masm(&cbuf); - - address base = - __ start_a_stub(Compile::MAX_stubs_size); - if (base == NULL) return; // CodeBuffer::expand failed - - // static stub relocation stores the instruction address of the call - __ relocate(static_stub_Relocation::spec(mark)); - - __ set_metadata(NULL, reg_to_register_object(Matcher::inline_cache_reg_encode())); - - __ set_inst_mark(); - AddressLiteral addrlit(-1); - __ JUMP(addrlit, G3, 0); - - __ delayed()->nop(); - - // Update current stubs pointer and restore code_end. - __ end_a_stub(); -} - -// size of call stub, compiled java to interpretor -uint size_java_to_interp() { - // This doesn't need to be accurate but it must be larger or equal to - // the real size of the stub. - return (NativeMovConstReg::instruction_size + // sethi/setlo; - NativeJump::instruction_size + // sethi; jmp; nop - (TraceJumps ? 20 * BytesPerInstWord : 0) ); -} -// relocation entries for call stub, compiled java to interpretor -uint reloc_java_to_interp() { - return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call -} - - //============================================================================= #ifndef PRODUCT void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { @@ -2576,15 +2529,15 @@ encode %{ enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. - if ( !_method ) { + if (!_method) { emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type); } else if (_optimized_virtual) { emit_call_reloc(cbuf, $meth$$method, relocInfo::opt_virtual_call_type); } else { emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type); } - if( _method ) { // Emit stub for static call - emit_java_to_interp(cbuf); + if (_method) { // Emit stub for static call. + CompiledStaticCall::emit_to_interp_stub(cbuf); } %} diff --git a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp new file mode 100644 index 00000000000..957695fdc32 --- /dev/null +++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" +#include "code/icBuffer.hpp" +#include "code/nmethod.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/safepoint.hpp" + +// Release the CompiledICHolder* associated with this call site is there is one. +void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) { + // This call site might have become stale so inspect it carefully. + NativeCall* call = nativeCall_at(call_site->addr()); + if (is_icholder_entry(call->destination())) { + NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value()); + InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data()); + } +} + +bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { + // This call site might have become stale so inspect it carefully. + NativeCall* call = nativeCall_at(call_site->addr()); + return is_icholder_entry(call->destination()); +} + +//----------------------------------------------------------------------------- +// High-level access to an inline cache. Guaranteed to be MT-safe. + +CompiledIC::CompiledIC(nmethod* nm, NativeCall* call) + : _ic_call(call) +{ + address ic_call = call->instruction_address(); + + assert(ic_call != NULL, "ic_call address must be set"); + assert(nm != NULL, "must pass nmethod"); + assert(nm->contains(ic_call), "must be in nmethod"); + + // Search for the ic_call at the given address. + RelocIterator iter(nm, ic_call, ic_call+1); + bool ret = iter.next(); + assert(ret == true, "relocInfo must exist at this address"); + assert(iter.addr() == ic_call, "must find ic_call"); + if (iter.type() == relocInfo::virtual_call_type) { + virtual_call_Relocation* r = iter.virtual_call_reloc(); + _is_optimized = false; + _value = nativeMovConstReg_at(r->cached_value()); + } else { + assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call"); + _is_optimized = true; + _value = NULL; + } +} + +// ---------------------------------------------------------------------------- + +#define __ _masm. +void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { + // Stub is fixed up when the corresponding call is converted from + // calling compiled code to calling interpreted code. + // movq rbx, 0 + // jmp -5 # to self + + address mark = cbuf.insts_mark(); // Get mark within main instrs section. + + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a stub. + MacroAssembler _masm(&cbuf); + + address base = + __ start_a_stub(to_interp_stub_size()*2); + if (base == NULL) return; // CodeBuffer::expand failed. + // Static stub relocation stores the instruction address of the call. + __ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand); + // Static stub relocation also tags the Method* in the code-stream. + __ mov_metadata(rbx, (Metadata*) NULL); // Method is zapped till fixup time. + // This is recognized as unresolved by relocs/nativeinst/ic code. + __ jump(RuntimeAddress(__ pc())); + + // Update current stubs pointer and restore insts_end. + __ end_a_stub(); +} +#undef __ + +int CompiledStaticCall::to_interp_stub_size() { + return NOT_LP64(10) // movl; jmp + LP64_ONLY(15); // movq (1+1+8); jmp (1+4) +} + +// Relocation entries for call stub, compiled java to interpreter. +int CompiledStaticCall::reloc_to_interp_stub() { + return 4; // 3 in emit_to_interp_stub + 1 in emit_call +} + +void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { + address stub = find_stub(); + guarantee(stub != NULL, "stub not found"); + + if (TraceICs) { + ResourceMark rm; + tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", + instruction_address(), + callee->name_and_sig_as_C_string()); + } + + // Creation also verifies the object. + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + + assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), + "a) MT-unsafe modification of inline cache"); + assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + "b) MT-unsafe modification of inline cache"); + + // Update stub. + method_holder->set_data((intptr_t)callee()); + jump->set_jump_destination(entry); + + // Update jump to call. + set_destination_mt_safe(stub); +} + +void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { + assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call"); + // Reset stub. + address stub = static_stub->addr(); + assert(stub != NULL, "stub not found"); + // Creation also verifies the object. + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + method_holder->set_data(0); + jump->set_jump_destination((address)-1); +} + +//----------------------------------------------------------------------------- +// Non-product mode code +#ifndef PRODUCT + +void CompiledStaticCall::verify() { + // Verify call. + NativeCall::verify(); + if (os::is_MP()) { + verify_alignment(); + } + + // Verify stub. + address stub = find_stub(); + assert(stub != NULL, "no stub found for static call"); + // Creation also verifies the object. + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + + // Verify state. + assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); +} + +#endif // !PRODUCT diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 4560fb2c526..316ebe2911d 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1256,43 +1256,6 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const { } } -//============================================================================= - -// emit call stub, compiled java to interpreter -void emit_java_to_interp(CodeBuffer &cbuf ) { - // Stub is fixed up when the corresponding call is converted from calling - // compiled code to calling interpreted code. - // mov rbx,0 - // jmp -1 - - address mark = cbuf.insts_mark(); // get mark within main instrs section - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a stub. - MacroAssembler _masm(&cbuf); - - address base = - __ start_a_stub(Compile::MAX_stubs_size); - if (base == NULL) return; // CodeBuffer::expand failed - // static stub relocation stores the instruction address of the call - __ relocate(static_stub_Relocation::spec(mark), RELOC_IMM32); - // static stub relocation also tags the Method* in the code-stream. - __ mov_metadata(rbx, (Metadata*)NULL); // method is zapped till fixup time - // This is recognized as unresolved by relocs/nativeInst/ic code - __ jump(RuntimeAddress(__ pc())); - - __ end_a_stub(); - // Update current stubs pointer and restore insts_end. -} -// size of call stub, compiled java to interpretor -uint size_java_to_interp() { - return 10; // movl; jmp -} -// relocation entries for call stub, compiled java to interpretor -uint reloc_java_to_interp() { - return 4; // 3 in emit_java_to_interp + 1 in Java_Static_Call -} - //============================================================================= #ifndef PRODUCT void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream* st ) const { @@ -1909,8 +1872,8 @@ encode %{ emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), static_call_Relocation::spec(), RELOC_IMM32 ); } - if (_method) { // Emit stub for static call - emit_java_to_interp(cbuf); + if (_method) { // Emit stub for static call. + CompiledStaticCall::emit_to_interp_stub(cbuf); } %} diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 170e2ff1100..e47976270cd 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -1387,48 +1387,6 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const return (offset < 0x80) ? 5 : 8; // REX } -//============================================================================= - -// emit call stub, compiled java to interpreter -void emit_java_to_interp(CodeBuffer& cbuf) -{ - // Stub is fixed up when the corresponding call is converted from - // calling compiled code to calling interpreted code. - // movq rbx, 0 - // jmp -5 # to self - - address mark = cbuf.insts_mark(); // get mark within main instrs section - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a stub. - MacroAssembler _masm(&cbuf); - - address base = - __ start_a_stub(Compile::MAX_stubs_size); - if (base == NULL) return; // CodeBuffer::expand failed - // static stub relocation stores the instruction address of the call - __ relocate(static_stub_Relocation::spec(mark), RELOC_IMM64); - // static stub relocation also tags the Method* in the code-stream. - __ mov_metadata(rbx, (Metadata*) NULL); // method is zapped till fixup time - // This is recognized as unresolved by relocs/nativeinst/ic code - __ jump(RuntimeAddress(__ pc())); - - // Update current stubs pointer and restore insts_end. - __ end_a_stub(); -} - -// size of call stub, compiled java to interpretor -uint size_java_to_interp() -{ - return 15; // movq (1+1+8); jmp (1+4) -} - -// relocation entries for call stub, compiled java to interpretor -uint reloc_java_to_interp() -{ - return 4; // 3 in emit_java_to_interp + 1 in Java_Static_Call -} - //============================================================================= #ifndef PRODUCT void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const @@ -2078,8 +2036,8 @@ encode %{ RELOC_DISP32); } if (_method) { - // Emit stub for static call - emit_java_to_interp(cbuf); + // Emit stub for static call. + CompiledStaticCall::emit_to_interp_stub(cbuf); } %} diff --git a/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp new file mode 100644 index 00000000000..6fa39ea078b --- /dev/null +++ b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/systemDictionary.hpp" +#include "code/codeCache.hpp" +#include "code/compiledIC.hpp" +#include "code/icBuffer.hpp" +#include "code/nmethod.hpp" +#include "code/vtableStubs.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/metadataFactory.hpp" +#include "memory/oopFactory.hpp" +#include "oops/method.hpp" +#include "oops/oop.inline.hpp" +#include "oops/symbol.hpp" +#include "runtime/icache.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/events.hpp" + + +// Release the CompiledICHolder* associated with this call site is there is one. +void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) { + // This call site might have become stale so inspect it carefully. + NativeCall* call = nativeCall_at(call_site->addr()); + if (is_icholder_entry(call->destination())) { + NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value()); + InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data()); + } +} + +bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { + // This call site might have become stale so inspect it carefully. + NativeCall* call = nativeCall_at(call_site->addr()); + return is_icholder_entry(call->destination()); +} + +//----------------------------------------------------------------------------- +// High-level access to an inline cache. Guaranteed to be MT-safe. + +CompiledIC::CompiledIC(nmethod* nm, NativeCall* call) + : _ic_call(call) +{ + address ic_call = call->instruction_address(); + + assert(ic_call != NULL, "ic_call address must be set"); + assert(nm != NULL, "must pass nmethod"); + assert(nm->contains(ic_call), "must be in nmethod"); + + // Search for the ic_call at the given address. + RelocIterator iter(nm, ic_call, ic_call+1); + bool ret = iter.next(); + assert(ret == true, "relocInfo must exist at this address"); + assert(iter.addr() == ic_call, "must find ic_call"); + if (iter.type() == relocInfo::virtual_call_type) { + virtual_call_Relocation* r = iter.virtual_call_reloc(); + _is_optimized = false; + _value = nativeMovConstReg_at(r->cached_value()); + } else { + assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call"); + _is_optimized = true; + _value = NULL; + } +} + +// ---------------------------------------------------------------------------- + +void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { + ShouldNotReachHere(); // Only needed for COMPILER2. +} + +int CompiledStaticCall::to_interp_stub_size() { + ShouldNotReachHere(); // Only needed for COMPILER2. + return 0; +} + +// Relocation entries for call stub, compiled java to interpreter. +int CompiledStaticCall::reloc_to_interp_stub() { + ShouldNotReachHere(); // Only needed for COMPILER2. + return 0; +} + +void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { + ShouldNotReachHere(); // Only needed for COMPILER2. +} + +void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { + ShouldNotReachHere(); // Only needed for COMPILER2. +} + +//----------------------------------------------------------------------------- +// Non-product mode code. +#ifndef PRODUCT + +void CompiledStaticCall::verify() { + ShouldNotReachHere(); // Only needed for COMPILER2. +} + +#endif // !PRODUCT diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 12c3f7c0fd6..f0b32196f5d 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -1230,10 +1230,6 @@ bool os::dll_build_name(char* buffer, size_t buflen, return retval; } -const char* os::get_current_directory(char *buf, int buflen) { - return getcwd(buf, buflen); -} - // check if addr is inside libjvm.so bool os::address_is_in_vm(address addr) { static address libjvm_base_addr; diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index f4dd5777299..4ca47019569 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1663,10 +1663,6 @@ bool os::dll_build_name(char* buffer, size_t buflen, return retval; } -const char* os::get_current_directory(char *buf, int buflen) { - return getcwd(buf, buflen); -} - // check if addr is inside libjvm.so bool os::address_is_in_vm(address addr) { static address libjvm_base_addr; diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 03302783688..e2d7c2d7f7f 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -251,3 +251,11 @@ bool os::has_allocatable_memory_limit(julong* limit) { return true; #endif } + +const char* os::get_current_directory(char *buf, size_t buflen) { + return getcwd(buf, buflen); +} + +FILE* os::open(int fd, const char* mode) { + return ::fdopen(fd, mode); +} diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 566f3c1cd46..09204157d65 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1916,10 +1916,6 @@ bool os::dll_build_name(char* buffer, size_t buflen, return retval; } -const char* os::get_current_directory(char *buf, int buflen) { - return getcwd(buf, buflen); -} - // check if addr is inside libjvm.so bool os::address_is_in_vm(address addr) { static address libjvm_base_addr; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index a9b8136d305..dfcb64dd99b 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -1221,8 +1221,10 @@ bool os::dll_build_name(char *buffer, size_t buflen, // Needs to be in os specific directory because windows requires another // header file
- * - * @param cal-const char* os::get_current_directory(char *buf, int buflen) { - return _getcwd(buf, buflen); +const char* os::get_current_directory(char *buf, size_t buflen) { + int n = static_cast (buflen); + if (buflen > INT_MAX) n = INT_MAX; + return _getcwd(buf, n); } //----------------------------------------------------------- @@ -4098,6 +4100,10 @@ int os::open(const char *path, int oflag, int mode) { return ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode); } +FILE* os::open(int fd, const char* mode) { + return ::_fdopen(fd, mode); +} + // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { WIN32_FIND_DATA fd; diff --git a/hotspot/src/share/vm/adlc/main.cpp b/hotspot/src/share/vm/adlc/main.cpp index 8ecce63dd78..4b812316381 100644 --- a/hotspot/src/share/vm/adlc/main.cpp +++ b/hotspot/src/share/vm/adlc/main.cpp @@ -213,6 +213,7 @@ int main(int argc, char *argv[]) AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_file, "memory/allocation.inline.hpp"); AD.addInclude(AD._CPP_file, "asm/macroAssembler.inline.hpp"); + AD.addInclude(AD._CPP_file, "code/compiledIC.hpp"); AD.addInclude(AD._CPP_file, "code/vmreg.hpp"); AD.addInclude(AD._CPP_file, "gc_interface/collectedHeap.inline.hpp"); AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp"); diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 4199c8b5fe6..7776db5eb6d 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -1150,23 +1150,9 @@ void ciEnv::record_out_of_memory_failure() { record_method_not_compilable("out of memory"); } -fileStream* ciEnv::_replay_data_stream = NULL; - -void ciEnv::dump_replay_data() { +void ciEnv::dump_replay_data(outputStream* out) { VM_ENTRY_MARK; MutexLocker ml(Compile_lock); - if (_replay_data_stream == NULL) { - _replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile); - if (_replay_data_stream == NULL) { - fatal(err_msg("Can't open %s for replay data", ReplayDataFile)); - } - } - dump_replay_data(_replay_data_stream); -} - - -void ciEnv::dump_replay_data(outputStream* out) { - ASSERT_IN_VM; ResourceMark rm; #if INCLUDE_JVMTI out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables); @@ -1179,13 +1165,15 @@ void ciEnv::dump_replay_data(outputStream* out) { for (int i = 0; i < objects->length(); i++) { objects->at(i)->dump_replay_data(out); } - Method* method = task()->method(); - int entry_bci = task()->osr_bci(); + CompileTask* task = this->task(); + Method* method = task->method(); + int entry_bci = task->osr_bci(); + int comp_level = task->comp_level(); // Klass holder = method->method_holder(); - out->print_cr("compile %s %s %s %d", + out->print_cr("compile %s %s %s %d %d", method->klass_name()->as_quoted_ascii(), method->name()->as_quoted_ascii(), method->signature()->as_quoted_ascii(), - entry_bci); + entry_bci, comp_level); out->flush(); } diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index 042bc32fa00..45dd42eb25e 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -46,8 +46,6 @@ class ciEnv : StackObj { friend class CompileBroker; friend class Dependencies; // for get_object, during logging - static fileStream* _replay_data_stream; - private: Arena* _arena; // Alias for _ciEnv_arena except in init_shared_objects() Arena _ciEnv_arena; @@ -451,10 +449,6 @@ public: // RedefineClasses support void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); } - // Dump the compilation replay data for this ciEnv to - // ReplayDataFile, creating the file if needed. - void dump_replay_data(); - // Dump the compilation replay data for the ciEnv to the stream. void dump_replay_data(outputStream* out); }; diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index f206f1991a0..46ea500b551 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -196,7 +196,6 @@ class ciMethod : public ciMetadata { // Analysis and profiling. // // Usage note: liveness_at_bci and init_vars should be wrapped in ResourceMarks. - bool uses_monitors() const { return _uses_monitors; } // this one should go away, it has a misleading name bool has_monitor_bytecodes() const { return _uses_monitors; } bool has_balanced_monitors(); diff --git a/hotspot/src/share/vm/ci/ciReplay.cpp b/hotspot/src/share/vm/ci/ciReplay.cpp index 0d68b8cc891..a314f35f821 100644 --- a/hotspot/src/share/vm/ci/ciReplay.cpp +++ b/hotspot/src/share/vm/ci/ciReplay.cpp @@ -89,7 +89,7 @@ class CompileReplay : public StackObj { loader = Handle(thread, SystemDictionary::java_system_loader()); stream = fopen(filename, "rt"); if (stream == NULL) { - fprintf(stderr, "Can't open replay file %s\n", filename); + fprintf(stderr, "ERROR: Can't open replay file %s\n", filename); } buffer_length = 32; buffer = NEW_RESOURCE_ARRAY(char, buffer_length); @@ -327,7 +327,6 @@ class CompileReplay : public StackObj { if (had_error()) { tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); tty->print_cr("%s", buffer); - assert(false, "error"); return; } pos = 0; @@ -370,11 +369,47 @@ class CompileReplay : public StackObj { } } - // compile + // validation of comp_level + bool is_valid_comp_level(int comp_level) { + const int msg_len = 256; + char* msg = NULL; + if (!is_compile(comp_level)) { + msg = NEW_RESOURCE_ARRAY(char, msg_len); + jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level); + } else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) { + msg = NEW_RESOURCE_ARRAY(char, msg_len); + switch (comp_level) { + case CompLevel_simple: + jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level); + break; + case CompLevel_full_optimization: + jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level); + break; + default: + jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level); + } + } + if (msg != NULL) { + report_error(msg); + return false; + } + return true; + } + + // compile void process_compile(TRAPS) { // methodHandle method; Method* method = parse_method(CHECK); int entry_bci = parse_int("entry_bci"); + const char* comp_level_label = "comp_level"; + int comp_level = parse_int(comp_level_label); + // old version w/o comp_level + if (had_error() && (error_message() == comp_level_label)) { + comp_level = CompLevel_full_optimization; + } + if (!is_valid_comp_level(comp_level)) { + return; + } Klass* k = method->method_holder(); ((InstanceKlass*)k)->initialize(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -389,12 +424,12 @@ class CompileReplay : public StackObj { } } // Make sure the existence of a prior compile doesn't stop this one - nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code(); + nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); if (nm != NULL) { nm->make_not_entrant(); } replay_state = this; - CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization, + CompileBroker::compile_method(method, entry_bci, comp_level, methodHandle(), 0, "replay", THREAD); replay_state = NULL; reset(); @@ -551,7 +586,7 @@ class CompileReplay : public StackObj { if (parsed_two_word == i) continue; default: - ShouldNotReachHere(); + fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value())); break; } @@ -819,6 +854,11 @@ int ciReplay::replay_impl(TRAPS) { ReplaySuppressInitializers = 1; } + if (FLAG_IS_DEFAULT(ReplayDataFile)) { + tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt)."); + return 1; + } + // Load and parse the replay data CompileReplay rp(ReplayDataFile, THREAD); int exit_code = 0; diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 5b9358b98e5..650a299f346 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -1345,9 +1345,10 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { tty->print_cr("CompileTheWorld (%d) : %s", _compile_the_world_class_counter, buffer); // Preload all classes to get around uncommon traps // Iterate over all methods in class + int comp_level = CompilationPolicy::policy()->initial_compile_level(); for (int n = 0; n < k->methods()->length(); n++) { methodHandle m (THREAD, k->methods()->at(n)); - if (CompilationPolicy::can_be_compiled(m)) { + if (CompilationPolicy::can_be_compiled(m, comp_level)) { if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) { // Give sweeper a chance to keep up with CTW @@ -1356,7 +1357,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { _codecache_sweep_counter = 0; } // Force compilation - CompileBroker::compile_method(m, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(), + CompileBroker::compile_method(m, InvocationEntryBci, comp_level, methodHandle(), 0, "CTW", THREAD); if (HAS_PENDING_EXCEPTION) { clear_pending_exception_if_not_oom(CHECK); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 6cafd76c852..c030645f64b 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -53,6 +53,7 @@ #include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "memory/gcLocker.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" @@ -65,17 +66,19 @@ ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; -ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) : +ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) : _class_loader(h_class_loader()), _is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially _metaspace(NULL), _unloading(false), _klasses(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), - _next(NULL), _dependencies(), + _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { // empty } void ClassLoaderData::init_dependencies(TRAPS) { + assert(!Universe::is_fully_initialized(), "should only be called when initializing"); + assert(is_the_null_class_loader_data(), "should only call this for the null class loader"); _dependencies.init(CHECK); } @@ -429,7 +432,7 @@ void ClassLoaderData::free_deallocate_list() { // These anonymous class loaders are to contain classes used for JSR292 ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) { // Add a new class loader data to the graph. - return ClassLoaderDataGraph::add(NULL, loader, CHECK_NULL); + return ClassLoaderDataGraph::add(loader, true, CHECK_NULL); } const char* ClassLoaderData::loader_name() { @@ -501,19 +504,22 @@ ClassLoaderData* ClassLoaderDataGraph::_head = NULL; ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL; ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL; - // Add a new class loader data node to the list. Assign the newly created // ClassLoaderData into the java/lang/ClassLoader object as a hidden field -ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader, TRAPS) { - // Not assigned a class loader data yet. - // Create one. - ClassLoaderData* *list_head = &_head; - ClassLoaderData* next = _head; +ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRAPS) { + // We need to allocate all the oops for the ClassLoaderData before allocating the + // actual ClassLoaderData object. + ClassLoaderData::Dependencies dependencies(CHECK_NULL); - bool is_anonymous = (cld_addr == NULL); - ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous); + No_Safepoint_Verifier no_safepoints; // we mustn't GC until we've installed the + // ClassLoaderData in the graph since the CLD + // contains unhandled oops - if (cld_addr != NULL) { + ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies); + + + if (!is_anonymous) { + ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader()); // First, Atomically set it ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL); if (old != NULL) { @@ -525,6 +531,9 @@ ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle lo // We won the race, and therefore the task of adding the data to the list of // class loader data + ClassLoaderData** list_head = &_head; + ClassLoaderData* next = _head; + do { cld->set_next(next); ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next); @@ -537,10 +546,6 @@ ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle lo cld->loader_name()); tty->print_cr("]"); } - // Create dependencies after the CLD is added to the list. Otherwise, - // the GC GC will not find the CLD and the _class_loader field will - // not be updated. - cld->init_dependencies(CHECK_NULL); return cld; } next = exchanged; @@ -671,6 +676,8 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) { dead->unload(); data = data->next(); // Remove from loader list. + // This class loader data will no longer be found + // in the ClassLoaderDataGraph. if (prev != NULL) { prev->set_next(data); } else { @@ -692,6 +699,7 @@ void ClassLoaderDataGraph::purge() { next = purge_me->next(); delete purge_me; } + Metaspace::purge(); } // CDS support diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index e6315182e18..2a7e43082b2 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -62,7 +62,7 @@ class ClassLoaderDataGraph : public AllStatic { // CMS support. static ClassLoaderData* _saved_head; - static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader, TRAPS); + static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS); public: static ClassLoaderData* find_or_create(Handle class_loader, TRAPS); static void purge(); @@ -100,6 +100,9 @@ class ClassLoaderData : public CHeapObj { Thread* THREAD); public: Dependencies() : _list_head(NULL) {} + Dependencies(TRAPS) : _list_head(NULL) { + init(CHECK); + } void add(Handle dependency, TRAPS); void init(TRAPS); void oops_do(OopClosure* f); @@ -150,7 +153,7 @@ class ClassLoaderData : public CHeapObj { void set_next(ClassLoaderData* next) { _next = next; } ClassLoaderData* next() const { return _next; } - ClassLoaderData(Handle h_class_loader, bool is_anonymous); + ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies); ~ClassLoaderData(); void set_metaspace(Metaspace* m) { _metaspace = m; } @@ -190,7 +193,9 @@ class ClassLoaderData : public CHeapObj { static void init_null_class_loader_data() { assert(_the_null_class_loader_data == NULL, "cannot initialize twice"); assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice"); - _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false); + + // We explicitly initialize the Dependencies object at a later phase in the initialization + _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false, Dependencies()); ClassLoaderDataGraph::_head = _the_null_class_loader_data; assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be"); if (DumpSharedSpaces) { diff --git a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp index b3a5ccf86d1..018b6761c50 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp @@ -43,10 +43,9 @@ inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAP assert(loader() != NULL,"Must be a class loader"); // Gets the class loader data out of the java/lang/ClassLoader object, if non-null // it's already in the loader_data, so no need to add - ClassLoaderData** loader_data_addr = java_lang_ClassLoader::loader_data_addr(loader()); - ClassLoaderData* loader_data_id = *loader_data_addr; - if (loader_data_id) { - return loader_data_id; + ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader()); + if (loader_data) { + return loader_data; } - return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD); + return ClassLoaderDataGraph::add(loader, false, THREAD); } diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 39850490f56..3aa1b77c92a 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -830,7 +830,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla Klass *kk; { MutexLocker mu(SystemDictionary_lock, THREAD); - kk = find_class(name, ik->class_loader_data()); + kk = find_class(d_index, d_hash, name, ik->class_loader_data()); } if (kk != NULL) { // No clean up is needed if the shared class has been entered diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 1e66346eec5..428b2940f61 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -517,13 +517,18 @@ template(sun_management_ManagementFactory, "sun/management/ManagementFactory") \ template(sun_management_Sensor, "sun/management/Sensor") \ template(sun_management_Agent, "sun/management/Agent") \ + template(sun_management_DiagnosticCommandImpl, "sun/management/DiagnosticCommandImpl") \ template(sun_management_GarbageCollectorImpl, "sun/management/GarbageCollectorImpl") \ + template(sun_management_ManagementFactoryHelper, "sun/management/ManagementFactoryHelper") \ + template(getDiagnosticCommandMBean_name, "getDiagnosticCommandMBean") \ + template(getDiagnosticCommandMBean_signature, "()Lcom/sun/management/DiagnosticCommandMBean;") \ template(getGcInfoBuilder_name, "getGcInfoBuilder") \ template(getGcInfoBuilder_signature, "()Lsun/management/GcInfoBuilder;") \ template(com_sun_management_GcInfo, "com/sun/management/GcInfo") \ template(com_sun_management_GcInfo_constructor_signature, "(Lsun/management/GcInfoBuilder;JJJ[Ljava/lang/management/MemoryUsage;[Ljava/lang/management/MemoryUsage;[Ljava/lang/Object;)V") \ template(createGCNotification_name, "createGCNotification") \ template(createGCNotification_signature, "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/sun/management/GcInfo;)V") \ + template(createDiagnosticFrameworkNotification_name, "createDiagnosticFrameworkNotification") \ template(createMemoryPoolMBean_name, "createMemoryPoolMBean") \ template(createMemoryManagerMBean_name, "createMemoryManagerMBean") \ template(createGarbageCollectorMBean_name, "createGarbageCollectorMBean") \ diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 7d2bb575d9f..f7be307b254 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -463,8 +463,10 @@ void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) { } #endif //PRODUCT - -nmethod* CodeCache::find_and_remove_saved_code(Method* m) { +/** + * Remove and return nmethod from the saved code list in order to reanimate it. + */ +nmethod* CodeCache::reanimate_saved_code(Method* m) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); nmethod* saved = _saved_nmethods; nmethod* prev = NULL; @@ -479,7 +481,7 @@ nmethod* CodeCache::find_and_remove_saved_code(Method* m) { saved->set_speculatively_disconnected(false); saved->set_saved_nmethod_link(NULL); if (PrintMethodFlushing) { - saved->print_on(tty, " ### nmethod is reconnected\n"); + saved->print_on(tty, " ### nmethod is reconnected"); } if (LogCompilation && (xtty != NULL)) { ttyLocker ttyl; @@ -496,6 +498,9 @@ nmethod* CodeCache::find_and_remove_saved_code(Method* m) { return NULL; } +/** + * Remove nmethod from the saved code list in order to discard it permanently + */ void CodeCache::remove_saved_code(nmethod* nm) { // For conc swpr this will be called with CodeCache_lock taken by caller assert_locked_or_safepoint(CodeCache_lock); @@ -529,7 +534,7 @@ void CodeCache::speculatively_disconnect(nmethod* nm) { nm->set_saved_nmethod_link(_saved_nmethods); _saved_nmethods = nm; if (PrintMethodFlushing) { - nm->print_on(tty, " ### nmethod is speculatively disconnected\n"); + nm->print_on(tty, " ### nmethod is speculatively disconnected"); } if (LogCompilation && (xtty != NULL)) { ttyLocker ttyl; diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 9bb0b839e14..38799019b8f 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -57,7 +57,7 @@ class CodeCache : AllStatic { static int _number_of_nmethods_with_dependencies; static bool _needs_cache_clean; static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() - static nmethod* _saved_nmethods; // linked via nm->saved_nmethod_look() + static nmethod* _saved_nmethods; // Linked list of speculatively disconnected nmethods. static void verify_if_often() PRODUCT_RETURN; @@ -168,7 +168,7 @@ class CodeCache : AllStatic { static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; } static void clear_inline_caches(); // clear all inline caches - static nmethod* find_and_remove_saved_code(Method* m); + static nmethod* reanimate_saved_code(Method* m); static void remove_saved_code(nmethod* nm); static void speculatively_disconnect(nmethod* nm); diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index 85eeda47056..e9a63b86623 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -45,25 +45,6 @@ // Every time a compiled IC is changed or its type is being accessed, // either the CompiledIC_lock must be set or we must be at a safe point. - -// Release the CompiledICHolder* associated with this call site is there is one. -void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) { - // This call site might have become stale so inspect it carefully. - NativeCall* call = nativeCall_at(call_site->addr()); - if (is_icholder_entry(call->destination())) { - NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value()); - InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data()); - } -} - - -bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { - // This call site might have become stale so inspect it carefully. - NativeCall* call = nativeCall_at(call_site->addr()); - return is_icholder_entry(call->destination()); -} - - //----------------------------------------------------------------------------- // Low-level access to an inline cache. Private, since they might not be // MT-safe to use. @@ -488,33 +469,6 @@ bool CompiledIC::is_icholder_entry(address entry) { return (cb != NULL && cb->is_adapter_blob()); } - -CompiledIC::CompiledIC(nmethod* nm, NativeCall* call) - : _ic_call(call) -{ - address ic_call = call->instruction_address(); - - assert(ic_call != NULL, "ic_call address must be set"); - assert(nm != NULL, "must pass nmethod"); - assert(nm->contains(ic_call), "must be in nmethod"); - - // search for the ic_call at the given address - RelocIterator iter(nm, ic_call, ic_call+1); - bool ret = iter.next(); - assert(ret == true, "relocInfo must exist at this address"); - assert(iter.addr() == ic_call, "must find ic_call"); - if (iter.type() == relocInfo::virtual_call_type) { - virtual_call_Relocation* r = iter.virtual_call_reloc(); - _is_optimized = false; - _value = nativeMovConstReg_at(r->cached_value()); - } else { - assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call"); - _is_optimized = true; - _value = NULL; -} -} - - // ---------------------------------------------------------------------------- void CompiledStaticCall::set_to_clean() { @@ -549,33 +503,6 @@ bool CompiledStaticCall::is_call_to_interpreted() const { return nm->stub_contains(destination()); } - -void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { - address stub=find_stub(); - guarantee(stub != NULL, "stub not found"); - - if (TraceICs) { - ResourceMark rm; - tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - instruction_address(), - callee->name_and_sig_as_C_string()); - } - - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - - assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), "a) MT-unsafe modification of inline cache"); - assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, "b) MT-unsafe modification of inline cache"); - - // Update stub - method_holder->set_data((intptr_t)callee()); - jump->set_jump_destination(entry); - - // Update jump to call - set_destination_mt_safe(stub); -} - - void CompiledStaticCall::set(const StaticCallInfo& info) { assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call"); MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); @@ -618,19 +545,6 @@ void CompiledStaticCall::compute_entry(methodHandle m, StaticCallInfo& info) { } } - -void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { - assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call"); - // Reset stub - address stub = static_stub->addr(); - assert(stub!=NULL, "stub not found"); - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - method_holder->set_data(0); - jump->set_jump_destination((address)-1); -} - - address CompiledStaticCall::find_stub() { // Find reloc. information containing this call-site RelocIterator iter((nmethod*)NULL, instruction_address()); @@ -668,19 +582,16 @@ void CompiledIC::verify() { || is_optimized() || is_megamorphic(), "sanity check"); } - void CompiledIC::print() { print_compiled_ic(); tty->cr(); } - void CompiledIC::print_compiled_ic() { tty->print("Inline cache at " INTPTR_FORMAT ", calling %s " INTPTR_FORMAT " cached_value " INTPTR_FORMAT, instruction_address(), is_call_to_interpreted() ? "interpreted " : "", ic_destination(), is_optimized() ? NULL : cached_value()); } - void CompiledStaticCall::print() { tty->print("static call at " INTPTR_FORMAT " -> ", instruction_address()); if (is_clean()) { @@ -693,21 +604,4 @@ void CompiledStaticCall::print() { tty->cr(); } -void CompiledStaticCall::verify() { - // Verify call - NativeCall::verify(); - if (os::is_MP()) { - verify_alignment(); - } - - // Verify stub - address stub = find_stub(); - assert(stub != NULL, "no stub found for static call"); - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - - // Verify state - assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); -} - -#endif +#endif // !PRODUCT diff --git a/hotspot/src/share/vm/code/compiledIC.hpp b/hotspot/src/share/vm/code/compiledIC.hpp index 79c39742746..96cb0a582bb 100644 --- a/hotspot/src/share/vm/code/compiledIC.hpp +++ b/hotspot/src/share/vm/code/compiledIC.hpp @@ -304,6 +304,11 @@ class CompiledStaticCall: public NativeCall { friend CompiledStaticCall* compiledStaticCall_at(address native_call); friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site); + // Code + static void emit_to_interp_stub(CodeBuffer &cbuf); + static int to_interp_stub_size(); + static int reloc_to_interp_stub(); + // State bool is_clean() const; bool is_call_to_compiled() const; diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 411f02b6771..086bff881cd 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -65,7 +65,7 @@ HS_DTRACE_PROBE_DECL8(hotspot, method__compile__begin, HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t, bool); -#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \ +#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) \ { \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ @@ -77,8 +77,7 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, signature->bytes(), signature->utf8_length()); \ } -#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \ - comp_name, success) \ +#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) \ { \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ @@ -92,7 +91,7 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, #else /* USDT2 */ -#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \ +#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) \ { \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ @@ -104,8 +103,7 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, (char *) signature->bytes(), signature->utf8_length()); \ } -#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \ - comp_name, success) \ +#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) \ { \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ @@ -120,8 +118,8 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, #else // ndef DTRACE_ENABLED -#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) -#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, comp_name, success) +#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) +#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) #endif // ndef DTRACE_ENABLED @@ -1229,7 +1227,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, if (method->is_not_compilable(comp_level)) return NULL; if (UseCodeCacheFlushing) { - nmethod* saved = CodeCache::find_and_remove_saved_code(method()); + nmethod* saved = CodeCache::reanimate_saved_code(method()); if (saved != NULL) { method->set_code(method, saved); return saved; @@ -1288,9 +1286,9 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, method->jmethod_id(); } - // If the compiler is shut off due to code cache flushing or otherwise, + // If the compiler is shut off due to code cache getting full // fail out now so blocking compiles dont hang the java thread - if (!should_compile_new_jobs() || (UseCodeCacheFlushing && CodeCache::needs_flushing())) { + if (!should_compile_new_jobs()) { CompilationPolicy::policy()->delay_compilation(method()); return NULL; } @@ -1766,8 +1764,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { // Save information about this method in case of failure. set_last_compile(thread, method, is_osr, task_level); - DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task_level), method, - compiler_name(task_level)); + DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level)); } // Allocate a new set of JNI handles. @@ -1842,13 +1839,14 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { } } } + // simulate crash during compilation + assert(task->compile_id() != CICrashAt, "just as planned"); } pop_jni_handle_block(); methodHandle method(thread, task->method()); - DTRACE_METHOD_COMPILE_END_PROBE(compiler(task_level), method, - compiler_name(task_level), task->is_success()); + DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success()); collect_statistics(thread, time, task); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 70a26089437..ffb7531caac 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -2444,8 +2444,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { // initial marking in checkpointRootsInitialWork has been completed if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - gclog_or_tty->print("Verify before initial mark: "); - Universe::verify(); + Universe::verify("Verify before initial mark: "); } { bool res = markFromRoots(false); @@ -2456,8 +2455,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { case FinalMarking: if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - gclog_or_tty->print("Verify before re-mark: "); - Universe::verify(); + Universe::verify("Verify before re-mark: "); } checkpointRootsFinal(false, clear_all_soft_refs, init_mark_was_synchronous); @@ -2468,8 +2466,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { // final marking in checkpointRootsFinal has been completed if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - gclog_or_tty->print("Verify before sweep: "); - Universe::verify(); + Universe::verify("Verify before sweep: "); } sweep(false); assert(_collectorState == Resizing, "Incorrect state"); @@ -2484,8 +2481,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { // The heap has been resized. if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - gclog_or_tty->print("Verify before reset: "); - Universe::verify(); + Universe::verify("Verify before reset: "); } reset(false); assert(_collectorState == Idling, "Collector state should " @@ -2853,8 +2849,8 @@ class VerifyMarkedClosure: public BitMapClosure { bool failed() { return _failed; } }; -bool CMSCollector::verify_after_remark() { - gclog_or_tty->print(" [Verifying CMS Marking... "); +bool CMSCollector::verify_after_remark(bool silent) { + if (!silent) gclog_or_tty->print(" [Verifying CMS Marking... "); MutexLockerEx ml(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag); static bool init = false; @@ -2915,7 +2911,7 @@ bool CMSCollector::verify_after_remark() { warning("Unrecognized value %d for CMSRemarkVerifyVariant", CMSRemarkVerifyVariant); } - gclog_or_tty->print(" done] "); + if (!silent) gclog_or_tty->print(" done] "); return true; } @@ -3426,8 +3422,9 @@ bool ConcurrentMarkSweepGeneration::grow_to_reserved() { void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) { assert_locked_or_safepoint(Heap_lock); assert_lock_strong(freelistLock()); - // XXX Fix when compaction is implemented. - warning("Shrinking of CMS not yet implemented"); + if (PrintGCDetails && Verbose) { + warning("Shrinking of CMS not yet implemented"); + } return; } @@ -6010,26 +6007,23 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) { &cmsDrainMarkingStackClosure, NULL); } - verify_work_stacks_empty(); } + // This is the point where the entire marking should have completed. + verify_work_stacks_empty(); + if (should_unload_classes()) { { TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty); - // Follow SystemDictionary roots and unload classes + // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); - // Follow CodeCache roots and unload any methods marked for unloading + // Unload nmethods. CodeCache::do_unloading(&_is_alive_closure, purged_class); - cmsDrainMarkingStackClosure.do_void(); - verify_work_stacks_empty(); - - // Update subklass/sibling/implementor links in KlassKlass descendants + // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(&_is_alive_closure); - // Nothing should have been pushed onto the working stacks. - verify_work_stacks_empty(); } { @@ -6043,11 +6037,10 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) { // Need to check if we really scanned the StringTable. if ((roots_scanning_options() & SharedHeap::SO_Strings) == 0) { TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty); - // Now clean up stale oops in StringTable + // Delete entries for dead interned strings. StringTable::unlink(&_is_alive_closure); } - verify_work_stacks_empty(); // Restore any preserved marks as a result of mark stack or // work queue overflow restore_preserved_marks_if_any(); // done single-threaded for now diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index aa84d716670..7040f218eb0 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -990,7 +990,7 @@ class CMSCollector: public CHeapObj { // debugging void verify(); - bool verify_after_remark(); + bool verify_after_remark(bool silent = VerifySilently); void verify_ok_to_terminate() const PRODUCT_RETURN; void verify_work_stacks_empty() const PRODUCT_RETURN; void verify_overflow_empty() const PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 03086a3bfb6..39e5a2792b5 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1273,10 +1273,9 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (VerifyDuringGC) { HandleMark hm; // handle scope - gclog_or_tty->print(" VerifyDuringGC:(before)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(VerifyOption_G1UsePrevMarking, + " VerifyDuringGC:(before)"); } G1CollectorPolicy* g1p = g1h->g1_policy(); @@ -1300,10 +1299,9 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { // Verify the heap w.r.t. the previous marking bitmap. if (VerifyDuringGC) { HandleMark hm; // handle scope - gclog_or_tty->print(" VerifyDuringGC:(overflow)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(VerifyOption_G1UsePrevMarking, + " VerifyDuringGC:(overflow)"); } // Clear the marking state because we will be restarting @@ -1323,10 +1321,9 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (VerifyDuringGC) { HandleMark hm; // handle scope - gclog_or_tty->print(" VerifyDuringGC:(after)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UseNextMarking); + Universe::verify(VerifyOption_G1UseNextMarking, + " VerifyDuringGC:(after)"); } assert(!restart_for_overflow(), "sanity"); // Completely reset the marking state since marking completed @@ -1972,10 +1969,9 @@ void ConcurrentMark::cleanup() { if (VerifyDuringGC) { HandleMark hm; // handle scope - gclog_or_tty->print(" VerifyDuringGC:(before)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(VerifyOption_G1UsePrevMarking, + " VerifyDuringGC:(before)"); } G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); @@ -2127,10 +2123,9 @@ void ConcurrentMark::cleanup() { if (VerifyDuringGC) { HandleMark hm; // handle scope - gclog_or_tty->print(" VerifyDuringGC:(after)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(VerifyOption_G1UsePrevMarking, + " VerifyDuringGC:(after)"); } g1h->verify_region_sets_optional(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 4eea2a48cd5..76ce145ebed 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1271,9 +1271,8 @@ double G1CollectedHeap::verify(bool guard, const char* msg) { if (guard && total_collections() >= VerifyGCStartAt) { double verify_start = os::elapsedTime(); HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(msg); prepare_for_verify(); - Universe::verify(false /* silent */, VerifyOption_G1UsePrevMarking); + Universe::verify(VerifyOption_G1UsePrevMarking, msg); verify_time_ms = (os::elapsedTime() - verify_start) * 1000; } @@ -1304,7 +1303,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, print_heap_before_gc(); - size_t metadata_prev_used = MetaspaceAux::used_in_bytes(); + size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes(); HRSPhaseSetter x(HRSPhaseFullGC); verify_region_sets_optional(); @@ -1425,6 +1424,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, // Delete metaspaces for unloaded class loaders and clean up loader_data graph ClassLoaderDataGraph::purge(); + MetaspaceAux::verify_metrics(); // Note: since we've just done a full GC, concurrent // marking is no longer active. Therefore we need not @@ -1955,13 +1955,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : int n_rem_sets = HeapRegionRemSet::num_par_rem_sets(); assert(n_rem_sets > 0, "Invariant."); - HeapRegionRemSetIterator** iter_arr = - NEW_C_HEAP_ARRAY(HeapRegionRemSetIterator*, n_queues, mtGC); - for (int i = 0; i < n_queues; i++) { - iter_arr[i] = new HeapRegionRemSetIterator(); - } - _rem_set_iterator = iter_arr; - _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC); _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC); @@ -5079,10 +5072,9 @@ g1_process_strong_roots(bool is_scavenging, } void -G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure, - OopClosure* non_root_closure) { +G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure) { CodeBlobToOopClosure roots_in_blobs(root_closure, /*do_marking=*/ false); - SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure); + SharedHeap::process_weak_roots(root_closure, &roots_in_blobs); } // Weak Reference Processing support diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 4fbf0ff367a..32f5a46b471 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -786,9 +786,6 @@ protected: // concurrently after the collection. DirtyCardQueueSet _dirty_card_queue_set; - // The Heap Region Rem Set Iterator. - HeapRegionRemSetIterator** _rem_set_iterator; - // The closure used to refine a single card. RefineCardTableEntryClosure* _refine_cte_cl; @@ -827,8 +824,7 @@ protected: // Apply "blk" to all the weak roots of the system. These include // JNI weak roots, the code cache, system dictionary, symbol table, // string table, and referents of reachable weak refs. - void g1_process_weak_roots(OopClosure* root_closure, - OopClosure* non_root_closure); + void g1_process_weak_roots(OopClosure* root_closure); // Frees a non-humongous region by initializing its contents and // adding it to the free list that's passed as a parameter (this is @@ -1114,15 +1110,6 @@ public: G1RemSet* g1_rem_set() const { return _g1_rem_set; } ModRefBarrierSet* mr_bs() const { return _mr_bs; } - // The rem set iterator. - HeapRegionRemSetIterator* rem_set_iterator(int i) { - return _rem_set_iterator[i]; - } - - HeapRegionRemSetIterator* rem_set_iterator() { - return _rem_set_iterator[0]; - } - unsigned get_gc_time_stamp() { return _gc_time_stamp; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index b987f7df4e7..d87a6cca135 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp @@ -144,33 +144,28 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, &GenMarkSweep::follow_stack_closure, NULL); - // Follow system dictionary roots and unload classes + + // This is the point where the entire marking should have completed. + assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed"); + + // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive); - assert(GenMarkSweep::_marking_stack.is_empty(), - "stack should be empty by now"); - // Follow code cache roots (has to be done after system dictionary, - // assumes all live klasses are marked) + // Unload nmethods. CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class); - GenMarkSweep::follow_stack(); - // Update subklass/sibling/implementor links of live klasses + // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); - assert(GenMarkSweep::_marking_stack.is_empty(), - "stack should be empty by now"); - // Visit interned string tables and delete unmarked oops + // Delete entries for dead interned strings. StringTable::unlink(&GenMarkSweep::is_alive); + // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); - assert(GenMarkSweep::_marking_stack.is_empty(), - "stack should be empty by now"); - if (VerifyDuringGC) { HandleMark hm; // handle scope COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact); - gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying "); Universe::heap()->prepare_for_verify(); // Note: we can verify only the heap here. When an object is // marked, the previous value of the mark word (including @@ -182,11 +177,13 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, // fail. At the end of the GC, the orginal mark word values // (including hash values) are restored to the appropriate // objects. - Universe::heap()->verify(/* silent */ false, - /* option */ VerifyOption_G1UseMarkWord); - - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - gclog_or_tty->print_cr("]"); + if (!VerifySilently) { + gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying "); + } + Universe::heap()->verify(VerifySilently, VerifyOption_G1UseMarkWord); + if (!VerifySilently) { + gclog_or_tty->print_cr("]"); + } } } @@ -308,17 +305,16 @@ void G1MarkSweep::mark_sweep_phase3() { sh->process_strong_roots(true, // activate StrongRootsScope false, // not scavenging. SharedHeap::SO_AllClasses, - &GenMarkSweep::adjust_root_pointer_closure, + &GenMarkSweep::adjust_pointer_closure, NULL, // do not touch code cache here &GenMarkSweep::adjust_klass_closure); assert(GenMarkSweep::ref_processor() == g1h->ref_processor_stw(), "Sanity"); - g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_root_pointer_closure); + g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_pointer_closure); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) - g1h->g1_process_weak_roots(&GenMarkSweep::adjust_root_pointer_closure, - &GenMarkSweep::adjust_pointer_closure); + g1h->g1_process_weak_roots(&GenMarkSweep::adjust_pointer_closure); GenMarkSweep::adjust_marks(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 04af52e9478..e7151071e9f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -169,14 +169,13 @@ public: // _try_claimed || r->claim_iter() // is true: either we're supposed to work on claimed-but-not-complete // regions, or we successfully claimed the region. - HeapRegionRemSetIterator* iter = _g1h->rem_set_iterator(_worker_i); - hrrs->init_iterator(iter); + HeapRegionRemSetIterator iter(hrrs); size_t card_index; // We claim cards in block so as to recude the contention. The block size is determined by // the G1RSetScanBlockSize parameter. size_t jump_to_card = hrrs->iter_claimed_next(_block_size); - for (size_t current_card = 0; iter->has_next(card_index); current_card++) { + for (size_t current_card = 0; iter.has_next(card_index); current_card++) { if (current_card >= jump_to_card + _block_size) { jump_to_card = hrrs->iter_claimed_next(_block_size); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp index 0468e9ac312..eee6b447087 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -53,14 +53,14 @@ protected: NumSeqTasks = 1 }; - CardTableModRefBS* _ct_bs; - SubTasksDone* _seq_task; - G1CollectorPolicy* _g1p; + CardTableModRefBS* _ct_bs; + SubTasksDone* _seq_task; + G1CollectorPolicy* _g1p; - ConcurrentG1Refine* _cg1r; + ConcurrentG1Refine* _cg1r; - size_t* _cards_scanned; - size_t _total_cards_scanned; + size_t* _cards_scanned; + size_t _total_cards_scanned; // Used for caching the closure that is responsible for scanning // references into the collection set. diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index aeaeea39866..1e005a26ecd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -877,14 +877,9 @@ bool HeapRegionRemSet::iter_is_complete() { return _iter_state == Complete; } -void HeapRegionRemSet::init_iterator(HeapRegionRemSetIterator* iter) const { - iter->initialize(this); -} - #ifndef PRODUCT void HeapRegionRemSet::print() const { - HeapRegionRemSetIterator iter; - init_iterator(&iter); + HeapRegionRemSetIterator iter(this); size_t card_index; while (iter.has_next(card_index)) { HeapWord* card_start = @@ -928,35 +923,23 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, //-------------------- Iteration -------------------- -HeapRegionRemSetIterator:: -HeapRegionRemSetIterator() : - _hrrs(NULL), +HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) : + _hrrs(hrrs), _g1h(G1CollectedHeap::heap()), - _bosa(NULL), - _sparse_iter() { } - -void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) { - _hrrs = hrrs; - _coarse_map = &_hrrs->_other_regions._coarse_map; - _fine_grain_regions = _hrrs->_other_regions._fine_grain_regions; - _bosa = _hrrs->bosa(); - - _is = Sparse; + _coarse_map(&hrrs->_other_regions._coarse_map), + _fine_grain_regions(hrrs->_other_regions._fine_grain_regions), + _bosa(hrrs->bosa()), + _is(Sparse), // Set these values so that we increment to the first region. - _coarse_cur_region_index = -1; - _coarse_cur_region_cur_card = (HeapRegion::CardsPerRegion-1); - - _cur_region_cur_card = 0; - - _fine_array_index = -1; - _fine_cur_prt = NULL; - - _n_yielded_coarse = 0; - _n_yielded_fine = 0; - _n_yielded_sparse = 0; - - _sparse_iter.init(&hrrs->_other_regions._sparse_table); -} + _coarse_cur_region_index(-1), + _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1), + _cur_region_cur_card(0), + _fine_array_index(-1), + _fine_cur_prt(NULL), + _n_yielded_coarse(0), + _n_yielded_fine(0), + _n_yielded_sparse(0), + _sparse_iter(&hrrs->_other_regions._sparse_table) {} bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) { if (_hrrs->_other_regions._n_coarse_entries == 0) return false; @@ -1209,8 +1192,7 @@ void HeapRegionRemSet::test() { hrrs->add_reference((OopOrNarrowOopStar)hr5->bottom()); // Now, does iteration yield these three? - HeapRegionRemSetIterator iter; - hrrs->init_iterator(&iter); + HeapRegionRemSetIterator iter(hrrs); size_t sum = 0; size_t card_index; while (iter.has_next(card_index)) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 1b1d42d7a35..2e165074e10 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -281,9 +281,6 @@ public: return (_iter_state == Unclaimed) && (_iter_claimed == 0); } - // Initialize the given iterator to iterate over this rem set. - void init_iterator(HeapRegionRemSetIterator* iter) const; - // The actual # of bytes this hr_remset takes up. size_t mem_size() { return _other_regions.mem_size() @@ -345,9 +342,9 @@ public: #endif }; -class HeapRegionRemSetIterator : public CHeapObj { +class HeapRegionRemSetIterator : public StackObj { - // The region over which we're iterating. + // The region RSet over which we're iterating. const HeapRegionRemSet* _hrrs; // Local caching of HRRS fields. @@ -362,8 +359,10 @@ class HeapRegionRemSetIterator : public CHeapObj { size_t _n_yielded_coarse; size_t _n_yielded_sparse; - // If true we're iterating over the coarse table; if false the fine - // table. + // Indicates what granularity of table that we're currently iterating over. + // We start iterating over the sparse table, progress to the fine grain + // table, and then finish with the coarse table. + // See HeapRegionRemSetIterator::has_next(). enum IterState { Sparse, Fine, @@ -403,9 +402,7 @@ class HeapRegionRemSetIterator : public CHeapObj { public: // We require an iterator to be initialized before use, so the // constructor does little. - HeapRegionRemSetIterator(); - - void initialize(const HeapRegionRemSet* hrrs); + HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs); // If there remains one or more cards to be yielded, returns true and // sets "card_index" to one of those cards (which is then considered diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp index 0daa63512a3..a08e8a9801e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp @@ -35,10 +35,6 @@ #define UNROLL_CARD_LOOPS 1 -void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) { - sprt_iter->init(this); -} - void SparsePRTEntry::init(RegionIdx_t region_ind) { _region_ind = region_ind; _next_index = NullEntry; diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp index ab0ab1f0205..6e821f73bbc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp @@ -192,18 +192,11 @@ class RSHashTableIter VALUE_OBJ_CLASS_SPEC { size_t compute_card_ind(CardIdx_t ci); public: - RSHashTableIter() : - _tbl_ind(RSHashTable::NullEntry), + RSHashTableIter(RSHashTable* rsht) : + _tbl_ind(RSHashTable::NullEntry), // So that first increment gets to 0. _bl_ind(RSHashTable::NullEntry), _card_ind((SparsePRTEntry::cards_num() - 1)), - _rsht(NULL) {} - - void init(RSHashTable* rsht) { - _rsht = rsht; - _tbl_ind = -1; // So that first increment gets to 0. - _bl_ind = RSHashTable::NullEntry; - _card_ind = (SparsePRTEntry::cards_num() - 1); - } + _rsht(rsht) {} bool has_next(size_t& card_index); }; @@ -284,8 +277,6 @@ public: static void cleanup_all(); RSHashTable* cur() const { return _cur; } - void init_iterator(SparsePRTIter* sprt_iter); - static void add_to_expanded_list(SparsePRT* sprt); static SparsePRT* get_from_expanded_list(); @@ -321,9 +312,9 @@ public: class SparsePRTIter: public RSHashTableIter { public: - void init(const SparsePRT* sprt) { - RSHashTableIter::init(sprt->cur()); - } + SparsePRTIter(const SparsePRT* sprt) : + RSHashTableIter(sprt->cur()) {} + bool has_next(size_t& card_index) { return RSHashTableIter::has_next(card_index); } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp index 63cd3760282..adbaee43fc3 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp @@ -138,8 +138,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(); + Universe::verify(" VerifyBeforeGC:"); } // Verify object start arrays @@ -177,7 +176,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { size_t prev_used = heap->used(); // Capture metadata size before collection for sizing. - size_t metadata_prev_used = MetaspaceAux::used_in_bytes(); + size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes(); // For PrintGCDetails size_t old_gen_prev_used = old_gen->used_in_bytes(); @@ -238,6 +237,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { // Delete metaspaces for unloaded class loaders and clean up loader_data graph ClassLoaderDataGraph::purge(); + MetaspaceAux::verify_metrics(); BiasedLocking::restore_marks(); Threads::gc_epilogue(); @@ -340,8 +340,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(); + Universe::verify(" VerifyAfterGC:"); } // Re-verify object start arrays @@ -518,23 +517,23 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL); } - // Follow system dictionary roots and unload classes + // This is the point where the entire marking should have completed. + assert(_marking_stack.is_empty(), "Marking should have completed"); + + // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); - // Follow code cache roots + // Unload nmethods. CodeCache::do_unloading(is_alive_closure(), purged_class); - follow_stack(); // Flush marking stack - // Update subklass/sibling/implementor links of live klasses - Klass::clean_weak_klass_links(&is_alive); - assert(_marking_stack.is_empty(), "just drained"); + // Prune dead klasses from subklass/sibling/implementor lists. + Klass::clean_weak_klass_links(is_alive_closure()); - // Visit interned string tables and delete unmarked oops + // Delete entries for dead interned strings. StringTable::unlink(is_alive_closure()); + // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); - - assert(_marking_stack.is_empty(), "stack should be empty by now"); } @@ -583,28 +582,27 @@ void PSMarkSweep::mark_sweep_phase3() { ClassLoaderDataGraph::clear_claimed_marks(); // General strong roots. - Universe::oops_do(adjust_root_pointer_closure()); - JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles - CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure()); - Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL); - ObjectSynchronizer::oops_do(adjust_root_pointer_closure()); - FlatProfiler::oops_do(adjust_root_pointer_closure()); - Management::oops_do(adjust_root_pointer_closure()); - JvmtiExport::oops_do(adjust_root_pointer_closure()); + Universe::oops_do(adjust_pointer_closure()); + JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles + CLDToOopClosure adjust_from_cld(adjust_pointer_closure()); + Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL); + ObjectSynchronizer::oops_do(adjust_pointer_closure()); + FlatProfiler::oops_do(adjust_pointer_closure()); + Management::oops_do(adjust_pointer_closure()); + JvmtiExport::oops_do(adjust_pointer_closure()); // SO_AllClasses - SystemDictionary::oops_do(adjust_root_pointer_closure()); - ClassLoaderDataGraph::oops_do(adjust_root_pointer_closure(), adjust_klass_closure(), true); - //CodeCache::scavenge_root_nmethods_oops_do(adjust_root_pointer_closure()); + SystemDictionary::oops_do(adjust_pointer_closure()); + ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) // Global (weak) JNI handles - JNIHandles::weak_oops_do(&always_true, adjust_root_pointer_closure()); + JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure()); CodeCache::oops_do(adjust_pointer_closure()); - StringTable::oops_do(adjust_root_pointer_closure()); - ref_processor()->weak_oops_do(adjust_root_pointer_closure()); - PSScavenge::reference_processor()->weak_oops_do(adjust_root_pointer_closure()); + StringTable::oops_do(adjust_pointer_closure()); + ref_processor()->weak_oops_do(adjust_pointer_closure()); + PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure()); adjust_marks(); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp index fcbc103dc3a..7d96afbb4df 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp @@ -44,7 +44,6 @@ class PSMarkSweep : public MarkSweep { static KlassClosure* follow_klass_closure() { return &MarkSweep::follow_klass_closure; } static VoidClosure* follow_stack_closure() { return (VoidClosure*)&MarkSweep::follow_stack_closure; } static OopClosure* adjust_pointer_closure() { return (OopClosure*)&MarkSweep::adjust_pointer_closure; } - static OopClosure* adjust_root_pointer_closure() { return (OopClosure*)&MarkSweep::adjust_root_pointer_closure; } static KlassClosure* adjust_klass_closure() { return &MarkSweep::adjust_klass_closure; } static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&MarkSweep::is_alive; } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index 487a4e56553..b03107a97cd 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -787,12 +787,11 @@ bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap( void PSParallelCompact::KeepAliveClosure::do_oop(oop* p) { PSParallelCompact::KeepAliveClosure::do_oop_work(p); } void PSParallelCompact::KeepAliveClosure::do_oop(narrowOop* p) { PSParallelCompact::KeepAliveClosure::do_oop_work(p); } -PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_root_pointer_closure(true); -PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure(false); +PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure; PSParallelCompact::AdjustKlassClosure PSParallelCompact::_adjust_klass_closure; -void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p, _is_root); } -void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); } +void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); } +void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); } void PSParallelCompact::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); } @@ -805,7 +804,7 @@ void PSParallelCompact::FollowKlassClosure::do_klass(Klass* klass) { klass->oops_do(_mark_and_push_closure); } void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) { - klass->oops_do(&PSParallelCompact::_adjust_root_pointer_closure); + klass->oops_do(&PSParallelCompact::_adjust_pointer_closure); } void PSParallelCompact::post_initialize() { @@ -892,7 +891,7 @@ public: _heap_used = heap->used(); _young_gen_used = heap->young_gen()->used_in_bytes(); _old_gen_used = heap->old_gen()->used_in_bytes(); - _metadata_used = MetaspaceAux::used_in_bytes(); + _metadata_used = MetaspaceAux::allocated_used_bytes(); }; size_t heap_used() const { return _heap_used; } @@ -967,8 +966,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(); + Universe::verify(" VerifyBeforeGC:"); } // Verify object start arrays @@ -1027,6 +1025,7 @@ void PSParallelCompact::post_compact() // Delete metaspaces for unloaded class loaders and clean up loader_data graph ClassLoaderDataGraph::purge(); + MetaspaceAux::verify_metrics(); Threads::gc_epilogue(); CodeCache::gc_epilogue(); @@ -2168,8 +2167,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(); + Universe::verify(" VerifyAfterGC:"); } // Re-verify object start arrays @@ -2356,22 +2354,24 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, } TraceTime tm_c("class unloading", print_phases(), true, gclog_or_tty); + + // This is the point where the entire marking should have completed. + assert(cm->marking_stacks_empty(), "Marking should have completed"); + // Follow system dictionary roots and unload classes. bool purged_class = SystemDictionary::do_unloading(is_alive_closure()); - // Follow code cache roots. + // Unload nmethods. CodeCache::do_unloading(is_alive_closure(), purged_class); - cm->follow_marking_stacks(); // Flush marking stack. - // Update subklass/sibling/implementor links of live klasses + // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(is_alive_closure()); - // Visit interned string tables and delete unmarked oops + // Delete entries for dead interned strings. StringTable::unlink(is_alive_closure()); + // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); - - assert(cm->marking_stacks_empty(), "marking stacks should be empty"); } void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) { @@ -2398,7 +2398,7 @@ void PSParallelCompact::follow_class_loader(ParCompactionManager* cm, void PSParallelCompact::adjust_class_loader(ParCompactionManager* cm, ClassLoaderData* cld) { - cld->oops_do(PSParallelCompact::adjust_root_pointer_closure(), + cld->oops_do(PSParallelCompact::adjust_pointer_closure(), PSParallelCompact::adjust_klass_closure(), true); } @@ -2419,32 +2419,31 @@ void PSParallelCompact::adjust_roots() { ClassLoaderDataGraph::clear_claimed_marks(); // General strong roots. - Universe::oops_do(adjust_root_pointer_closure()); - JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles - CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure()); - Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL); - ObjectSynchronizer::oops_do(adjust_root_pointer_closure()); - FlatProfiler::oops_do(adjust_root_pointer_closure()); - Management::oops_do(adjust_root_pointer_closure()); - JvmtiExport::oops_do(adjust_root_pointer_closure()); + Universe::oops_do(adjust_pointer_closure()); + JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles + CLDToOopClosure adjust_from_cld(adjust_pointer_closure()); + Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL); + ObjectSynchronizer::oops_do(adjust_pointer_closure()); + FlatProfiler::oops_do(adjust_pointer_closure()); + Management::oops_do(adjust_pointer_closure()); + JvmtiExport::oops_do(adjust_pointer_closure()); // SO_AllClasses - SystemDictionary::oops_do(adjust_root_pointer_closure()); - ClassLoaderDataGraph::oops_do(adjust_root_pointer_closure(), adjust_klass_closure(), true); + SystemDictionary::oops_do(adjust_pointer_closure()); + ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) // Global (weak) JNI handles - JNIHandles::weak_oops_do(&always_true, adjust_root_pointer_closure()); + JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure()); CodeCache::oops_do(adjust_pointer_closure()); - StringTable::oops_do(adjust_root_pointer_closure()); - ref_processor()->weak_oops_do(adjust_root_pointer_closure()); + StringTable::oops_do(adjust_pointer_closure()); + ref_processor()->weak_oops_do(adjust_pointer_closure()); // Roots were visited so references into the young gen in roots // may have been scanned. Process them also. // Should the reference processor have a span that excludes // young gen objects? - PSScavenge::reference_processor()->weak_oops_do( - adjust_root_pointer_closure()); + PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure()); } void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp index 68b54fb9b13..6ced655c21a 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp @@ -799,16 +799,6 @@ class PSParallelCompact : AllStatic { virtual void do_oop(narrowOop* p); }; - // Current unused - class FollowRootClosure: public OopsInGenClosure { - private: - ParCompactionManager* _compaction_manager; - public: - FollowRootClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } - virtual void do_oop(oop* p); - virtual void do_oop(narrowOop* p); - }; - class FollowStackClosure: public VoidClosure { private: ParCompactionManager* _compaction_manager; @@ -818,10 +808,7 @@ class PSParallelCompact : AllStatic { }; class AdjustPointerClosure: public OopClosure { - private: - bool _is_root; public: - AdjustPointerClosure(bool is_root) : _is_root(is_root) { } virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); // do not walk from thread stacks to the code cache on this phase @@ -838,7 +825,6 @@ class PSParallelCompact : AllStatic { friend class AdjustPointerClosure; friend class AdjustKlassClosure; friend class FollowKlassClosure; - friend class FollowRootClosure; friend class InstanceClassLoaderKlass; friend class RefProcTaskProxy; @@ -853,7 +839,6 @@ class PSParallelCompact : AllStatic { static IsAliveClosure _is_alive_closure; static SpaceInfo _space_info[last_space_id]; static bool _print_phases; - static AdjustPointerClosure _adjust_root_pointer_closure; static AdjustPointerClosure _adjust_pointer_closure; static AdjustKlassClosure _adjust_klass_closure; @@ -889,9 +874,6 @@ class PSParallelCompact : AllStatic { static void marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction); - template static inline void adjust_pointer(T* p, bool is_root); - static void adjust_root_pointer(oop* p) { adjust_pointer(p, true); } - template static inline void follow_root(ParCompactionManager* cm, T* p); @@ -1046,7 +1028,6 @@ class PSParallelCompact : AllStatic { // Closure accessors static OopClosure* adjust_pointer_closure() { return (OopClosure*)&_adjust_pointer_closure; } - static OopClosure* adjust_root_pointer_closure() { return (OopClosure*)&_adjust_root_pointer_closure; } static KlassClosure* adjust_klass_closure() { return (KlassClosure*)&_adjust_klass_closure; } static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&_is_alive_closure; } @@ -1067,6 +1048,7 @@ class PSParallelCompact : AllStatic { // Check mark and maybe push on marking stack template static inline void mark_and_push(ParCompactionManager* cm, T* p); + template static inline void adjust_pointer(T* p); static void follow_klass(ParCompactionManager* cm, Klass* klass); static void adjust_klass(ParCompactionManager* cm, Klass* klass); @@ -1151,9 +1133,6 @@ class PSParallelCompact : AllStatic { static ParMarkBitMap* mark_bitmap() { return &_mark_bitmap; } static ParallelCompactData& summary_data() { return _summary_data; } - static inline void adjust_pointer(oop* p) { adjust_pointer(p, false); } - static inline void adjust_pointer(narrowOop* p) { adjust_pointer(p, false); } - // Reference Processing static ReferenceProcessor* const ref_processor() { return _ref_processor; } @@ -1230,7 +1209,7 @@ inline void PSParallelCompact::mark_and_push(ParCompactionManager* cm, T* p) { } template -inline void PSParallelCompact::adjust_pointer(T* p, bool isroot) { +inline void PSParallelCompact::adjust_pointer(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index 078bd62aff7..4bc7870b98a 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -314,8 +314,7 @@ bool PSScavenge::invoke_no_policy() { if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(); + Universe::verify(" VerifyBeforeGC:"); } { @@ -638,8 +637,7 @@ bool PSScavenge::invoke_no_policy() { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(); + Universe::verify(" VerifyAfterGC:"); } heap->print_heap_after_gc(); diff --git a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp index 6ea4097daa9..5e52aa1eb84 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp @@ -81,7 +81,7 @@ void MarkSweep::follow_class_loader(ClassLoaderData* cld) { } void MarkSweep::adjust_class_loader(ClassLoaderData* cld) { - cld->oops_do(&MarkSweep::adjust_root_pointer_closure, &MarkSweep::adjust_klass_closure, true); + cld->oops_do(&MarkSweep::adjust_pointer_closure, &MarkSweep::adjust_klass_closure, true); } @@ -121,11 +121,10 @@ void MarkSweep::preserve_mark(oop obj, markOop mark) { } } -MarkSweep::AdjustPointerClosure MarkSweep::adjust_root_pointer_closure(true); -MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure(false); +MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure; -void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p, _is_root); } -void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); } +void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); } +void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); } void MarkSweep::adjust_marks() { assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(), diff --git a/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp b/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp index 1de7561ce55..ec724afa5ec 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp @@ -80,10 +80,7 @@ class MarkSweep : AllStatic { }; class AdjustPointerClosure: public OopsInGenClosure { - private: - bool _is_root; public: - AdjustPointerClosure(bool is_root) : _is_root(is_root) {} virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); }; @@ -146,7 +143,6 @@ class MarkSweep : AllStatic { static MarkAndPushClosure mark_and_push_closure; static FollowKlassClosure follow_klass_closure; static FollowStackClosure follow_stack_closure; - static AdjustPointerClosure adjust_root_pointer_closure; static AdjustPointerClosure adjust_pointer_closure; static AdjustKlassClosure adjust_klass_closure; @@ -179,12 +175,7 @@ class MarkSweep : AllStatic { static void adjust_marks(); // Adjust the pointers in the preserved marks table static void restore_marks(); // Restore the marks that we saved in preserve_mark - template static inline void adjust_pointer(T* p, bool isroot); - - static void adjust_root_pointer(oop* p) { adjust_pointer(p, true); } - static void adjust_pointer(oop* p) { adjust_pointer(p, false); } - static void adjust_pointer(narrowOop* p) { adjust_pointer(p, false); } - + template static inline void adjust_pointer(T* p); }; class PreservedMark VALUE_OBJ_CLASS_SPEC { diff --git a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp index 9752291959a..8ffe0f78236 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp @@ -76,7 +76,7 @@ void MarkSweep::push_objarray(oop obj, size_t index) { _objarray_stack.push(task); } -template inline void MarkSweep::adjust_pointer(T* p, bool isroot) { +template inline void MarkSweep::adjust_pointer(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index 756ed28f010..211a084ab38 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp @@ -225,7 +225,10 @@ void VM_CollectForMetadataAllocation::doit() { gclog_or_tty->print_cr("\nCMS full GC for Metaspace"); } heap->collect_as_vm_thread(GCCause::_metadata_GC_threshold); - _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype); + // After a GC try to allocate without expanding. Could fail + // and expansion will be tried below. + _result = + _loader_data->metaspace_non_null()->allocate(_size, _mdtype); } if (_result == NULL && !UseConcMarkSweepGC /* CMS already tried */) { // If still failing, allow the Metaspace to expand. diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 133685932fd..dbc0c87edce 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -238,8 +238,8 @@ void FileMapInfo::write_header() { void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) { align_file_position(); - size_t used = space->used_words(Metaspace::NonClassType) * BytesPerWord; - size_t capacity = space->capacity_words(Metaspace::NonClassType) * BytesPerWord; + size_t used = space->used_bytes_slow(Metaspace::NonClassType); + size_t capacity = space->capacity_bytes_slow(Metaspace::NonClassType); struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i]; write_region(i, (char*)space->bottom(), used, capacity, read_only, false); } diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index f39631ae00b..8c2eb34d262 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -377,7 +377,7 @@ void GenCollectedHeap::do_collection(bool full, ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy()); - const size_t metadata_prev_used = MetaspaceAux::used_in_bytes(); + const size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes(); print_heap_before_gc(); @@ -447,8 +447,7 @@ void GenCollectedHeap::do_collection(bool full, prepare_for_verify(); prepared_for_verification = true; } - gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(); + Universe::verify(" VerifyBeforeGC:"); } COMPILER2_PRESENT(DerivedPointerTable::clear()); @@ -519,8 +518,7 @@ void GenCollectedHeap::do_collection(bool full, if (VerifyAfterGC && i >= VerifyGCLevel && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(); + Universe::verify(" VerifyAfterGC:"); } if (PrintGCDetails) { @@ -556,6 +554,7 @@ void GenCollectedHeap::do_collection(bool full, if (complete) { // Delete metaspaces for unloaded class loaders and clean up loader_data graph ClassLoaderDataGraph::purge(); + MetaspaceAux::verify_metrics(); // Resize the metaspace capacity after full collections MetaspaceGC::compute_new_size(); update_full_collections_completed(); @@ -633,9 +632,8 @@ gen_process_strong_roots(int level, } void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure, - CodeBlobClosure* code_roots, - OopClosure* non_root_closure) { - SharedHeap::process_weak_roots(root_closure, code_roots, non_root_closure); + CodeBlobClosure* code_roots) { + SharedHeap::process_weak_roots(root_closure, code_roots); // "Local" "weak" refs for (int i = 0; i < _n_gens; i++) { _gens[i]->ref_processor()->weak_oops_do(root_closure); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index 034511b9b55..783cd372d7c 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -432,8 +432,7 @@ public: // JNI weak roots, the code cache, system dictionary, symbol table, // string table, and referents of reachable weak refs. void gen_process_weak_roots(OopClosure* root_closure, - CodeBlobClosure* code_roots, - OopClosure* non_root_closure); + CodeBlobClosure* code_roots); // Set the saved marks of generations, if that makes sense. // In particular, if any generation might iterate over the oops diff --git a/hotspot/src/share/vm/memory/genMarkSweep.cpp b/hotspot/src/share/vm/memory/genMarkSweep.cpp index 2180f63886f..6d0fd9b49d6 100644 --- a/hotspot/src/share/vm/memory/genMarkSweep.cpp +++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp @@ -223,23 +223,23 @@ void GenMarkSweep::mark_sweep_phase1(int level, &is_alive, &keep_alive, &follow_stack_closure, NULL); } - // Follow system dictionary roots and unload classes + // This is the point where the entire marking should have completed. + assert(_marking_stack.is_empty(), "Marking should have completed"); + + // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&is_alive); - // Follow code cache roots + // Unload nmethods. CodeCache::do_unloading(&is_alive, purged_class); - follow_stack(); // Flush marking stack - // Update subklass/sibling/implementor links of live klasses + // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(&is_alive); - assert(_marking_stack.is_empty(), "just drained"); - // Visit interned string tables and delete unmarked oops + // Delete entries for dead interned strings. StringTable::unlink(&is_alive); + // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); - - assert(_marking_stack.is_empty(), "stack should be empty by now"); } @@ -282,11 +282,10 @@ void GenMarkSweep::mark_sweep_phase3(int level) { // Need new claim bits for the pointer adjustment tracing. ClassLoaderDataGraph::clear_claimed_marks(); - // Because the two closures below are created statically, cannot + // Because the closure below is created statically, we cannot // use OopsInGenClosure constructor which takes a generation, // as the Universe has not been created when the static constructors // are run. - adjust_root_pointer_closure.set_orig_generation(gch->get_gen(level)); adjust_pointer_closure.set_orig_generation(gch->get_gen(level)); gch->gen_process_strong_roots(level, @@ -294,18 +293,17 @@ void GenMarkSweep::mark_sweep_phase3(int level) { true, // activate StrongRootsScope false, // not scavenging SharedHeap::SO_AllClasses, - &adjust_root_pointer_closure, + &adjust_pointer_closure, false, // do not walk code - &adjust_root_pointer_closure, + &adjust_pointer_closure, &adjust_klass_closure); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure, /*do_marking=*/ false); - gch->gen_process_weak_roots(&adjust_root_pointer_closure, - &adjust_code_pointer_closure, - &adjust_pointer_closure); + gch->gen_process_weak_roots(&adjust_pointer_closure, + &adjust_code_pointer_closure); adjust_marks(); GenAdjustPointersClosure blk; diff --git a/hotspot/src/share/vm/memory/metachunk.cpp b/hotspot/src/share/vm/memory/metachunk.cpp index 4cb955862a8..0ac4ced70f4 100644 --- a/hotspot/src/share/vm/memory/metachunk.cpp +++ b/hotspot/src/share/vm/memory/metachunk.cpp @@ -28,6 +28,7 @@ #include "utilities/copy.hpp" #include "utilities/debug.hpp" +class VirtualSpaceNode; // // Future modification // @@ -45,27 +46,30 @@ size_t Metachunk::_overhead = // Metachunk methods -Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) { - // Set bottom, top, and end. Allow space for the Metachunk itself - Metachunk* chunk = (Metachunk*) ptr; - - MetaWord* chunk_bottom = ptr + _overhead; - chunk->set_bottom(ptr); - chunk->set_top(chunk_bottom); - MetaWord* chunk_end = ptr + word_size; - assert(chunk_end > chunk_bottom, "Chunk must be too small"); - chunk->set_end(chunk_end); - chunk->set_next(NULL); - chunk->set_prev(NULL); - chunk->set_word_size(word_size); +Metachunk::Metachunk(size_t word_size, + VirtualSpaceNode* container) : + _word_size(word_size), + _bottom(NULL), + _end(NULL), + _top(NULL), + _next(NULL), + _prev(NULL), + _container(container) +{ + _bottom = (MetaWord*)this; + _top = (MetaWord*)this + _overhead; + _end = (MetaWord*)this + word_size; #ifdef ASSERT - size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord)); - Copy::fill_to_words((HeapWord*) chunk_bottom, data_word_size, metadata_chunk_initialize); + set_is_free(false); + size_t data_word_size = pointer_delta(end(), + top(), + sizeof(MetaWord)); + Copy::fill_to_words((HeapWord*) top(), + data_word_size, + metadata_chunk_initialize); #endif - return chunk; } - MetaWord* Metachunk::allocate(size_t word_size) { MetaWord* result = NULL; // If available, bump the pointer to allocate. diff --git a/hotspot/src/share/vm/memory/metachunk.hpp b/hotspot/src/share/vm/memory/metachunk.hpp index a10cba8dbbe..ff237ab5d3f 100644 --- a/hotspot/src/share/vm/memory/metachunk.hpp +++ b/hotspot/src/share/vm/memory/metachunk.hpp @@ -41,10 +41,13 @@ // | | | | // +--------------+ <- bottom ---+ ---+ +class VirtualSpaceNode; + class Metachunk VALUE_OBJ_CLASS_SPEC { // link to support lists of chunks Metachunk* _next; Metachunk* _prev; + VirtualSpaceNode* _container; MetaWord* _bottom; MetaWord* _end; @@ -61,29 +64,20 @@ class Metachunk VALUE_OBJ_CLASS_SPEC { // the space. static size_t _overhead; - void set_bottom(MetaWord* v) { _bottom = v; } - void set_end(MetaWord* v) { _end = v; } - void set_top(MetaWord* v) { _top = v; } - void set_word_size(size_t v) { _word_size = v; } public: -#ifdef ASSERT - Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), _is_free(false), - _next(NULL), _prev(NULL) {} -#else - Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), - _next(NULL), _prev(NULL) {} -#endif + Metachunk(size_t word_size , VirtualSpaceNode* container); // Used to add a Metachunk to a list of Metachunks void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");} void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");} + void set_container(VirtualSpaceNode* v) { _container = v; } MetaWord* allocate(size_t word_size); - static Metachunk* initialize(MetaWord* ptr, size_t word_size); // Accessors Metachunk* next() const { return _next; } Metachunk* prev() const { return _prev; } + VirtualSpaceNode* container() const { return _container; } MetaWord* bottom() const { return _bottom; } MetaWord* end() const { return _end; } MetaWord* top() const { return _top; } diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 1f623bf6032..68189bf3ea1 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -47,7 +47,6 @@ typedef BinaryTreeDictionary ChunkTreeDictionary; // the free chunk lists const bool metaspace_slow_verify = false; - // Parameters for stress mode testing const uint metadata_deallocate_a_lot_block = 10; const uint metadata_deallocate_a_lock_chunk = 3; @@ -112,6 +111,7 @@ typedef class FreeList ChunkList; class ChunkManager VALUE_OBJ_CLASS_SPEC { // Free list of chunks of different sizes. + // SpecializedChunk // SmallChunk // MediumChunk // HumongousChunk @@ -165,6 +165,10 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC { // for special, small, medium, and humongous chunks. static ChunkIndex list_index(size_t size); + // Remove the chunk from its freelist. It is + // expected to be on one of the _free_chunks[] lists. + void remove_chunk(Metachunk* chunk); + // Add the simple linked list of chunks to the freelist of chunks // of type index. void return_chunks(ChunkIndex index, Metachunk* chunks); @@ -215,7 +219,6 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC { void print_on(outputStream* st); }; - // Used to manage the free list of Metablocks (a block corresponds // to the allocation of a quantum of metadata). class BlockFreelist VALUE_OBJ_CLASS_SPEC { @@ -255,6 +258,8 @@ class VirtualSpaceNode : public CHeapObj { ReservedSpace _rs; VirtualSpace _virtual_space; MetaWord* _top; + // count of chunks contained in this VirtualSpace + uintx _container_count; // Convenience functions for logical bottom and end MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); } @@ -264,10 +269,19 @@ class VirtualSpaceNode : public CHeapObj { char* low() const { return virtual_space()->low(); } char* high() const { return virtual_space()->high(); } + // The first Metachunk will be allocated at the bottom of the + // VirtualSpace + Metachunk* first_chunk() { return (Metachunk*) bottom(); } + + void inc_container_count(); +#ifdef ASSERT + uint container_count_slow(); +#endif + public: VirtualSpaceNode(size_t byte_size); - VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs) {} + VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {} ~VirtualSpaceNode(); // address of next available space in _virtual_space; @@ -282,15 +296,22 @@ class VirtualSpaceNode : public CHeapObj { MemRegion* reserved() { return &_reserved; } VirtualSpace* virtual_space() const { return (VirtualSpace*) &_virtual_space; } - // Returns true if "word_size" is available in the virtual space + // Returns true if "word_size" is available in the VirtualSpace bool is_available(size_t word_size) { return _top + word_size <= end(); } MetaWord* top() const { return _top; } void inc_top(size_t word_size) { _top += word_size; } + uintx container_count() { return _container_count; } + void dec_container_count(); +#ifdef ASSERT + void verify_container_count(); +#endif + // used and capacity in this single entry in the list size_t used_words_in_vs() const; size_t capacity_words_in_vs() const; + size_t free_words_in_vs() const; bool initialize(); @@ -306,6 +327,10 @@ class VirtualSpaceNode : public CHeapObj { bool expand_by(size_t words, bool pre_touch = false); bool shrink_by(size_t words); + // In preparation for deleting this node, remove all the chunks + // in the node from any freelist. + void purge(ChunkManager* chunk_manager); + #ifdef ASSERT // Debug support static void verify_virtual_space_total(); @@ -317,7 +342,7 @@ class VirtualSpaceNode : public CHeapObj { }; // byte_size is the size of the associated virtualspace. -VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) { +VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) { // align up to vm allocation granularity byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); @@ -341,6 +366,39 @@ VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), MemTracker::record_virtual_memory_type((address)_rs.base(), mtClass); } +void VirtualSpaceNode::purge(ChunkManager* chunk_manager) { + Metachunk* chunk = first_chunk(); + Metachunk* invalid_chunk = (Metachunk*) top(); + while (chunk < invalid_chunk ) { + assert(chunk->is_free(), "Should be marked free"); + MetaWord* next = ((MetaWord*)chunk) + chunk->word_size(); + chunk_manager->remove_chunk(chunk); + assert(chunk->next() == NULL && + chunk->prev() == NULL, + "Was not removed from its list"); + chunk = (Metachunk*) next; + } +} + +#ifdef ASSERT +uint VirtualSpaceNode::container_count_slow() { + uint count = 0; + Metachunk* chunk = first_chunk(); + Metachunk* invalid_chunk = (Metachunk*) top(); + while (chunk < invalid_chunk ) { + MetaWord* next = ((MetaWord*)chunk) + chunk->word_size(); + // Don't count the chunks on the free lists. Those are + // still part of the VirtualSpaceNode but not currently + // counted. + if (!chunk->is_free()) { + count++; + } + chunk = (Metachunk*) next; + } + return count; +} +#endif + // List of VirtualSpaces for metadata allocation. // It has a _next link for singly linked list and a MemRegion // for total space in the VirtualSpace. @@ -390,6 +448,8 @@ class VirtualSpaceList : public CHeapObj { VirtualSpaceList(size_t word_size); VirtualSpaceList(ReservedSpace rs); + size_t free_bytes(); + Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words, size_t medium_chunk_bunch); @@ -410,14 +470,14 @@ class VirtualSpaceList : public CHeapObj { void initialize(size_t word_size); size_t virtual_space_total() { return _virtual_space_total; } - void inc_virtual_space_total(size_t v) { - Atomic::add_ptr(v, &_virtual_space_total); - } - size_t virtual_space_count() { return _virtual_space_count; } - void inc_virtual_space_count() { - Atomic::inc_ptr(&_virtual_space_count); - } + void inc_virtual_space_total(size_t v); + void dec_virtual_space_total(size_t v); + void inc_virtual_space_count(); + void dec_virtual_space_count(); + + // Unlink empty VirtualSpaceNodes and free it. + void purge(); // Used and capacity in the entire list of virtual spaces. // These are global values shared by all Metaspaces @@ -520,7 +580,11 @@ class SpaceManager : public CHeapObj { bool has_small_chunk_limit() { return !vs_list()->is_class(); } // Sum of all space in allocated chunks - size_t _allocation_total; + size_t _allocated_blocks_words; + + // Sum of all allocated chunks + size_t _allocated_chunks_words; + size_t _allocated_chunks_count; // Free lists of blocks are per SpaceManager since they // are assumed to be in chunks in use by the SpaceManager @@ -576,12 +640,27 @@ class SpaceManager : public CHeapObj { size_t medium_chunk_size() { return (size_t) vs_list()->is_class() ? ClassMediumChunk : MediumChunk; } size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } - size_t allocation_total() const { return _allocation_total; } - void inc_allocation_total(size_t v) { Atomic::add_ptr(v, &_allocation_total); } + size_t allocated_blocks_words() const { return _allocated_blocks_words; } + size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } + size_t allocated_chunks_words() const { return _allocated_chunks_words; } + size_t allocated_chunks_count() const { return _allocated_chunks_count; } + bool is_humongous(size_t word_size) { return word_size > medium_chunk_size(); } static Mutex* expand_lock() { return _expand_lock; } + // Increment the per Metaspace and global running sums for Metachunks + // by the given size. This is used when a Metachunk to added to + // the in-use list. + void inc_size_metrics(size_t words); + // Increment the per Metaspace and global running sums Metablocks by the given + // size. This is used when a Metablock is allocated. + void inc_used_metrics(size_t words); + // Delete the portion of the running sums for this SpaceManager. That is, + // the globals running sums for the Metachunks and Metablocks are + // decremented for all the Metachunks in-use by this SpaceManager. + void dec_total_from_size_metrics(); + // Set the sizes for the initial chunks. void get_initial_chunk_sizes(Metaspace::MetaspaceType type, size_t* chunk_word_size, @@ -627,7 +706,7 @@ class SpaceManager : public CHeapObj { void verify_chunk_size(Metachunk* chunk); NOT_PRODUCT(void mangle_freed_chunks();) #ifdef ASSERT - void verify_allocation_total(); + void verify_allocated_blocks_words(); #endif }; @@ -641,6 +720,28 @@ Mutex* const SpaceManager::_expand_lock = SpaceManager::_expand_lock_name, Mutex::_allow_vm_block_flag); +void VirtualSpaceNode::inc_container_count() { + assert_lock_strong(SpaceManager::expand_lock()); + _container_count++; + assert(_container_count == container_count_slow(), + err_msg("Inconsistency in countainer_count _container_count " SIZE_FORMAT + "container_count_slow() " SIZE_FORMAT, + _container_count, container_count_slow())); +} + +void VirtualSpaceNode::dec_container_count() { + assert_lock_strong(SpaceManager::expand_lock()); + _container_count--; +} + +#ifdef ASSERT +void VirtualSpaceNode::verify_container_count() { + assert(_container_count == container_count_slow(), + err_msg("Inconsistency in countainer_count _container_count " SIZE_FORMAT + "container_count_slow() " SIZE_FORMAT, _container_count, container_count_slow())); +} +#endif + // BlockFreelist methods BlockFreelist::BlockFreelist() : _dictionary(NULL) {} @@ -701,6 +802,10 @@ void BlockFreelist::print_on(outputStream* st) const { VirtualSpaceNode::~VirtualSpaceNode() { _rs.release(); +#ifdef ASSERT + size_t word_size = sizeof(*this) / BytesPerWord; + Copy::fill_to_words((HeapWord*) this, word_size, 0xf1f1f1f1); +#endif } size_t VirtualSpaceNode::used_words_in_vs() const { @@ -712,6 +817,9 @@ size_t VirtualSpaceNode::capacity_words_in_vs() const { return pointer_delta(end(), bottom(), sizeof(MetaWord)); } +size_t VirtualSpaceNode::free_words_in_vs() const { + return pointer_delta(end(), top(), sizeof(MetaWord)); +} // Allocates the chunk from the virtual space only. // This interface is also used internally for debugging. Not all @@ -733,8 +841,8 @@ Metachunk* VirtualSpaceNode::take_from_committed(size_t chunk_word_size) { // Take the space (bump top on the current virtual space). inc_top(chunk_word_size); - // Point the chunk at the space - Metachunk* result = Metachunk::initialize(chunk_limit, chunk_word_size); + // Initialize the chunk + Metachunk* result = ::new (chunk_limit) Metachunk(chunk_word_size, this); return result; } @@ -762,9 +870,11 @@ bool VirtualSpaceNode::shrink_by(size_t words) { Metachunk* VirtualSpaceNode::get_chunk_vs(size_t chunk_word_size) { assert_lock_strong(SpaceManager::expand_lock()); - Metachunk* result = NULL; - - return take_from_committed(chunk_word_size); + Metachunk* result = take_from_committed(chunk_word_size); + if (result != NULL) { + inc_container_count(); + } + return result; } Metachunk* VirtualSpaceNode::get_chunk_vs_with_expand(size_t chunk_word_size) { @@ -843,6 +953,83 @@ VirtualSpaceList::~VirtualSpaceList() { } } +void VirtualSpaceList::inc_virtual_space_total(size_t v) { + assert_lock_strong(SpaceManager::expand_lock()); + _virtual_space_total = _virtual_space_total + v; +} +void VirtualSpaceList::dec_virtual_space_total(size_t v) { + assert_lock_strong(SpaceManager::expand_lock()); + _virtual_space_total = _virtual_space_total - v; +} + +void VirtualSpaceList::inc_virtual_space_count() { + assert_lock_strong(SpaceManager::expand_lock()); + _virtual_space_count++; +} +void VirtualSpaceList::dec_virtual_space_count() { + assert_lock_strong(SpaceManager::expand_lock()); + _virtual_space_count--; +} + +void ChunkManager::remove_chunk(Metachunk* chunk) { + size_t word_size = chunk->word_size(); + ChunkIndex index = list_index(word_size); + if (index != HumongousIndex) { + free_chunks(index)->remove_chunk(chunk); + } else { + humongous_dictionary()->remove_chunk(chunk); + } + + // Chunk is being removed from the chunks free list. + dec_free_chunks_total(chunk->capacity_word_size()); +} + +// Walk the list of VirtualSpaceNodes and delete +// nodes with a 0 container_count. Remove Metachunks in +// the node from their respective freelists. +void VirtualSpaceList::purge() { + assert_lock_strong(SpaceManager::expand_lock()); + // Don't use a VirtualSpaceListIterator because this + // list is being changed and a straightforward use of an iterator is not safe. + VirtualSpaceNode* purged_vsl = NULL; + VirtualSpaceNode* prev_vsl = virtual_space_list(); + VirtualSpaceNode* next_vsl = prev_vsl; + while (next_vsl != NULL) { + VirtualSpaceNode* vsl = next_vsl; + next_vsl = vsl->next(); + // Don't free the current virtual space since it will likely + // be needed soon. + if (vsl->container_count() == 0 && vsl != current_virtual_space()) { + // Unlink it from the list + if (prev_vsl == vsl) { + // This is the case of the current note being the first note. + assert(vsl == virtual_space_list(), "Expected to be the first note"); + set_virtual_space_list(vsl->next()); + } else { + prev_vsl->set_next(vsl->next()); + } + + vsl->purge(chunk_manager()); + dec_virtual_space_total(vsl->reserved()->word_size()); + dec_virtual_space_count(); + purged_vsl = vsl; + delete vsl; + } else { + prev_vsl = vsl; + } + } +#ifdef ASSERT + if (purged_vsl != NULL) { + // List should be stable enough to use an iterator here. + VirtualSpaceListIterator iter(virtual_space_list()); + while (iter.repeat()) { + VirtualSpaceNode* vsl = iter.get_next(); + assert(vsl != purged_vsl, "Purge of vsl failed"); + } + } +#endif +} + size_t VirtualSpaceList::used_words_sum() { size_t allocated_by_vs = 0; VirtualSpaceListIterator iter(virtual_space_list()); @@ -907,6 +1094,10 @@ VirtualSpaceList::VirtualSpaceList(ReservedSpace rs) : link_vs(class_entry, rs.size()/BytesPerWord); } +size_t VirtualSpaceList::free_bytes() { + return virtual_space_list()->free_words_in_vs() * BytesPerWord; +} + // Allocate another meta virtual space and add it to the list. bool VirtualSpaceList::grow_vs(size_t vs_word_size) { assert_lock_strong(SpaceManager::expand_lock()); @@ -955,8 +1146,10 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, // Get a chunk from the chunk freelist Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words); - // Allocate a chunk out of the current virtual space. - if (next == NULL) { + if (next != NULL) { + next->container()->inc_container_count(); + } else { + // Allocate a chunk out of the current virtual space. next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); } @@ -1045,9 +1238,9 @@ bool VirtualSpaceList::contains(const void *ptr) { // // After the GC the compute_new_size() for MetaspaceGC is called to // resize the capacity of the metaspaces. The current implementation -// is based on the flags MinMetaspaceFreeRatio and MaxHeapFreeRatio used +// is based on the flags MinMetaspaceFreeRatio and MaxMetaspaceFreeRatio used // to resize the Java heap by some GC's. New flags can be implemented -// if really needed. MinHeapFreeRatio is used to calculate how much +// if really needed. MinMetaspaceFreeRatio is used to calculate how much // free space is desirable in the metaspace capacity to decide how much // to increase the HWM. MaxMetaspaceFreeRatio is used to decide how much // free space is desirable in the metaspace capacity before decreasing @@ -1082,7 +1275,11 @@ size_t MetaspaceGC::delta_capacity_until_GC(size_t word_size) { } bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) { + + size_t committed_capacity_bytes = MetaspaceAux::allocated_capacity_bytes(); // If the user wants a limit, impose one. + size_t max_metaspace_size_bytes = MaxMetaspaceSize; + size_t metaspace_size_bytes = MetaspaceSize; if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) && MetaspaceAux::reserved_in_bytes() >= MaxMetaspaceSize) { return false; @@ -1094,57 +1291,48 @@ bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) { // If this is part of an allocation after a GC, expand // unconditionally. - if(MetaspaceGC::expand_after_GC()) { + if (MetaspaceGC::expand_after_GC()) { return true; } - size_t metaspace_size_words = MetaspaceSize / BytesPerWord; + // If the capacity is below the minimum capacity, allow the // expansion. Also set the high-water-mark (capacity_until_GC) // to that minimum capacity so that a GC will not be induced // until that minimum capacity is exceeded. - if (vsl->capacity_words_sum() < metaspace_size_words || + if (committed_capacity_bytes < metaspace_size_bytes || capacity_until_GC() == 0) { - set_capacity_until_GC(metaspace_size_words); + set_capacity_until_GC(metaspace_size_bytes); return true; } else { - if (vsl->capacity_words_sum() < capacity_until_GC()) { + if (committed_capacity_bytes < capacity_until_GC()) { return true; } else { if (TraceMetadataChunkAllocation && Verbose) { gclog_or_tty->print_cr(" allocation request size " SIZE_FORMAT " capacity_until_GC " SIZE_FORMAT - " capacity_words_sum " SIZE_FORMAT - " used_words_sum " SIZE_FORMAT - " free chunks " SIZE_FORMAT - " free chunks count %d", + " allocated_capacity_bytes " SIZE_FORMAT, word_size, capacity_until_GC(), - vsl->capacity_words_sum(), - vsl->used_words_sum(), - vsl->chunk_manager()->free_chunks_total(), - vsl->chunk_manager()->free_chunks_count()); + MetaspaceAux::allocated_capacity_bytes()); } return false; } } } -// Variables are in bytes + void MetaspaceGC::compute_new_size() { assert(_shrink_factor <= 100, "invalid shrink factor"); uint current_shrink_factor = _shrink_factor; _shrink_factor = 0; - VirtualSpaceList *vsl = Metaspace::space_list(); - - size_t capacity_after_gc = vsl->capacity_bytes_sum(); - // Check to see if these two can be calculated without walking the CLDG - size_t used_after_gc = vsl->used_bytes_sum(); - size_t capacity_until_GC = vsl->capacity_bytes_sum(); - size_t free_after_gc = capacity_until_GC - used_after_gc; + // Until a faster way of calculating the "used" quantity is implemented, + // use "capacity". + const size_t used_after_gc = MetaspaceAux::allocated_capacity_bytes(); + const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC(); const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0; const double maximum_used_percentage = 1.0 - minimum_free_percentage; @@ -1157,45 +1345,34 @@ void MetaspaceGC::compute_new_size() { MetaspaceSize); if (PrintGCDetails && Verbose) { - const double free_percentage = ((double)free_after_gc) / capacity_until_GC; gclog_or_tty->print_cr("\nMetaspaceGC::compute_new_size: "); gclog_or_tty->print_cr(" " " minimum_free_percentage: %6.2f" " maximum_used_percentage: %6.2f", minimum_free_percentage, maximum_used_percentage); - double d_free_after_gc = free_after_gc / (double) K; gclog_or_tty->print_cr(" " - " free_after_gc : %6.1fK" - " used_after_gc : %6.1fK" - " capacity_after_gc : %6.1fK" - " metaspace HWM : %6.1fK", - free_after_gc / (double) K, - used_after_gc / (double) K, - capacity_after_gc / (double) K, - capacity_until_GC / (double) K); - gclog_or_tty->print_cr(" " - " free_percentage: %6.2f", - free_percentage); + " used_after_gc : %6.1fKB", + used_after_gc / (double) K); } + size_t shrink_bytes = 0; if (capacity_until_GC < minimum_desired_capacity) { // If we have less capacity below the metaspace HWM, then // increment the HWM. size_t expand_bytes = minimum_desired_capacity - capacity_until_GC; // Don't expand unless it's significant if (expand_bytes >= MinMetaspaceExpansion) { - size_t expand_words = expand_bytes / BytesPerWord; - MetaspaceGC::inc_capacity_until_GC(expand_words); + MetaspaceGC::set_capacity_until_GC(capacity_until_GC + expand_bytes); } if (PrintGCDetails && Verbose) { - size_t new_capacity_until_GC = MetaspaceGC::capacity_until_GC_in_bytes(); + size_t new_capacity_until_GC = capacity_until_GC; gclog_or_tty->print_cr(" expanding:" - " minimum_desired_capacity: %6.1fK" - " expand_words: %6.1fK" - " MinMetaspaceExpansion: %6.1fK" - " new metaspace HWM: %6.1fK", + " minimum_desired_capacity: %6.1fKB" + " expand_bytes: %6.1fKB" + " MinMetaspaceExpansion: %6.1fKB" + " new metaspace HWM: %6.1fKB", minimum_desired_capacity / (double) K, expand_bytes / (double) K, MinMetaspaceExpansion / (double) K, @@ -1205,11 +1382,10 @@ void MetaspaceGC::compute_new_size() { } // No expansion, now see if we want to shrink - size_t shrink_words = 0; // We would never want to shrink more than this - size_t max_shrink_words = capacity_until_GC - minimum_desired_capacity; - assert(max_shrink_words >= 0, err_msg("max_shrink_words " SIZE_FORMAT, - max_shrink_words)); + size_t max_shrink_bytes = capacity_until_GC - minimum_desired_capacity; + assert(max_shrink_bytes >= 0, err_msg("max_shrink_bytes " SIZE_FORMAT, + max_shrink_bytes)); // Should shrinking be considered? if (MaxMetaspaceFreeRatio < 100) { @@ -1219,17 +1395,15 @@ void MetaspaceGC::compute_new_size() { size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); maximum_desired_capacity = MAX2(maximum_desired_capacity, MetaspaceSize); - if (PrintGC && Verbose) { + if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr(" " " maximum_free_percentage: %6.2f" " minimum_used_percentage: %6.2f", maximum_free_percentage, minimum_used_percentage); gclog_or_tty->print_cr(" " - " capacity_until_GC: %6.1fK" - " minimum_desired_capacity: %6.1fK" - " maximum_desired_capacity: %6.1fK", - capacity_until_GC / (double) K, + " minimum_desired_capacity: %6.1fKB" + " maximum_desired_capacity: %6.1fKB", minimum_desired_capacity / (double) K, maximum_desired_capacity / (double) K); } @@ -1239,17 +1413,17 @@ void MetaspaceGC::compute_new_size() { if (capacity_until_GC > maximum_desired_capacity) { // Capacity too large, compute shrinking size - shrink_words = capacity_until_GC - maximum_desired_capacity; + shrink_bytes = capacity_until_GC - maximum_desired_capacity; // We don't want shrink all the way back to initSize if people call // System.gc(), because some programs do that between "phases" and then // we'd just have to grow the heap up again for the next phase. So we // damp the shrinking: 0% on the first call, 10% on the second call, 40% // on the third call, and 100% by the fourth call. But if we recompute // size without shrinking, it goes back to 0%. - shrink_words = shrink_words / 100 * current_shrink_factor; - assert(shrink_words <= max_shrink_words, + shrink_bytes = shrink_bytes / 100 * current_shrink_factor; + assert(shrink_bytes <= max_shrink_bytes, err_msg("invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT, - shrink_words, max_shrink_words)); + shrink_bytes, max_shrink_bytes)); if (current_shrink_factor == 0) { _shrink_factor = 10; } else { @@ -1263,11 +1437,11 @@ void MetaspaceGC::compute_new_size() { MetaspaceSize / (double) K, maximum_desired_capacity / (double) K); gclog_or_tty->print_cr(" " - " shrink_words: %.1fK" + " shrink_bytes: %.1fK" " current_shrink_factor: %d" " new shrink factor: %d" " MinMetaspaceExpansion: %.1fK", - shrink_words / (double) K, + shrink_bytes / (double) K, current_shrink_factor, _shrink_factor, MinMetaspaceExpansion / (double) K); @@ -1275,23 +1449,11 @@ void MetaspaceGC::compute_new_size() { } } - // Don't shrink unless it's significant - if (shrink_words >= MinMetaspaceExpansion) { - VirtualSpaceNode* csp = vsl->current_virtual_space(); - size_t available_to_shrink = csp->capacity_words_in_vs() - - csp->used_words_in_vs(); - shrink_words = MIN2(shrink_words, available_to_shrink); - csp->shrink_by(shrink_words); - MetaspaceGC::dec_capacity_until_GC(shrink_words); - if (PrintGCDetails && Verbose) { - size_t new_capacity_until_GC = MetaspaceGC::capacity_until_GC_in_bytes(); - gclog_or_tty->print_cr(" metaspace HWM: %.1fK", new_capacity_until_GC / (double) K); - } + if (shrink_bytes >= MinMetaspaceExpansion && + ((capacity_until_GC - shrink_bytes) >= MetaspaceSize)) { + MetaspaceGC::set_capacity_until_GC(capacity_until_GC - shrink_bytes); } - assert(used_after_gc <= vsl->capacity_bytes_sum(), - "sanity check"); - } // Metadebug methods @@ -1567,9 +1729,6 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { } // Chunk is being removed from the chunks free list. dec_free_chunks_total(chunk->capacity_word_size()); -#ifdef ASSERT - chunk->set_is_free(false); -#endif } else { return NULL; } @@ -1578,6 +1737,11 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { // Remove it from the links to this freelist chunk->set_next(NULL); chunk->set_prev(NULL); +#ifdef ASSERT + // Chunk is no longer on any freelist. Setting to false make container_count_slow() + // work. + chunk->set_is_free(false); +#endif slow_locked_verify(); return chunk; } @@ -1692,18 +1856,28 @@ size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const { } size_t SpaceManager::sum_capacity_in_chunks_in_use() const { - MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); - size_t sum = 0; - for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { - Metachunk* chunk = chunks_in_use(i); - while (chunk != NULL) { - // Just changed this sum += chunk->capacity_word_size(); - // sum += chunk->word_size() - Metachunk::overhead(); - sum += chunk->capacity_word_size(); - chunk = chunk->next(); + // For CMS use "allocated_chunks_words()" which does not need the + // Metaspace lock. For the other collectors sum over the + // lists. Use both methods as a check that "allocated_chunks_words()" + // is correct. That is, sum_capacity_in_chunks() is too expensive + // to use in the product and allocated_chunks_words() should be used + // but allow for checking that allocated_chunks_words() returns the same + // value as sum_capacity_in_chunks_in_use() which is the definitive + // answer. + if (UseConcMarkSweepGC) { + return allocated_chunks_words(); + } else { + MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); + size_t sum = 0; + for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { + Metachunk* chunk = chunks_in_use(i); + while (chunk != NULL) { + sum += chunk->capacity_word_size(); + chunk = chunk->next(); + } } - } return sum; + } } size_t SpaceManager::sum_count_in_chunks_in_use() { @@ -1861,12 +2035,44 @@ void SpaceManager::print_on(outputStream* st) const { SpaceManager::SpaceManager(Mutex* lock, VirtualSpaceList* vs_list) : _vs_list(vs_list), - _allocation_total(0), + _allocated_blocks_words(0), + _allocated_chunks_words(0), + _allocated_chunks_count(0), _lock(lock) { initialize(); } +void SpaceManager::inc_size_metrics(size_t words) { + assert_lock_strong(SpaceManager::expand_lock()); + // Total of allocated Metachunks and allocated Metachunks count + // for each SpaceManager + _allocated_chunks_words = _allocated_chunks_words + words; + _allocated_chunks_count++; + // Global total of capacity in allocated Metachunks + MetaspaceAux::inc_capacity(words); + // Global total of allocated Metablocks. + // used_words_slow() includes the overhead in each + // Metachunk so include it in the used when the + // Metachunk is first added (so only added once per + // Metachunk). + MetaspaceAux::inc_used(Metachunk::overhead()); +} + +void SpaceManager::inc_used_metrics(size_t words) { + // Add to the per SpaceManager total + Atomic::add_ptr(words, &_allocated_blocks_words); + // Add to the global total + MetaspaceAux::inc_used(words); +} + +void SpaceManager::dec_total_from_size_metrics() { + MetaspaceAux::dec_capacity(allocated_chunks_words()); + MetaspaceAux::dec_used(allocated_blocks_words()); + // Also deduct the overhead per Metachunk + MetaspaceAux::dec_used(allocated_chunks_count() * Metachunk::overhead()); +} + void SpaceManager::initialize() { Metadebug::init_allocation_fail_alot_count(); for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { @@ -1887,11 +2093,13 @@ void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { assert_lock_strong(SpaceManager::expand_lock()); Metachunk* cur = chunks; - // This return chunks one at a time. If a new + // This returns chunks one at a time. If a new // class List can be created that is a base class // of FreeList then something like FreeList::prepend() // can be used in place of this loop while (cur != NULL) { + assert(cur->container() != NULL, "Container should have been set"); + cur->container()->dec_container_count(); // Capture the next link before it is changed // by the call to return_chunk_at_head(); Metachunk* next = cur->next(); @@ -1903,7 +2111,10 @@ void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { SpaceManager::~SpaceManager() { // This call this->_lock which can't be done while holding expand_lock() - const size_t in_use_before = sum_capacity_in_chunks_in_use(); + assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(), + err_msg("sum_capacity_in_chunks_in_use() " SIZE_FORMAT + " allocated_chunks_words() " SIZE_FORMAT, + sum_capacity_in_chunks_in_use(), allocated_chunks_words())); MutexLockerEx fcl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); @@ -1912,17 +2123,19 @@ SpaceManager::~SpaceManager() { chunk_manager->slow_locked_verify(); + dec_total_from_size_metrics(); + if (TraceMetadataChunkAllocation && Verbose) { gclog_or_tty->print_cr("~SpaceManager(): " PTR_FORMAT, this); locked_print_chunks_in_use_on(gclog_or_tty); } - // Mangle freed memory. - NOT_PRODUCT(mangle_freed_chunks();) + // Do not mangle freed Metachunks. The chunk size inside Metachunks + // is during the freeing of a VirtualSpaceNodes. // Have to update before the chunks_in_use lists are emptied // below. - chunk_manager->inc_free_chunks_total(in_use_before, + chunk_manager->inc_free_chunks_total(allocated_chunks_words(), sum_count_in_chunks_in_use()); // Add all the chunks in use by this space manager @@ -1978,6 +2191,7 @@ SpaceManager::~SpaceManager() { " granularity %d", humongous_chunks->word_size(), HumongousChunkGranularity)); Metachunk* next_humongous_chunks = humongous_chunks->next(); + humongous_chunks->container()->dec_container_count(); chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks); humongous_chunks = next_humongous_chunks; } @@ -1987,7 +2201,6 @@ SpaceManager::~SpaceManager() { chunk_manager->humongous_dictionary()->total_count(), chunk_size_name(HumongousIndex)); } - set_chunks_in_use(HumongousIndex, NULL); chunk_manager->slow_locked_verify(); } @@ -2067,12 +2280,17 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { assert(new_chunk->word_size() > medium_chunk_size(), "List inconsistency"); } + // Add to the running sum of capacity + inc_size_metrics(new_chunk->word_size()); + assert(new_chunk->is_empty(), "Not ready for reuse"); if (TraceMetadataChunkAllocation && Verbose) { gclog_or_tty->print("SpaceManager::add_chunk: %d) ", sum_count_in_chunks_in_use()); new_chunk->print_on(gclog_or_tty); - vs_list()->chunk_manager()->locked_print_free_chunks(tty); + if (vs_list() != NULL) { + vs_list()->chunk_manager()->locked_print_free_chunks(tty); + } } } @@ -2143,7 +2361,7 @@ MetaWord* SpaceManager::allocate_work(size_t word_size) { // of memory if this returns null. if (DumpSharedSpaces) { assert(current_chunk() != NULL, "should never happen"); - inc_allocation_total(word_size); + inc_used_metrics(word_size); return current_chunk()->allocate(word_size); // caller handles null result } if (current_chunk() != NULL) { @@ -2154,7 +2372,7 @@ MetaWord* SpaceManager::allocate_work(size_t word_size) { result = grow_and_allocate(word_size); } if (result > 0) { - inc_allocation_total(word_size); + inc_used_metrics(word_size); assert(result != (MetaWord*) chunks_in_use(MediumIndex), "Head of the list is being allocated"); } @@ -2188,20 +2406,14 @@ void SpaceManager::verify_chunk_size(Metachunk* chunk) { } #ifdef ASSERT -void SpaceManager::verify_allocation_total() { +void SpaceManager::verify_allocated_blocks_words() { // Verification is only guaranteed at a safepoint. - if (SafepointSynchronize::is_at_safepoint()) { - gclog_or_tty->print_cr("Chunk " PTR_FORMAT " allocation_total " SIZE_FORMAT - " sum_used_in_chunks_in_use " SIZE_FORMAT, - this, - allocation_total(), - sum_used_in_chunks_in_use()); - } - MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); - assert(allocation_total() == sum_used_in_chunks_in_use(), + assert(SafepointSynchronize::is_at_safepoint() || !Universe::is_fully_initialized(), + "Verification can fail if the applications is running"); + assert(allocated_blocks_words() == sum_used_in_chunks_in_use(), err_msg("allocation total is not consistent " SIZE_FORMAT " vs " SIZE_FORMAT, - allocation_total(), sum_used_in_chunks_in_use())); + allocated_blocks_words(), sum_used_in_chunks_in_use())); } #endif @@ -2257,14 +2469,65 @@ void SpaceManager::mangle_freed_chunks() { // MetaspaceAux -size_t MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) { + +size_t MetaspaceAux::_allocated_capacity_words = 0; +size_t MetaspaceAux::_allocated_used_words = 0; + +size_t MetaspaceAux::free_bytes() { + size_t result = 0; + if (Metaspace::class_space_list() != NULL) { + result = result + Metaspace::class_space_list()->free_bytes(); + } + if (Metaspace::space_list() != NULL) { + result = result + Metaspace::space_list()->free_bytes(); + } + return result; +} + +void MetaspaceAux::dec_capacity(size_t words) { + assert_lock_strong(SpaceManager::expand_lock()); + assert(words <= _allocated_capacity_words, + err_msg("About to decrement below 0: words " SIZE_FORMAT + " is greater than _allocated_capacity_words " SIZE_FORMAT, + words, _allocated_capacity_words)); + _allocated_capacity_words = _allocated_capacity_words - words; +} + +void MetaspaceAux::inc_capacity(size_t words) { + assert_lock_strong(SpaceManager::expand_lock()); + // Needs to be atomic + _allocated_capacity_words = _allocated_capacity_words + words; +} + +void MetaspaceAux::dec_used(size_t words) { + assert(words <= _allocated_used_words, + err_msg("About to decrement below 0: words " SIZE_FORMAT + " is greater than _allocated_used_words " SIZE_FORMAT, + words, _allocated_used_words)); + // For CMS deallocation of the Metaspaces occurs during the + // sweep which is a concurrent phase. Protection by the expand_lock() + // is not enough since allocation is on a per Metaspace basis + // and protected by the Metaspace lock. + jlong minus_words = (jlong) - (jlong) words; + Atomic::add_ptr(minus_words, &_allocated_used_words); +} + +void MetaspaceAux::inc_used(size_t words) { + // _allocated_used_words tracks allocations for + // each piece of metadata. Those allocations are + // generally done concurrently by different application + // threads so must be done atomically. + Atomic::add_ptr(words, &_allocated_used_words); +} + +size_t MetaspaceAux::used_bytes_slow(Metaspace::MetadataType mdtype) { size_t used = 0; ClassLoaderDataGraphMetaspaceIterator iter; while (iter.repeat()) { Metaspace* msp = iter.get_next(); - // Sum allocation_total for each metaspace + // Sum allocated_blocks_words for each metaspace if (msp != NULL) { - used += msp->used_words(mdtype); + used += msp->used_words_slow(mdtype); } } return used * BytesPerWord; @@ -2282,13 +2545,15 @@ size_t MetaspaceAux::free_in_bytes(Metaspace::MetadataType mdtype) { return free * BytesPerWord; } -size_t MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) { - size_t capacity = free_chunks_total(mdtype); +size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) { + // Don't count the space in the freelists. That space will be + // added to the capacity calculation as needed. + size_t capacity = 0; ClassLoaderDataGraphMetaspaceIterator iter; while (iter.repeat()) { Metaspace* msp = iter.get_next(); if (msp != NULL) { - capacity += msp->capacity_words(mdtype); + capacity += msp->capacity_words_slow(mdtype); } } return capacity * BytesPerWord; @@ -2315,23 +2580,30 @@ size_t MetaspaceAux::free_chunks_total_in_bytes(Metaspace::MetadataType mdtype) return free_chunks_total(mdtype) * BytesPerWord; } +size_t MetaspaceAux::free_chunks_total() { + return free_chunks_total(Metaspace::ClassType) + + free_chunks_total(Metaspace::NonClassType); +} + +size_t MetaspaceAux::free_chunks_total_in_bytes() { + return free_chunks_total() * BytesPerWord; +} + void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) { gclog_or_tty->print(", [Metaspace:"); if (PrintGCDetails && Verbose) { gclog_or_tty->print(" " SIZE_FORMAT "->" SIZE_FORMAT - "(" SIZE_FORMAT "/" SIZE_FORMAT ")", + "(" SIZE_FORMAT ")", prev_metadata_used, - used_in_bytes(), - capacity_in_bytes(), + allocated_capacity_bytes(), reserved_in_bytes()); } else { gclog_or_tty->print(" " SIZE_FORMAT "K" "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K/" SIZE_FORMAT "K)", + "(" SIZE_FORMAT "K)", prev_metadata_used / K, - used_in_bytes()/ K, - capacity_in_bytes()/K, + allocated_capacity_bytes() / K, reserved_in_bytes()/ K); } @@ -2346,23 +2618,30 @@ void MetaspaceAux::print_on(outputStream* out) { out->print_cr(" Metaspace total " SIZE_FORMAT "K, used " SIZE_FORMAT "K," " reserved " SIZE_FORMAT "K", - capacity_in_bytes()/K, used_in_bytes()/K, reserved_in_bytes()/K); - out->print_cr(" data space " - SIZE_FORMAT "K, used " SIZE_FORMAT "K," - " reserved " SIZE_FORMAT "K", - capacity_in_bytes(nct)/K, used_in_bytes(nct)/K, reserved_in_bytes(nct)/K); - out->print_cr(" class space " - SIZE_FORMAT "K, used " SIZE_FORMAT "K," - " reserved " SIZE_FORMAT "K", - capacity_in_bytes(ct)/K, used_in_bytes(ct)/K, reserved_in_bytes(ct)/K); + allocated_capacity_bytes()/K, allocated_used_bytes()/K, reserved_in_bytes()/K); +#if 0 +// The calls to capacity_bytes_slow() and used_bytes_slow() cause +// lock ordering assertion failures with some collectors. Do +// not include this code until the lock ordering is fixed. + if (PrintGCDetails && Verbose) { + out->print_cr(" data space " + SIZE_FORMAT "K, used " SIZE_FORMAT "K," + " reserved " SIZE_FORMAT "K", + capacity_bytes_slow(nct)/K, used_bytes_slow(nct)/K, reserved_in_bytes(nct)/K); + out->print_cr(" class space " + SIZE_FORMAT "K, used " SIZE_FORMAT "K," + " reserved " SIZE_FORMAT "K", + capacity_bytes_slow(ct)/K, used_bytes_slow(ct)/K, reserved_in_bytes(ct)/K); + } +#endif } // Print information for class space and data space separately. // This is almost the same as above. void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) { size_t free_chunks_capacity_bytes = free_chunks_total_in_bytes(mdtype); - size_t capacity_bytes = capacity_in_bytes(mdtype); - size_t used_bytes = used_in_bytes(mdtype); + size_t capacity_bytes = capacity_bytes_slow(mdtype); + size_t used_bytes = used_bytes_slow(mdtype); size_t free_bytes = free_in_bytes(mdtype); size_t used_and_free = used_bytes + free_bytes + free_chunks_capacity_bytes; @@ -2435,6 +2714,36 @@ void MetaspaceAux::verify_free_chunks() { Metaspace::class_space_list()->chunk_manager()->verify(); } +void MetaspaceAux::verify_capacity() { +#ifdef ASSERT + size_t running_sum_capacity_bytes = allocated_capacity_bytes(); + // For purposes of the running sum of used, verify against capacity + size_t capacity_in_use_bytes = capacity_bytes_slow(); + assert(running_sum_capacity_bytes == capacity_in_use_bytes, + err_msg("allocated_capacity_words() * BytesPerWord " SIZE_FORMAT + " capacity_bytes_slow()" SIZE_FORMAT, + running_sum_capacity_bytes, capacity_in_use_bytes)); +#endif +} + +void MetaspaceAux::verify_used() { +#ifdef ASSERT + size_t running_sum_used_bytes = allocated_used_bytes(); + // For purposes of the running sum of used, verify against capacity + size_t used_in_use_bytes = used_bytes_slow(); + assert(allocated_used_bytes() == used_in_use_bytes, + err_msg("allocated_used_bytes() " SIZE_FORMAT + " used_bytes_slow()()" SIZE_FORMAT, + allocated_used_bytes(), used_in_use_bytes)); +#endif +} + +void MetaspaceAux::verify_metrics() { + verify_capacity(); + verify_used(); +} + + // Metaspace methods size_t Metaspace::_first_chunk_word_size = 0; @@ -2584,8 +2893,8 @@ MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) MetaWord* result; MetaspaceGC::set_expand_after_GC(true); size_t before_inc = MetaspaceGC::capacity_until_GC(); - size_t delta_words = MetaspaceGC::delta_capacity_until_GC(word_size); - MetaspaceGC::inc_capacity_until_GC(delta_words); + size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size) * BytesPerWord; + MetaspaceGC::inc_capacity_until_GC(delta_bytes); if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT " to " SIZE_FORMAT, before_inc, MetaspaceGC::capacity_until_GC()); @@ -2603,8 +2912,8 @@ char* Metaspace::bottom() const { return (char*)vsm()->current_chunk()->bottom(); } -size_t Metaspace::used_words(MetadataType mdtype) const { - // return vsm()->allocation_total(); +size_t Metaspace::used_words_slow(MetadataType mdtype) const { + // return vsm()->allocated_used_words(); return mdtype == ClassType ? class_vsm()->sum_used_in_chunks_in_use() : vsm()->sum_used_in_chunks_in_use(); // includes overhead! } @@ -2619,16 +2928,24 @@ size_t Metaspace::free_words(MetadataType mdtype) const { // have been made. Don't include space in the global freelist and // in the space available in the dictionary which // is already counted in some chunk. -size_t Metaspace::capacity_words(MetadataType mdtype) const { +size_t Metaspace::capacity_words_slow(MetadataType mdtype) const { return mdtype == ClassType ? class_vsm()->sum_capacity_in_chunks_in_use() : vsm()->sum_capacity_in_chunks_in_use(); } +size_t Metaspace::used_bytes_slow(MetadataType mdtype) const { + return used_words_slow(mdtype) * BytesPerWord; +} + +size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const { + return capacity_words_slow(mdtype) * BytesPerWord; +} + void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { if (SafepointSynchronize::is_at_safepoint()) { assert(Thread::current()->is_VM_thread(), "should be the VM thread"); // Don't take Heap_lock - MutexLocker ml(vsm()->lock()); + MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); if (word_size < TreeChunk ::min_size()) { // Dark matter. Too small for dictionary. #ifdef ASSERT @@ -2642,7 +2959,7 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { vsm()->deallocate(ptr, word_size); } } else { - MutexLocker ml(vsm()->lock()); + MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); if (word_size < TreeChunk ::min_size()) { // Dark matter. Too small for dictionary. @@ -2716,6 +3033,13 @@ Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, return Metablock::initialize(result, word_size); } +void Metaspace::purge() { + MutexLockerEx cl(SpaceManager::expand_lock(), + Mutex::_no_safepoint_check_flag); + space_list()->purge(); + class_space_list()->purge(); +} + void Metaspace::print_on(outputStream* out) const { // Print both class virtual space counts and metaspace. if (Verbose) { @@ -2733,7 +3057,8 @@ bool Metaspace::contains(const void * ptr) { // aren't deleted presently. When they are, some sort of locking might // be needed. Note, locking this can cause inversion problems with the // caller in MetaspaceObj::is_metadata() function. - return space_list()->contains(ptr) || class_space_list()->contains(ptr); + return space_list()->contains(ptr) || + class_space_list()->contains(ptr); } void Metaspace::verify() { @@ -2742,10 +3067,6 @@ void Metaspace::verify() { } void Metaspace::dump(outputStream* const out) const { - if (UseMallocOnly) { - // Just print usage for now - out->print_cr("usage %d", used_words(Metaspace::NonClassType)); - } out->print_cr("\nVirtual space manager: " INTPTR_FORMAT, vsm()); vsm()->dump(out); out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm()); diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index f704804795f..1108c79feab 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -111,6 +111,10 @@ class Metaspace : public CHeapObj { SpaceManager* _class_vsm; SpaceManager* class_vsm() const { return _class_vsm; } + // Allocate space for metadata of type mdtype. This is space + // within a Metachunk and is used by + // allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS) + // which returns a Metablock. MetaWord* allocate(size_t word_size, MetadataType mdtype); // Virtual Space lists for both classes and other metadata @@ -133,11 +137,14 @@ class Metaspace : public CHeapObj { static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; } char* bottom() const; - size_t used_words(MetadataType mdtype) const; + size_t used_words_slow(MetadataType mdtype) const; size_t free_words(MetadataType mdtype) const; - size_t capacity_words(MetadataType mdtype) const; + size_t capacity_words_slow(MetadataType mdtype) const; size_t waste_words(MetadataType mdtype) const; + size_t used_bytes_slow(MetadataType mdtype) const; + size_t capacity_bytes_slow(MetadataType mdtype) const; + static Metablock* allocate(ClassLoaderData* loader_data, size_t size, bool read_only, MetadataType mdtype, TRAPS); void deallocate(MetaWord* ptr, size_t byte_size, bool is_class); @@ -150,6 +157,9 @@ class Metaspace : public CHeapObj { static bool contains(const void *ptr); void dump(outputStream* const out) const; + // Free empty virtualspaces + static void purge(); + void print_on(outputStream* st) const; // Debugging support void verify(); @@ -158,28 +168,81 @@ class Metaspace : public CHeapObj { class MetaspaceAux : AllStatic { // Statistics for class space and data space in metaspace. - static size_t used_in_bytes(Metaspace::MetadataType mdtype); + + // These methods iterate over the classloader data graph + // for the given Metaspace type. These are slow. + static size_t used_bytes_slow(Metaspace::MetadataType mdtype); static size_t free_in_bytes(Metaspace::MetadataType mdtype); - static size_t capacity_in_bytes(Metaspace::MetadataType mdtype); + static size_t capacity_bytes_slow(Metaspace::MetadataType mdtype); + + // Iterates over the virtual space list. static size_t reserved_in_bytes(Metaspace::MetadataType mdtype); static size_t free_chunks_total(Metaspace::MetadataType mdtype); static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); public: - // Total of space allocated to metadata in all Metaspaces - static size_t used_in_bytes() { - return used_in_bytes(Metaspace::ClassType) + - used_in_bytes(Metaspace::NonClassType); + // Running sum of space in all Metachunks that has been + // allocated to a Metaspace. This is used instead of + // iterating over all the classloaders + static size_t _allocated_capacity_words; + // Running sum of space in all Metachunks that have + // are being used for metadata. + static size_t _allocated_used_words; + + public: + // Decrement and increment _allocated_capacity_words + static void dec_capacity(size_t words); + static void inc_capacity(size_t words); + + // Decrement and increment _allocated_used_words + static void dec_used(size_t words); + static void inc_used(size_t words); + + // Total of space allocated to metadata in all Metaspaces. + // This sums the space used in each Metachunk by + // iterating over the classloader data graph + static size_t used_bytes_slow() { + return used_bytes_slow(Metaspace::ClassType) + + used_bytes_slow(Metaspace::NonClassType); } - // Total of available space in all Metaspaces - // Total of capacity allocated to all Metaspaces. This includes - // space in Metachunks not yet allocated and in the Metachunk - // freelist. - static size_t capacity_in_bytes() { - return capacity_in_bytes(Metaspace::ClassType) + - capacity_in_bytes(Metaspace::NonClassType); + // Used by MetaspaceCounters + static size_t free_chunks_total(); + static size_t free_chunks_total_in_bytes(); + + static size_t allocated_capacity_words() { + return _allocated_capacity_words; + } + static size_t allocated_capacity_bytes() { + return _allocated_capacity_words * BytesPerWord; + } + + static size_t allocated_used_words() { + return _allocated_used_words; + } + static size_t allocated_used_bytes() { + return _allocated_used_words * BytesPerWord; + } + + static size_t free_bytes(); + + // Total capacity in all Metaspaces + static size_t capacity_bytes_slow() { +#ifdef PRODUCT + // Use allocated_capacity_bytes() in PRODUCT instead of this function. + guarantee(false, "Should not call capacity_bytes_slow() in the PRODUCT"); +#endif + size_t class_capacity = capacity_bytes_slow(Metaspace::ClassType); + size_t non_class_capacity = capacity_bytes_slow(Metaspace::NonClassType); + assert(allocated_capacity_bytes() == class_capacity + non_class_capacity, + err_msg("bad accounting: allocated_capacity_bytes() " SIZE_FORMAT + " class_capacity + non_class_capacity " SIZE_FORMAT + " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT, + allocated_capacity_bytes(), class_capacity + non_class_capacity, + class_capacity, non_class_capacity)); + + return class_capacity + non_class_capacity; } // Total space reserved in all Metaspaces @@ -198,6 +261,11 @@ class MetaspaceAux : AllStatic { static void print_waste(outputStream* out); static void dump(outputStream* out); static void verify_free_chunks(); + // Checks that the values returned by allocated_capacity_bytes() and + // capacity_bytes_slow() are the same. + static void verify_capacity(); + static void verify_used(); + static void verify_metrics(); }; // Metaspace are deallocated when their class loader are GC'ed. @@ -232,7 +300,6 @@ class MetaspaceGC : AllStatic { public: static size_t capacity_until_GC() { return _capacity_until_GC; } - static size_t capacity_until_GC_in_bytes() { return _capacity_until_GC * BytesPerWord; } static void inc_capacity_until_GC(size_t v) { _capacity_until_GC += v; } static void dec_capacity_until_GC(size_t v) { _capacity_until_GC = _capacity_until_GC > v ? _capacity_until_GC - v : 0; diff --git a/hotspot/src/share/vm/memory/metaspaceCounters.cpp b/hotspot/src/share/vm/memory/metaspaceCounters.cpp index dc2f4f733aa..b2be29bca2f 100644 --- a/hotspot/src/share/vm/memory/metaspaceCounters.cpp +++ b/hotspot/src/share/vm/memory/metaspaceCounters.cpp @@ -29,6 +29,16 @@ MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL; +size_t MetaspaceCounters::calc_total_capacity() { + // The total capacity is the sum of + // 1) capacity of Metachunks in use by all Metaspaces + // 2) unused space at the end of each Metachunk + // 3) space in the freelist + size_t total_capacity = MetaspaceAux::allocated_capacity_bytes() + + MetaspaceAux::free_bytes() + MetaspaceAux::free_chunks_total_in_bytes(); + return total_capacity; +} + MetaspaceCounters::MetaspaceCounters() : _capacity(NULL), _used(NULL), @@ -36,8 +46,8 @@ MetaspaceCounters::MetaspaceCounters() : if (UsePerfData) { size_t min_capacity = MetaspaceAux::min_chunk_size(); size_t max_capacity = MetaspaceAux::reserved_in_bytes(); - size_t curr_capacity = MetaspaceAux::capacity_in_bytes(); - size_t used = MetaspaceAux::used_in_bytes(); + size_t curr_capacity = calc_total_capacity(); + size_t used = MetaspaceAux::allocated_used_bytes(); initialize(min_capacity, max_capacity, curr_capacity, used); } @@ -82,15 +92,13 @@ void MetaspaceCounters::initialize(size_t min_capacity, void MetaspaceCounters::update_capacity() { assert(UsePerfData, "Should not be called unless being used"); - assert(_capacity != NULL, "Should be initialized"); - size_t capacity_in_bytes = MetaspaceAux::capacity_in_bytes(); - _capacity->set_value(capacity_in_bytes); + size_t total_capacity = calc_total_capacity(); + _capacity->set_value(total_capacity); } void MetaspaceCounters::update_used() { assert(UsePerfData, "Should not be called unless being used"); - assert(_used != NULL, "Should be initialized"); - size_t used_in_bytes = MetaspaceAux::used_in_bytes(); + size_t used_in_bytes = MetaspaceAux::allocated_used_bytes(); _used->set_value(used_in_bytes); } diff --git a/hotspot/src/share/vm/memory/metaspaceCounters.hpp b/hotspot/src/share/vm/memory/metaspaceCounters.hpp index 4b6de646b60..46a9308888a 100644 --- a/hotspot/src/share/vm/memory/metaspaceCounters.hpp +++ b/hotspot/src/share/vm/memory/metaspaceCounters.hpp @@ -37,6 +37,7 @@ class MetaspaceCounters: public CHeapObj { size_t max_capacity, size_t curr_capacity, size_t used); + size_t calc_total_capacity(); public: MetaspaceCounters(); ~MetaspaceCounters(); diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 4f53114c6cd..5f0f152e975 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -376,18 +376,17 @@ void VM_PopulateDumpSharedSpace::doit() { const char* fmt = "%s space: %9d [ %4.1f%% of total] out of %9d bytes [%4.1f%% used] at " PTR_FORMAT; Metaspace* ro_space = _loader_data->ro_metaspace(); Metaspace* rw_space = _loader_data->rw_metaspace(); - const size_t BPW = BytesPerWord; // Allocated size of each space (may not be all occupied) - const size_t ro_alloced = ro_space->capacity_words(Metaspace::NonClassType) * BPW; - const size_t rw_alloced = rw_space->capacity_words(Metaspace::NonClassType) * BPW; + const size_t ro_alloced = ro_space->capacity_bytes_slow(Metaspace::NonClassType); + const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType); const size_t md_alloced = md_end-md_low; const size_t mc_alloced = mc_end-mc_low; const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced; // Occupied size of each space. - const size_t ro_bytes = ro_space->used_words(Metaspace::NonClassType) * BPW; - const size_t rw_bytes = rw_space->used_words(Metaspace::NonClassType) * BPW; + const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType); + const size_t rw_bytes = rw_space->used_bytes_slow(Metaspace::NonClassType); const size_t md_bytes = size_t(md_top - md_low); const size_t mc_bytes = size_t(mc_top - mc_low); diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index caef7ac7ad0..cd577d4b57e 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -218,14 +218,13 @@ public: static AlwaysTrueClosure always_true; void SharedHeap::process_weak_roots(OopClosure* root_closure, - CodeBlobClosure* code_roots, - OopClosure* non_root_closure) { + CodeBlobClosure* code_roots) { // Global (weak) JNI handles JNIHandles::weak_oops_do(&always_true, root_closure); CodeCache::blobs_do(code_roots); - StringTable::oops_do(root_closure); - } + StringTable::oops_do(root_closure); +} void SharedHeap::set_barrier_set(BarrierSet* bs) { _barrier_set = bs; diff --git a/hotspot/src/share/vm/memory/sharedHeap.hpp b/hotspot/src/share/vm/memory/sharedHeap.hpp index 2f8e2d910c2..b13bf15b846 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.hpp +++ b/hotspot/src/share/vm/memory/sharedHeap.hpp @@ -249,8 +249,7 @@ public: // JNI weak roots, the code cache, system dictionary, symbol table, // string table. void process_weak_roots(OopClosure* root_closure, - CodeBlobClosure* code_roots, - OopClosure* non_root_closure); + CodeBlobClosure* code_roots); // The functions below are helper functions that a subclass of // "SharedHeap" can use in the implementation of its virtual diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 90a2276cb93..a0849df9914 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -1270,7 +1270,7 @@ void Universe::print_heap_after_gc(outputStream* st, bool ignore_extended) { st->print_cr("}"); } -void Universe::verify(bool silent, VerifyOption option) { +void Universe::verify(VerifyOption option, const char* prefix, bool silent) { // The use of _verify_in_progress is a temporary work around for // 6320749. Don't bother with a creating a class to set and clear // it since it is only used in this method and the control flow is @@ -1287,11 +1287,12 @@ void Universe::verify(bool silent, VerifyOption option) { HandleMark hm; // Handles created during verification can be zapped _verify_count++; + if (!silent) gclog_or_tty->print(prefix); if (!silent) gclog_or_tty->print("[Verifying "); if (!silent) gclog_or_tty->print("threads "); Threads::verify(); + if (!silent) gclog_or_tty->print("heap "); heap()->verify(silent, option); - if (!silent) gclog_or_tty->print("syms "); SymbolTable::verify(); if (!silent) gclog_or_tty->print("strs "); diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 2bf0b653f58..48d32f71ed6 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -445,12 +445,12 @@ class Universe: AllStatic { // Debugging static bool verify_in_progress() { return _verify_in_progress; } - static void verify(bool silent, VerifyOption option); - static void verify(bool silent) { - verify(silent, VerifyOption_Default /* option */); + static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently); + static void verify(const char* prefix, bool silent = VerifySilently) { + verify(VerifyOption_Default, prefix, silent); } - static void verify() { - verify(false /* silent */); + static void verify(bool silent = VerifySilently) { + verify("", silent); } static int verify_count() { return _verify_count; } diff --git a/hotspot/src/share/vm/oops/klassVtable.cpp b/hotspot/src/share/vm/oops/klassVtable.cpp index 3f8609532fa..ebc6e0aea88 100644 --- a/hotspot/src/share/vm/oops/klassVtable.cpp +++ b/hotspot/src/share/vm/oops/klassVtable.cpp @@ -519,6 +519,9 @@ bool klassVtable::is_miranda_entry_at(int i) { // check if a method is a miranda method, given a class's methods table and it's super // the caller must make sure that the method belongs to an interface implemented by the class bool klassVtable::is_miranda(Method* m, Array * class_methods, Klass* super) { + if (m->is_static()) { + return false; + } Symbol* name = m->name(); Symbol* signature = m->signature(); if (InstanceKlass::find_method(class_methods, name, signature) == NULL) { diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index b06c081781a..74364c3bd6a 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -877,7 +877,7 @@ address Method::verified_code_entry() { debug_only(No_Safepoint_Verifier nsv;) nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code); if (code == NULL && UseCodeCacheFlushing) { - nmethod *saved_code = CodeCache::find_and_remove_saved_code(this); + nmethod *saved_code = CodeCache::reanimate_saved_code(this); if (saved_code != NULL) { methodHandle method(this); assert( ! saved_code->is_osr_method(), "should not get here for osr" ); diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 028020f51de..e2285916ce5 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3564,7 +3564,8 @@ void GraphKit::g1_write_barrier_pre(bool do_load, Node* no_ctrl = NULL; Node* no_base = __ top(); - Node* zero = __ ConI(0); + Node* zero = __ ConI(0); + Node* zeroX = __ ConX(0); float likely = PROB_LIKELY(0.999); float unlikely = PROB_UNLIKELY(0.999); @@ -3590,7 +3591,9 @@ void GraphKit::g1_write_barrier_pre(bool do_load, // if (!marking) __ if_then(marking, BoolTest::ne, zero); { - Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw); + BasicType index_bt = TypeX_X->basic_type(); + assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 PtrQueue::_index with wrong size."); + Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); if (do_load) { // load original value @@ -3603,22 +3606,16 @@ void GraphKit::g1_write_barrier_pre(bool do_load, Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); // is the queue for this thread full? - __ if_then(index, BoolTest::ne, zero, likely); { + __ if_then(index, BoolTest::ne, zeroX, likely); { // decrement the index - Node* next_index = __ SubI(index, __ ConI(sizeof(intptr_t))); - Node* next_indexX = next_index; -#ifdef _LP64 - // We could refine the type for what it's worth - // const TypeLong* lidxtype = TypeLong::make(CONST64(0), get_size_from_queue); - next_indexX = _gvn.transform( new (C) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) ); -#endif + Node* next_index = _gvn.transform(new (C) SubXNode(index, __ ConX(sizeof(intptr_t)))); // Now get the buffer location we will log the previous value into and store it - Node *log_addr = __ AddP(no_base, buffer, next_indexX); + Node *log_addr = __ AddP(no_base, buffer, next_index); __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw); // update the index - __ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw); + __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw); } __ else_(); { @@ -3645,26 +3642,21 @@ void GraphKit::g1_mark_card(IdealKit& ideal, Node* buffer, const TypeFunc* tf) { - Node* zero = __ ConI(0); + Node* zero = __ ConI(0); + Node* zeroX = __ ConX(0); Node* no_base = __ top(); BasicType card_bt = T_BYTE; // Smash zero into card. MUST BE ORDERED WRT TO STORE __ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw); // Now do the queue work - __ if_then(index, BoolTest::ne, zero); { + __ if_then(index, BoolTest::ne, zeroX); { - Node* next_index = __ SubI(index, __ ConI(sizeof(intptr_t))); - Node* next_indexX = next_index; -#ifdef _LP64 - // We could refine the type for what it's worth - // const TypeLong* lidxtype = TypeLong::make(CONST64(0), get_size_from_queue); - next_indexX = _gvn.transform( new (C) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) ); -#endif // _LP64 - Node* log_addr = __ AddP(no_base, buffer, next_indexX); + Node* next_index = _gvn.transform(new (C) SubXNode(index, __ ConX(sizeof(intptr_t)))); + Node* log_addr = __ AddP(no_base, buffer, next_index); __ store(__ ctrl(), log_addr, card_adr, T_ADDRESS, Compile::AliasIdxRaw); - __ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw); + __ store(__ ctrl(), index_adr, next_index, TypeX_X->basic_type(), Compile::AliasIdxRaw); } __ else_(); { __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), "g1_wb_post", card_adr, __ thread()); @@ -3725,7 +3717,7 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, // Now some values // Use ctrl to avoid hoisting these values past a safepoint, which could // potentially reset these fields in the JavaThread. - Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw); + Node* index = __ load(__ ctrl(), index_adr, TypeX_X, TypeX_X->basic_type(), Compile::AliasIdxRaw); Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); // Convert the store obj pointer to an int prior to doing math on it diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 8c42920995e..f5a1e08e169 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/debugInfo.hpp" #include "code/debugInfoRec.hpp" #include "compiler/compileBroker.hpp" @@ -41,8 +42,6 @@ #include "runtime/handles.inline.hpp" #include "utilities/xmlstream.hpp" -extern uint size_java_to_interp(); -extern uint reloc_java_to_interp(); extern uint size_exception_handler(); extern uint size_deopt_handler(); @@ -389,15 +388,15 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size MachNode *mach = nj->as_Mach(); blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding reloc_size += mach->reloc(); - if( mach->is_MachCall() ) { + if (mach->is_MachCall()) { MachCallNode *mcall = mach->as_MachCall(); // This destination address is NOT PC-relative mcall->method_set((intptr_t)mcall->entry_point()); - if( mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method ) { - stub_size += size_java_to_interp(); - reloc_size += reloc_java_to_interp(); + if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) { + stub_size += CompiledStaticCall::to_interp_stub_size(); + reloc_size += CompiledStaticCall::reloc_to_interp_stub(); } } else if (mach->is_MachSafePoint()) { // If call/safepoint are adjacent, account for possible diff --git a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.cpp b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.cpp index aec2b410412..9300334729f 100644 --- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.cpp +++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.cpp @@ -513,6 +513,11 @@ void JvmtiClassFileReconstituter::write_method_info(methodHandle method) { AnnotationArray* param_anno = method->parameter_annotations(); AnnotationArray* default_anno = method->annotation_default(); + // skip generated default interface methods + if (method->is_overpass()) { + return; + } + write_u2(access_flags.get_flags() & JVM_RECOGNIZED_METHOD_MODIFIERS); write_u2(const_method->name_index()); write_u2(const_method->signature_index()); @@ -619,8 +624,19 @@ void JvmtiClassFileReconstituter::write_method_infos() { HandleMark hm(thread()); Array * methods = ikh()->methods(); int num_methods = methods->length(); + int num_overpass = 0; - write_u2(num_methods); + // count the generated default interface methods + // these will not be re-created by write_method_info + // and should not be included in the total count + for (int index = 0; index < num_methods; index++) { + Method* method = methods->at(index); + if (method->is_overpass()) { + num_overpass++; + } + } + + write_u2(num_methods - num_overpass); if (JvmtiExport::can_maintain_original_method_order()) { int index; int original_index; diff --git a/hotspot/src/share/vm/prims/perf.cpp b/hotspot/src/share/vm/prims/perf.cpp index e0326f77484..6318d9d6652 100644 --- a/hotspot/src/share/vm/prims/perf.cpp +++ b/hotspot/src/share/vm/prims/perf.cpp @@ -142,20 +142,20 @@ PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, } switch(variability) { - case 1: /* V_Constant */ + case PerfData::V_Constant: pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf, (PerfData::Units)units, value, CHECK_NULL); break; - case 2: /* V_Variable */ - pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf, + case PerfData::V_Monotonic: + pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf, (PerfData::Units)units, value, CHECK_NULL); break; - case 3: /* V_Monotonic Counter */ - pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf, + case PerfData::V_Variable: + pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf, (PerfData::Units)units, value, CHECK_NULL); break; diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index ab21a80d7c7..10e738fca41 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -439,9 +439,29 @@ JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass)) instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass()); Handle loader(ikh->class_loader()); if (loader.is_null()) { + ResourceMark rm; ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI - jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0])); - if (result == 0) { + bool result = true; + // one by one registration natives for exception catching + jclass exceptionKlass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string()); + for (int i = 0, n = sizeof(methods) / sizeof(methods[0]); i < n; ++i) { + if (env->RegisterNatives(wbclass, methods + i, 1) != 0) { + result = false; + if (env->ExceptionCheck() && env->IsInstanceOf(env->ExceptionOccurred(), exceptionKlass)) { + // j.l.NoSuchMethodError is thrown when a method can't be found or a method is not native + // ignoring the exception + tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", methods[i].name, methods[i].signature); + env->ExceptionClear(); + } else { + // register is failed w/o exception or w/ unexpected exception + tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", methods[i].name, methods[i].signature); + env->UnregisterNatives(wbclass); + break; + } + } + } + + if (result) { WhiteBox::set_used(); } } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 236a1272624..b2ff4e5f9d2 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2224,6 +2224,55 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) { return JNI_OK; } +// Checks if name in command-line argument -agent{lib,path}:name[=options] +// represents a valid HPROF of JDWP agent. is_path==true denotes that we +// are dealing with -agentpath (case where name is a path), otherwise with +// -agentlib +bool valid_hprof_or_jdwp_agent(char *name, bool is_path) { + char *_name; + const char *_hprof = "hprof", *_jdwp = "jdwp"; + size_t _len_hprof, _len_jdwp, _len_prefix; + + if (is_path) { + if ((_name = strrchr(name, (int) *os::file_separator())) == NULL) { + return false; + } + + _name++; // skip past last path separator + _len_prefix = strlen(JNI_LIB_PREFIX); + + if (strncmp(_name, JNI_LIB_PREFIX, _len_prefix) != 0) { + return false; + } + + _name += _len_prefix; + _len_hprof = strlen(_hprof); + _len_jdwp = strlen(_jdwp); + + if (strncmp(_name, _hprof, _len_hprof) == 0) { + _name += _len_hprof; + } + else if (strncmp(_name, _jdwp, _len_jdwp) == 0) { + _name += _len_jdwp; + } + else { + return false; + } + + if (strcmp(_name, JNI_LIB_SUFFIX) != 0) { + return false; + } + + return true; + } + + if (strcmp(name, _hprof) == 0 || strcmp(name, _jdwp) == 0) { + return true; + } + + return false; +} + jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, @@ -2322,7 +2371,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(pos + 1) + 1, mtInternal), pos + 1); } #if !INCLUDE_JVMTI - if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { + if (valid_hprof_or_jdwp_agent(name, is_absolute_path)) { jio_fprintf(defaultStream::error_stream(), "Profiling and debugging agents are not supported in this VM\n"); return JNI_ERR; diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.cpp b/hotspot/src/share/vm/runtime/compilationPolicy.cpp index 11607385abd..8fff9586b5b 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp @@ -109,6 +109,9 @@ bool CompilationPolicy::must_be_compiled(methodHandle m, int comp_level) { // Returns true if m is allowed to be compiled bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) { + // allow any levels for WhiteBox + assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level"); + if (m->is_abstract()) return false; if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; @@ -122,7 +125,13 @@ bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) { return false; } if (comp_level == CompLevel_all) { - return !m->is_not_compilable(CompLevel_simple) && !m->is_not_compilable(CompLevel_full_optimization); + if (TieredCompilation) { + // enough to be compilable at any level for tiered + return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization); + } else { + // must be compilable at available level for non-tiered + return !m->is_not_compilable(CompLevel_highest_tier); + } } else if (is_compile(comp_level)) { return !m->is_not_compilable(comp_level); } @@ -436,7 +445,7 @@ void SimpleCompPolicy::method_invocation_event(methodHandle m, JavaThread* threa reset_counter_for_invocation_event(m); const char* comment = "count"; - if (is_compilation_enabled() && can_be_compiled(m)) { + if (is_compilation_enabled() && can_be_compiled(m, comp_level)) { nmethod* nm = m->code(); if (nm == NULL ) { CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, comment, thread); @@ -449,7 +458,7 @@ void SimpleCompPolicy::method_back_branch_event(methodHandle m, int bci, JavaThr const int hot_count = m->backedge_count(); const char* comment = "backedge_count"; - if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) { + if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) { CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread); NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));) } @@ -467,7 +476,7 @@ void StackWalkCompPolicy::method_invocation_event(methodHandle m, JavaThread* th reset_counter_for_invocation_event(m); const char* comment = "count"; - if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m)) { + if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m, comp_level)) { ResourceMark rm(thread); frame fr = thread->last_frame(); assert(fr.is_interpreted_frame(), "must be interpreted"); @@ -505,7 +514,7 @@ void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int bci, Java const int hot_count = m->backedge_count(); const char* comment = "backedge_count"; - if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) { + if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) { CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread); NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));) } @@ -600,7 +609,7 @@ RFrame* StackWalkCompPolicy::findTopInlinableFrame(GrowableArray * stack // If the caller method is too big or something then we do not want to // compile it just to inline a method - if (!can_be_compiled(next_m)) { + if (!can_be_compiled(next_m, CompLevel_any)) { msg = "caller cannot be compiled"; break; } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 011112ce9a5..f927120dcb4 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2123,6 +2123,9 @@ class CommandLineFlags { product(intx, PrefetchFieldsAhead, -1, \ "How many fields ahead to prefetch in oop scan (<= 0 means off)") \ \ + diagnostic(bool, VerifySilently, false, \ + "Don't print print the verification progress") \ + \ diagnostic(bool, VerifyDuringStartup, false, \ "Verify memory system before executing any Java code " \ "during VM initialization") \ @@ -3179,6 +3182,9 @@ class CommandLineFlags { product(uintx, CodeCacheFlushingMinimumFreeSpace, 1500*K, \ "When less than X space left, start code cache cleaning") \ \ + product(uintx, CodeCacheFlushingFraction, 2, \ + "Fraction of the code cache that is flushed when full") \ + \ /* interpreter debugging */ \ develop(intx, BinarySwitchThreshold, 5, \ "Minimal number of lookupswitch entries for rewriting to binary " \ @@ -3223,8 +3229,9 @@ class CommandLineFlags { develop(bool, ReplayCompiles, false, \ "Enable replay of compilations from ReplayDataFile") \ \ - develop(ccstr, ReplayDataFile, "replay.txt", \ - "file containing compilation replay information") \ + product(ccstr, ReplayDataFile, NULL, \ + "File containing compilation replay information" \ + "[default: ./replay_pid%p.log] (%p replaced with pid)") \ \ develop(intx, ReplaySuppressInitializers, 2, \ "Controls handling of class initialization during replay" \ @@ -3237,8 +3244,8 @@ class CommandLineFlags { develop(bool, ReplayIgnoreInitErrors, false, \ "Ignore exceptions thrown during initialization for replay") \ \ - develop(bool, DumpReplayDataOnError, true, \ - "record replay data for crashing compiler threads") \ + product(bool, DumpReplayDataOnError, true, \ + "Record replay data for crashing compiler threads") \ \ product(bool, CICompilerCountPerCPU, false, \ "1 compiler thread for log(N CPUs)") \ @@ -3247,7 +3254,9 @@ class CommandLineFlags { "Fire OutOfMemoryErrors throughout CI for testing the compiler " \ "(non-negative value throws OOM after this many CI accesses " \ "in each compile)") \ - \ + notproduct(intx, CICrashAt, -1, \ + "id of compilation to trigger assert in compiler thread for " \ + "the purpose of testing, e.g. generation of replay data") \ notproduct(bool, CIObjectFactoryVerify, false, \ "enable potentially expensive verification in ciObjectFactory") \ \ diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 82f45df60b8..2ea7b8b7546 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -454,6 +454,7 @@ class os: AllStatic { // File i/o operations static const int default_file_open_flags(); static int open(const char *path, int oflag, int mode); + static FILE* open(int fd, const char* mode); static int close(int fd); static jlong lseek(int fd, jlong offset, int whence); static char* native_path(char *path); @@ -477,7 +478,7 @@ class os: AllStatic { static const char* dll_file_extension(); static const char* get_temp_directory(); - static const char* get_current_directory(char *buf, int buflen); + static const char* get_current_directory(char *buf, size_t buflen); // Builds a platform-specific full library path given a ld path and lib name // Returns true if buffer contains full path to existing file, false otherwise diff --git a/hotspot/src/share/vm/runtime/serviceThread.cpp b/hotspot/src/share/vm/runtime/serviceThread.cpp index 3c121e96219..66d4572522f 100644 --- a/hotspot/src/share/vm/runtime/serviceThread.cpp +++ b/hotspot/src/share/vm/runtime/serviceThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ #include "runtime/mutexLocker.hpp" #include "prims/jvmtiImpl.hpp" #include "services/gcNotifier.hpp" +#include "services/diagnosticArgument.hpp" +#include "services/diagnosticFramework.hpp" ServiceThread* ServiceThread::_instance = NULL; @@ -83,6 +85,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool sensors_changed = false; bool has_jvmti_events = false; bool has_gc_notification_event = false; + bool has_dcmd_notification_event = false; JvmtiDeferredEvent jvmti_event; { // Need state transition ThreadBlockInVM so that this thread @@ -98,7 +101,8 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); while (!(sensors_changed = LowMemoryDetector::has_pending_requests()) && !(has_jvmti_events = JvmtiDeferredEventQueue::has_events()) && - !(has_gc_notification_event = GCNotifier::has_event())) { + !(has_gc_notification_event = GCNotifier::has_event()) && + !(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification())) { // wait until one of the sensors has pending requests, or there is a // pending JVMTI event or JMX GC notification to post Service_lock->wait(Mutex::_no_safepoint_check_flag); @@ -120,6 +124,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { if(has_gc_notification_event) { GCNotifier::sendNotification(CHECK); } + + if(has_dcmd_notification_event) { + DCmdFactory::send_notification(CHECK); + } } } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 09a0b65b958..57af1f3bda7 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1316,12 +1316,6 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* thread)) assert(stub_frame.is_runtime_frame(), "sanity check"); frame caller_frame = stub_frame.sender(®_map); - // MethodHandle invokes don't have a CompiledIC and should always - // simply redispatch to the callee_target. - address sender_pc = caller_frame.pc(); - CodeBlob* sender_cb = caller_frame.cb(); - nmethod* sender_nm = sender_cb->as_nmethod_or_null(); - if (caller_frame.is_interpreted_frame() || caller_frame.is_entry_frame()) { Method* callee = thread->callee_target(); diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp index 0752fac9d79..ad4c27cf29e 100644 --- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp @@ -154,9 +154,10 @@ void SimpleThresholdPolicy::set_carry_if_necessary(InvocationCounter *counter) { // Set carry flags on the counters if necessary void SimpleThresholdPolicy::handle_counter_overflow(Method* method) { MethodCounters *mcs = method->method_counters(); - assert(mcs != NULL, ""); - set_carry_if_necessary(mcs->invocation_counter()); - set_carry_if_necessary(mcs->backedge_counter()); + if (mcs != NULL) { + set_carry_if_necessary(mcs->invocation_counter()); + set_carry_if_necessary(mcs->backedge_counter()); + } MethodData* mdo = method->method_data(); if (mdo != NULL) { set_carry_if_necessary(mdo->invocation_counter()); diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp index 7c516dfe951..2921b2544b7 100644 --- a/hotspot/src/share/vm/runtime/sweeper.cpp +++ b/hotspot/src/share/vm/runtime/sweeper.cpp @@ -136,13 +136,12 @@ volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progre jint NMethodSweeper::_locked_seen = 0; jint NMethodSweeper::_not_entrant_seen_on_stack = 0; -bool NMethodSweeper::_rescan = false; -bool NMethodSweeper::_do_sweep = false; -bool NMethodSweeper::_was_full = false; -jint NMethodSweeper::_advise_to_sweep = 0; -jlong NMethodSweeper::_last_was_full = 0; -uint NMethodSweeper::_highest_marked = 0; -long NMethodSweeper::_was_full_traversal = 0; +bool NMethodSweeper::_resweep = false; +jint NMethodSweeper::_flush_token = 0; +jlong NMethodSweeper::_last_full_flush_time = 0; +int NMethodSweeper::_highest_marked = 0; +int NMethodSweeper::_dead_compile_ids = 0; +long NMethodSweeper::_last_flush_traversal_id = 0; class MarkActivationClosure: public CodeBlobClosure { public: @@ -155,20 +154,16 @@ public: }; static MarkActivationClosure mark_activation_closure; +bool NMethodSweeper::sweep_in_progress() { + return (_current != NULL); +} + void NMethodSweeper::scan_stacks() { assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint"); if (!MethodFlushing) return; - _do_sweep = true; // No need to synchronize access, since this is always executed at a - // safepoint. If we aren't in the middle of scan and a rescan - // hasn't been requested then just return. If UseCodeCacheFlushing is on and - // code cache flushing is in progress, don't skip sweeping to help make progress - // clearing space in the code cache. - if ((_current == NULL && !_rescan) && !(UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs())) { - _do_sweep = false; - return; - } + // safepoint. // Make sure CompiledIC_lock in unlocked, since we might update some // inline caches. If it is, we just bail-out and try later. @@ -176,7 +171,7 @@ void NMethodSweeper::scan_stacks() { // Check for restart assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid"); - if (_current == NULL) { + if (!sweep_in_progress() && _resweep) { _seen = 0; _invocations = NmethodSweepFraction; _current = CodeCache::first_nmethod(); @@ -187,39 +182,30 @@ void NMethodSweeper::scan_stacks() { Threads::nmethods_do(&mark_activation_closure); // reset the flags since we started a scan from the beginning. - _rescan = false; + _resweep = false; _locked_seen = 0; _not_entrant_seen_on_stack = 0; } if (UseCodeCacheFlushing) { - if (!CodeCache::needs_flushing()) { - // scan_stacks() runs during a safepoint, no race with setters - _advise_to_sweep = 0; + // only allow new flushes after the interval is complete. + jlong now = os::javaTimeMillis(); + jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; + jlong curr_interval = now - _last_full_flush_time; + if (curr_interval > max_interval) { + _flush_token = 0; } - if (was_full()) { - // There was some progress so attempt to restart the compiler - jlong now = os::javaTimeMillis(); - jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; - jlong curr_interval = now - _last_was_full; - if ((!CodeCache::needs_flushing()) && (curr_interval > max_interval)) { - CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); - set_was_full(false); - - // Update the _last_was_full time so we can tell how fast the - // code cache is filling up - _last_was_full = os::javaTimeMillis(); - - log_sweep("restart_compiler"); - } + if (!CodeCache::needs_flushing() && !CompileBroker::should_compile_new_jobs()) { + CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); + log_sweep("restart_compiler"); } } } void NMethodSweeper::possibly_sweep() { assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode"); - if ((!MethodFlushing) || (!_do_sweep)) return; + if (!MethodFlushing || !sweep_in_progress()) return; if (_invocations > 0) { // Only one thread at a time will sweep @@ -253,6 +239,14 @@ void NMethodSweeper::sweep_code_cache() { tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); } + if (!CompileBroker::should_compile_new_jobs()) { + // If we have turned off compilations we might as well do full sweeps + // in order to reach the clean state faster. Otherwise the sleeping compiler + // threads will slow down sweeping. After a few iterations the cache + // will be clean and sweeping stops (_resweep will not be set) + _invocations = 1; + } + // We want to visit all nmethods after NmethodSweepFraction // invocations so divide the remaining number of nmethods by the // remaining number of invocations. This is only an estimate since @@ -296,7 +290,7 @@ void NMethodSweeper::sweep_code_cache() { assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache"); - if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) { + if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) { // we've completed a scan without making progress but there were // nmethods we were unable to process either because they were // locked or were still on stack. We don't have to aggresively @@ -318,6 +312,13 @@ void NMethodSweeper::sweep_code_cache() { if (_invocations == 1) { log_sweep("finished"); } + + // Sweeper is the only case where memory is released, + // check here if it is time to restart the compiler. + if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs() && !CodeCache::needs_flushing()) { + CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); + log_sweep("restart_compiler"); + } } class NMethodMarker: public StackObj { @@ -392,7 +393,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); } nm->mark_for_reclamation(); - _rescan = true; + _resweep = true; SWEEP(nm); } } else if (nm->is_not_entrant()) { @@ -403,7 +404,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); } nm->make_zombie(); - _rescan = true; + _resweep = true; SWEEP(nm); } else { // Still alive, clean up its inline caches @@ -425,16 +426,15 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { release_nmethod(nm); } else { nm->make_zombie(); - _rescan = true; + _resweep = true; SWEEP(nm); } } else { assert(nm->is_alive(), "should be alive"); if (UseCodeCacheFlushing) { - if ((nm->method()->code() != nm) && !(nm->is_locked_by_vm()) && !(nm->is_osr_method()) && - (_traversals > _was_full_traversal+2) && (((uint)nm->compile_id()) < _highest_marked) && - CodeCache::needs_flushing()) { + if (nm->is_speculatively_disconnected() && !nm->is_locked_by_vm() && !nm->is_osr_method() && + (_traversals > _last_flush_traversal_id + 2) && (nm->compile_id() < _highest_marked)) { // This method has not been called since the forced cleanup happened nm->make_not_entrant(); } @@ -457,41 +457,27 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { // _code field is restored and the Method*/nmethod // go back to their normal state. void NMethodSweeper::handle_full_code_cache(bool is_full) { - // Only the first one to notice can advise us to start early cleaning - if (!is_full){ - jint old = Atomic::cmpxchg( 1, &_advise_to_sweep, 0 ); - if (old != 0) { - return; - } - } if (is_full) { // Since code cache is full, immediately stop new compiles - bool did_set = CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation); - if (!did_set) { - // only the first to notice can start the cleaning, - // others will go back and block - return; + if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) { + log_sweep("disable_compiler"); } - set_was_full(true); + } - // If we run out within MinCodeCacheFlushingInterval of the last unload time, give up - jlong now = os::javaTimeMillis(); - jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000; - jlong curr_interval = now - _last_was_full; - if (curr_interval < max_interval) { - _rescan = true; - log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'", - curr_interval/1000); - return; - } + // Make sure only one thread can flush + // The token is reset after CodeCacheMinimumFlushInterval in scan stacks, + // no need to check the timeout here. + jint old = Atomic::cmpxchg( 1, &_flush_token, 0 ); + if (old != 0) { + return; } VM_HandleFullCodeCache op(is_full); VMThread::execute(&op); - // rescan again as soon as possible - _rescan = true; + // resweep again as soon as possible + _resweep = true; } void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { @@ -500,62 +486,64 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) { debug_only(jlong start = os::javaTimeMillis();) - if ((!was_full()) && (is_full)) { - if (!CodeCache::needs_flushing()) { - log_sweep("restart_compiler"); - CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation); - return; - } - } - // Traverse the code cache trying to dump the oldest nmethods - uint curr_max_comp_id = CompileBroker::get_compilation_id(); - uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked; + int curr_max_comp_id = CompileBroker::get_compilation_id(); + int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids; + log_sweep("start_cleaning"); nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); jint disconnected = 0; jint made_not_entrant = 0; + jint nmethod_count = 0; + while ((nm != NULL)){ - uint curr_comp_id = nm->compile_id(); + int curr_comp_id = nm->compile_id(); // OSR methods cannot be flushed like this. Also, don't flush native methods // since they are part of the JDK in most cases - if (nm->is_in_use() && (!nm->is_osr_method()) && (!nm->is_locked_by_vm()) && - (!nm->is_native_method()) && ((curr_comp_id < flush_target))) { + if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method()) { - if ((nm->method()->code() == nm)) { - // This method has not been previously considered for - // unloading or it was restored already - CodeCache::speculatively_disconnect(nm); - disconnected++; - } else if (nm->is_speculatively_disconnected()) { - // This method was previously considered for preemptive unloading and was not called since then - CompilationPolicy::policy()->delay_compilation(nm->method()); - nm->make_not_entrant(); - made_not_entrant++; - } + // only count methods that can be speculatively disconnected + nmethod_count++; - if (curr_comp_id > _highest_marked) { - _highest_marked = curr_comp_id; + if (nm->is_in_use() && (curr_comp_id < flush_target)) { + if ((nm->method()->code() == nm)) { + // This method has not been previously considered for + // unloading or it was restored already + CodeCache::speculatively_disconnect(nm); + disconnected++; + } else if (nm->is_speculatively_disconnected()) { + // This method was previously considered for preemptive unloading and was not called since then + CompilationPolicy::policy()->delay_compilation(nm->method()); + nm->make_not_entrant(); + made_not_entrant++; + } + + if (curr_comp_id > _highest_marked) { + _highest_marked = curr_comp_id; + } } } nm = CodeCache::alive_nmethod(CodeCache::next(nm)); } + // remember how many compile_ids wheren't seen last flush. + _dead_compile_ids = curr_max_comp_id - nmethod_count; + log_sweep("stop_cleaning", "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'", disconnected, made_not_entrant); // Shut off compiler. Sweeper will start over with a new stack scan and // traversal cycle and turn it back on if it clears enough space. - if (was_full()) { - _last_was_full = os::javaTimeMillis(); - CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation); + if (is_full) { + _last_full_flush_time = os::javaTimeMillis(); } // After two more traversals the sweeper will get rid of unrestored nmethods - _was_full_traversal = _traversals; + _last_flush_traversal_id = _traversals; + _resweep = true; #ifdef ASSERT jlong end = os::javaTimeMillis(); if(PrintMethodFlushing && Verbose) { diff --git a/hotspot/src/share/vm/runtime/sweeper.hpp b/hotspot/src/share/vm/runtime/sweeper.hpp index f6e9bc3091c..ff63029f1cf 100644 --- a/hotspot/src/share/vm/runtime/sweeper.hpp +++ b/hotspot/src/share/vm/runtime/sweeper.hpp @@ -35,26 +35,29 @@ class NMethodSweeper : public AllStatic { static nmethod* _current; // Current nmethod static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache - static volatile int _invocations; // No. of invocations left until we are completed with this pass - static volatile int _sweep_started; // Flag to control conc sweeper + static volatile int _invocations; // No. of invocations left until we are completed with this pass + static volatile int _sweep_started; // Flag to control conc sweeper - static bool _rescan; // Indicates that we should do a full rescan of the - // of the code cache looking for work to do. - static bool _do_sweep; // Flag to skip the conc sweep if no stack scan happened - static int _locked_seen; // Number of locked nmethods encountered during the scan + //The following are reset in scan_stacks and synchronized by the safepoint + static bool _resweep; // Indicates that a change has happend and we want another sweep, + // always checked and reset at a safepoint so memory will be in sync. + static int _locked_seen; // Number of locked nmethods encountered during the scan static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack + static jint _flush_token; // token that guards method flushing, making sure it is executed only once. - static bool _was_full; // remember if we did emergency unloading - static jint _advise_to_sweep; // flag to indicate code cache getting full - static jlong _last_was_full; // timestamp of last emergency unloading - static uint _highest_marked; // highest compile id dumped at last emergency unloading - static long _was_full_traversal; // trav number at last emergency unloading + // These are set during a flush, a VM-operation + static long _last_flush_traversal_id; // trav number at last flush unloading + static jlong _last_full_flush_time; // timestamp of last emergency unloading + + // These are synchronized by the _sweep_started token + static int _highest_marked; // highest compile id dumped at last emergency unloading + static int _dead_compile_ids; // number of compile ids that where not in the cache last flush static void process_nmethod(nmethod *nm); - static void release_nmethod(nmethod* nm); static void log_sweep(const char* msg, const char* format = NULL, ...); + static bool sweep_in_progress(); public: static long traversal_count() { return _traversals; } @@ -71,17 +74,14 @@ class NMethodSweeper : public AllStatic { static void possibly_sweep(); // Compiler threads call this to sweep static void notify(nmethod* nm) { - // Perform a full scan of the code cache from the beginning. No + // Request a new sweep of the code cache from the beginning. No // need to synchronize the setting of this flag since it only // changes to false at safepoint so we can never overwrite it with false. - _rescan = true; + _resweep = true; } static void handle_full_code_cache(bool is_full); // Called by compilers who fail to allocate static void speculative_disconnect_nmethods(bool was_full); // Called by vm op to deal with alloc failure - - static void set_was_full(bool state) { _was_full = state; } - static bool was_full() { return _was_full; } }; #endif // SHARE_VM_RUNTIME_SWEEPER_HPP diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index cf0297de099..7c3e256e2ef 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -3447,7 +3447,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { assert (Universe::is_fully_initialized(), "not initialized"); if (VerifyDuringStartup) { - VM_Verify verify_op(false /* silent */); // make sure we're starting with a clean slate + // Make sure we're starting with a clean slate. + VM_Verify verify_op; VMThread::execute(&verify_op); } diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index dffb588dbae..ba68e887e17 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -60,72 +60,6 @@ ReservedSpace::ReservedSpace(size_t size, size_t alignment, initialize(size, alignment, large, NULL, 0, executable); } -char * -ReservedSpace::align_reserved_region(char* addr, const size_t len, - const size_t prefix_size, - const size_t prefix_align, - const size_t suffix_size, - const size_t suffix_align) -{ - assert(addr != NULL, "sanity"); - const size_t required_size = prefix_size + suffix_size; - assert(len >= required_size, "len too small"); - - const size_t s = size_t(addr); - const size_t beg_ofs = (s + prefix_size) & (suffix_align - 1); - const size_t beg_delta = beg_ofs == 0 ? 0 : suffix_align - beg_ofs; - - if (len < beg_delta + required_size) { - return NULL; // Cannot do proper alignment. - } - const size_t end_delta = len - (beg_delta + required_size); - - if (beg_delta != 0) { - os::release_memory(addr, beg_delta); - } - - if (end_delta != 0) { - char* release_addr = (char*) (s + beg_delta + required_size); - os::release_memory(release_addr, end_delta); - } - - return (char*) (s + beg_delta); -} - -char* ReservedSpace::reserve_and_align(const size_t reserve_size, - const size_t prefix_size, - const size_t prefix_align, - const size_t suffix_size, - const size_t suffix_align) -{ - assert(reserve_size > prefix_size + suffix_size, "should not be here"); - - char* raw_addr = os::reserve_memory(reserve_size, NULL, prefix_align); - if (raw_addr == NULL) return NULL; - - char* result = align_reserved_region(raw_addr, reserve_size, prefix_size, - prefix_align, suffix_size, - suffix_align); - if (result == NULL && !os::release_memory(raw_addr, reserve_size)) { - fatal("os::release_memory failed"); - } - -#ifdef ASSERT - if (result != NULL) { - const size_t raw = size_t(raw_addr); - const size_t res = size_t(result); - assert(res >= raw, "alignment decreased start addr"); - assert(res + prefix_size + suffix_size <= raw + reserve_size, - "alignment increased end addr"); - assert((res & (prefix_align - 1)) == 0, "bad alignment of prefix"); - assert(((res + prefix_size) & (suffix_align - 1)) == 0, - "bad alignment of suffix"); - } -#endif - - return result; -} - // Helper method. static bool failed_to_reserve_as_requested(char* base, char* requested_address, const size_t size, bool special) @@ -155,92 +89,6 @@ static bool failed_to_reserve_as_requested(char* base, char* requested_address, return true; } -ReservedSpace::ReservedSpace(const size_t suffix_size, - const size_t suffix_align, - char* requested_address, - const size_t noaccess_prefix) -{ - assert(suffix_size != 0, "sanity"); - assert(suffix_align != 0, "sanity"); - assert((suffix_size & (suffix_align - 1)) == 0, - "suffix_size not divisible by suffix_align"); - - // Assert that if noaccess_prefix is used, it is the same as prefix_align. - // Add in noaccess_prefix to prefix - const size_t adjusted_prefix_size = noaccess_prefix; - const size_t size = adjusted_prefix_size + suffix_size; - - // On systems where the entire region has to be reserved and committed up - // front, the compound alignment normally done by this method is unnecessary. - const bool try_reserve_special = UseLargePages && - suffix_align == os::large_page_size(); - if (!os::can_commit_large_page_memory() && try_reserve_special) { - initialize(size, suffix_align, true, requested_address, noaccess_prefix, - false); - return; - } - - _base = NULL; - _size = 0; - _alignment = 0; - _special = false; - _noaccess_prefix = 0; - _executable = false; - - // Optimistically try to reserve the exact size needed. - char* addr; - if (requested_address != 0) { - requested_address -= noaccess_prefix; // adjust address - assert(requested_address != NULL, "huge noaccess prefix?"); - addr = os::attempt_reserve_memory_at(size, requested_address); - if (failed_to_reserve_as_requested(addr, requested_address, size, false)) { - // OS ignored requested address. Try different address. - addr = NULL; - } - } else { - addr = os::reserve_memory(size, NULL, suffix_align); - } - if (addr == NULL) return; - - // Check whether the result has the needed alignment - const size_t ofs = (size_t(addr) + adjusted_prefix_size) & (suffix_align - 1); - if (ofs != 0) { - // Wrong alignment. Release, allocate more space and do manual alignment. - // - // On most operating systems, another allocation with a somewhat larger size - // will return an address "close to" that of the previous allocation. The - // result is often the same address (if the kernel hands out virtual - // addresses from low to high), or an address that is offset by the increase - // in size. Exploit that to minimize the amount of extra space requested. - if (!os::release_memory(addr, size)) { - fatal("os::release_memory failed"); - } - - const size_t extra = MAX2(ofs, suffix_align - ofs); - addr = reserve_and_align(size + extra, adjusted_prefix_size, suffix_align, - suffix_size, suffix_align); - if (addr == NULL) { - // Try an even larger region. If this fails, address space is exhausted. - addr = reserve_and_align(size + suffix_align, adjusted_prefix_size, - suffix_align, suffix_size, suffix_align); - } - - if (requested_address != 0 && - failed_to_reserve_as_requested(addr, requested_address, size, false)) { - // As a result of the alignment constraints, the allocated addr differs - // from the requested address. Return back to the caller who can - // take remedial action (like try again without a requested address). - assert(_base == NULL, "should be"); - return; - } - } - - _base = addr; - _size = size; - _alignment = suffix_align; - _noaccess_prefix = noaccess_prefix; -} - void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* requested_address, const size_t noaccess_prefix, @@ -476,20 +324,6 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, protect_noaccess_prefix(size); } -ReservedHeapSpace::ReservedHeapSpace(const size_t heap_space_size, - const size_t alignment, - char* requested_address) : - ReservedSpace(heap_space_size, alignment, - requested_address, - (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && - Universe::narrow_oop_use_implicit_null_checks()) ? - lcm(os::vm_page_size(), alignment) : 0) { - if (base() > 0) { - MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); - } - protect_noaccess_prefix(heap_space_size); -} - // Reserve space for code segment. Same as Java heap only we mark this as // executable. ReservedCodeSpace::ReservedCodeSpace(size_t r_size, diff --git a/hotspot/src/share/vm/runtime/virtualspace.hpp b/hotspot/src/share/vm/runtime/virtualspace.hpp index 934efb88a14..0a959e900a0 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.hpp +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp @@ -47,28 +47,6 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { 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 - // resulting region, or NULL on failure. - // - // The region is logically divided into a prefix and a suffix. The prefix - // starts at the result address, which is aligned to prefix_align. The suffix - // starts at result address + prefix_size, which is aligned to suffix_align. - // The total size of the result region is size prefix_size + suffix_size. - char* align_reserved_region(char* addr, const size_t len, - const size_t prefix_size, - const size_t prefix_align, - const size_t suffix_size, - const size_t suffix_align); - - // Reserve memory, call align_reserved_region() to alignment it and return the - // result. - char* reserve_and_align(const size_t reserve_size, - const size_t prefix_size, - const size_t prefix_align, - const size_t suffix_size, - const size_t suffix_align); - protected: // Create protection page at the beginning of the space. void protect_noaccess_prefix(const size_t size); @@ -79,9 +57,6 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { ReservedSpace(size_t size, size_t alignment, bool large, char* requested_address = NULL, const size_t noaccess_prefix = 0); - ReservedSpace(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 @@ -128,8 +103,6 @@ public: // Constructor 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, - char* requested_address); }; // Class encapsulating behavior specific memory space for Code diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 609eb525b6c..b281d7ac39a 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -828,6 +828,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; nonstatic_field(nmethod, _lock_count, jint) \ nonstatic_field(nmethod, _stack_traversal_mark, long) \ nonstatic_field(nmethod, _compile_id, int) \ + nonstatic_field(nmethod, _comp_level, int) \ nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index 8cfc2700835..8c321721e27 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -293,7 +293,7 @@ void VMThread::run() { os::check_heap(); // Silent verification so as not to pollute normal output, // unless we really asked for it. - Universe::verify(!(PrintGCDetails || Verbose)); + Universe::verify(!(PrintGCDetails || Verbose) || VerifySilently); } CompileBroker::set_should_block(); diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index c1fc53607c0..9d79b2c0d7c 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -302,7 +302,7 @@ class VM_Verify: public VM_Operation { private: bool _silent; public: - VM_Verify(bool silent) : _silent(silent) {} + VM_Verify(bool silent = VerifySilently) : _silent(silent) {} VMOp_Type type() const { return VMOp_Verify; } void doit(); }; diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp index da93859bb94..564b20f4b3b 100644 --- a/hotspot/src/share/vm/services/attachListener.cpp +++ b/hotspot/src/share/vm/services/attachListener.cpp @@ -157,7 +157,7 @@ static jint jcmd(AttachOperation* op, outputStream* out) { Thread* THREAD = Thread::current(); // All the supplied jcmd arguments are stored as a single // string (op->arg(0)). This is parsed by the Dcmd framework. - DCmd::parse_and_execute(out, op->arg(0), ' ', THREAD); + DCmd::parse_and_execute(DCmd_Source_AttachAPI, out, op->arg(0), ' ', THREAD); if (HAS_PENDING_EXCEPTION) { java_lang_Throwable::print(PENDING_EXCEPTION, out); out->cr(); diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 5499d9ad2fe..5deaae0d416 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -34,26 +34,33 @@ void DCmdRegistrant::register_dcmds(){ // Registration of the diagnostic commands - // First boolean argument specifies if the command is enabled - // Second boolean argument specifies if the command is hidden - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); + // First argument specifies which interfaces will export the command + // Second argument specifies if the command is enabled + // Third argument specifies if the command is hidden + uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI + | DCmd_Source_MBean; + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); #if INCLUDE_SERVICES // Heap dumping/inspection supported - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); #endif // INCLUDE_SERVICES - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true, false)); - //Enhanced JMX Agent Support - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true,false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true,false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (true,false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (full_export, true, false)); + + // Enhanced JMX Agent Support + // These commands won't be exported via the DiagnosticCommandMBean until an + // appropriate permission is created for them + uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI; + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (jmx_agent_export_flags, true,false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (jmx_agent_export_flags, true,false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl (jmx_agent_export_flags, true,false)); } @@ -72,29 +79,37 @@ HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, hea _dcmdparser.add_dcmd_argument(&_cmd); }; -void HelpDCmd::execute(TRAPS) { +void HelpDCmd::execute(DCmdSource source, TRAPS) { if (_all.value()) { - GrowableArray * cmd_list = DCmdFactory::DCmd_list(); + GrowableArray * cmd_list = DCmdFactory::DCmd_list(source); for (int i = 0; i < cmd_list->length(); i++) { - DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), + DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), strlen(cmd_list->at(i))); - if (!factory->is_hidden()) { - output()->print_cr("%s%s", factory->name(), - factory->is_enabled() ? "" : " [disabled]"); - output()->print_cr("\t%s", factory->description()); - output()->cr(); - } + output()->print_cr("%s%s", factory->name(), + factory->is_enabled() ? "" : " [disabled]"); + output()->print_cr("\t%s", factory->description()); + output()->cr(); factory = factory->next(); } } else if (_cmd.has_value()) { DCmd* cmd = NULL; - DCmdFactory* factory = DCmdFactory::factory(_cmd.value(), + DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(), strlen(_cmd.value())); if (factory != NULL) { output()->print_cr("%s%s", factory->name(), factory->is_enabled() ? "" : " [disabled]"); output()->print_cr(factory->description()); output()->print_cr("\nImpact: %s", factory->impact()); + JavaPermission p = factory->permission(); + if(p._class != NULL) { + if(p._action != NULL) { + output()->print_cr("\nPermission: %s(%s, %s)", + p._class, p._name == NULL ? "null" : p._name, p._action); + } else { + output()->print_cr("\nPermission: %s(%s)", + p._class, p._name == NULL ? "null" : p._name); + } + } output()->cr(); cmd = factory->create_resource_instance(output()); if (cmd != NULL) { @@ -106,14 +121,12 @@ void HelpDCmd::execute(TRAPS) { } } else { output()->print_cr("The following commands are available:"); - GrowableArray * cmd_list = DCmdFactory::DCmd_list(); + GrowableArray * cmd_list = DCmdFactory::DCmd_list(source); for (int i = 0; i < cmd_list->length(); i++) { - DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), + DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), strlen(cmd_list->at(i))); - if (!factory->is_hidden()) { - output()->print_cr("%s%s", factory->name(), - factory->is_enabled() ? "" : " [disabled]"); - } + output()->print_cr("%s%s", factory->name(), + factory->is_enabled() ? "" : " [disabled]"); factory = factory->_next; } output()->print_cr("\nFor more information about a specific command use 'help '."); @@ -131,7 +144,7 @@ int HelpDCmd::num_arguments() { } } -void VersionDCmd::execute(TRAPS) { +void VersionDCmd::execute(DCmdSource source, TRAPS) { output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(), Abstract_VM_Version::vm_release()); JDK_Version jdk_version = JDK_Version::current(); @@ -150,7 +163,7 @@ PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) : _dcmdparser.add_dcmd_option(&_all); } -void PrintVMFlagsDCmd::execute(TRAPS) { +void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) { if (_all.value()) { CommandLineFlags::printFlags(output(), true); } else { @@ -169,7 +182,7 @@ int PrintVMFlagsDCmd::num_arguments() { } } -void PrintSystemPropertiesDCmd::execute(TRAPS) { +void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) { // load sun.misc.VMSupport Symbol* klass = vmSymbols::sun_misc_VMSupport(); Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK); @@ -219,7 +232,7 @@ VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) : _dcmdparser.add_dcmd_option(&_date); } -void VMUptimeDCmd::execute(TRAPS) { +void VMUptimeDCmd::execute(DCmdSource source, TRAPS) { if (_date.value()) { output()->date_stamp(true, "", ": "); } @@ -239,11 +252,15 @@ int VMUptimeDCmd::num_arguments() { } } -void SystemGCDCmd::execute(TRAPS) { - Universe::heap()->collect(GCCause::_java_lang_system_gc); +void SystemGCDCmd::execute(DCmdSource source, TRAPS) { + if (!DisableExplicitGC) { + Universe::heap()->collect(GCCause::_java_lang_system_gc); + } else { + output()->print_cr("Explicit GC is disabled, no GC has been performed."); + } } -void RunFinalizationDCmd::execute(TRAPS) { +void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) { Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); instanceKlassHandle klass(THREAD, k); @@ -263,7 +280,7 @@ HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) : _dcmdparser.add_dcmd_argument(&_filename); } -void HeapDumpDCmd::execute(TRAPS) { +void HeapDumpDCmd::execute(DCmdSource source, TRAPS) { // Request a full GC before heap dump if _all is false // This helps reduces the amount of unreachable objects in the dump // and makes it easier to browse. @@ -301,7 +318,7 @@ ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) : _dcmdparser.add_dcmd_option(&_all); } -void ClassHistogramDCmd::execute(TRAPS) { +void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) { VM_GC_HeapInspection heapop(output(), !_all.value() /* request full gc if false */, true /* need_prologue */); @@ -337,7 +354,7 @@ ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) : _dcmdparser.add_dcmd_argument(&_columns); } -void ClassStatsDCmd::execute(TRAPS) { +void ClassStatsDCmd::execute(DCmdSource source, TRAPS) { if (!UnlockDiagnosticVMOptions) { output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions"); return; @@ -384,7 +401,7 @@ ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) : _dcmdparser.add_dcmd_option(&_locks); } -void ThreadDumpDCmd::execute(TRAPS) { +void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) { // thread stacks VM_PrintThreads op1(output(), _locks.value()); VMThread::execute(&op1); @@ -526,7 +543,8 @@ int JMXStartRemoteDCmd::num_arguments() { } } -void JMXStartRemoteDCmd::execute(TRAPS) { + +void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -593,7 +611,7 @@ JMXStartLocalDCmd::JMXStartLocalDCmd(outputStream *output, bool heap_allocated) // do nothing } -void JMXStartLocalDCmd::execute(TRAPS) { +void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -611,7 +629,7 @@ void JMXStartLocalDCmd::execute(TRAPS) { } -void JMXStopRemoteDCmd::execute(TRAPS) { +void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index ac5d5809d1e..9c7216177bf 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -51,7 +51,7 @@ public: } static const char* impact() { return "Low"; } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; class VersionDCmd : public DCmd { @@ -62,8 +62,13 @@ public: return "Print JVM version information."; } static const char* impact() { return "Low"; } + static const JavaPermission permission() { + JavaPermission p = {"java.util.PropertyPermission", + "java.vm.version", "read"}; + return p; + } static int num_arguments() { return 0; } - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; class CommandLineDCmd : public DCmd { @@ -74,8 +79,13 @@ public: return "Print the command line used to start this VM instance."; } static const char* impact() { return "Low"; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } static int num_arguments() { return 0; } - virtual void execute(TRAPS) { + virtual void execute(DCmdSource source, TRAPS) { Arguments::print_on(_output); } }; @@ -91,8 +101,13 @@ public: static const char* impact() { return "Low"; } + static const JavaPermission permission() { + JavaPermission p = {"java.util.PropertyPermission", + "*", "read"}; + return p; + } static int num_arguments() { return 0; } - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; // See also: print_flag in attachListener.cpp @@ -108,8 +123,13 @@ public: static const char* impact() { return "Low"; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; class VMUptimeDCmd : public DCmdWithParser { @@ -125,7 +145,7 @@ public: return "Low"; } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; class SystemGCDCmd : public DCmd { @@ -139,7 +159,7 @@ public: return "Medium: Depends on Java heap size and content."; } static int num_arguments() { return 0; } - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; class RunFinalizationDCmd : public DCmd { @@ -153,7 +173,7 @@ public: return "Medium: Depends on Java content."; } static int num_arguments() { return 0; } - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; #if INCLUDE_SERVICES // Heap dumping supported @@ -174,8 +194,13 @@ public: return "High: Depends on Java heap size and content. " "Request a full GC unless the '-all' option is specified."; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; #endif // INCLUDE_SERVICES @@ -194,8 +219,13 @@ public: static const char* impact() { return "High: Depends on Java heap size and content."; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; class ClassStatsDCmd : public DCmdWithParser { @@ -216,7 +246,7 @@ public: return "High: Depends on Java heap size and content."; } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; // See also: thread_dump in attachListener.cpp @@ -232,8 +262,13 @@ public: static const char* impact() { return "Medium: Depends on the number of threads."; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; // Enhanced JMX Agent support @@ -281,7 +316,7 @@ public: static int num_arguments(); - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; @@ -302,7 +337,7 @@ public: return "Start local management agent."; } - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; @@ -321,7 +356,7 @@ public: return "Stop remote management agent."; } - virtual void execute(TRAPS); + virtual void execute(DCmdSource source, TRAPS); }; #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP diff --git a/hotspot/src/share/vm/services/diagnosticFramework.cpp b/hotspot/src/share/vm/services/diagnosticFramework.cpp index 2ae7866f6c6..dcc2a21e48a 100644 --- a/hotspot/src/share/vm/services/diagnosticFramework.cpp +++ b/hotspot/src/share/vm/services/diagnosticFramework.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -359,7 +359,7 @@ GrowableArray * DCmdParser::argument_info_array() { while (arg != NULL) { array->append(new DCmdArgumentInfo(arg->name(), arg->description(), arg->type(), arg->default_string(), arg->is_mandatory(), - false, idx)); + false, arg->allow_multiple(), idx)); idx++; arg = arg->next(); } @@ -367,32 +367,42 @@ GrowableArray * DCmdParser::argument_info_array() { while (arg != NULL) { array->append(new DCmdArgumentInfo(arg->name(), arg->description(), arg->type(), arg->default_string(), arg->is_mandatory(), - true)); + true, arg->allow_multiple())); arg = arg->next(); } return array; } DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL; +bool DCmdFactory::_has_pending_jmx_notification = false; -void DCmd::parse_and_execute(outputStream* out, const char* cmdline, - char delim, TRAPS) { +void DCmd::parse_and_execute(DCmdSource source, outputStream* out, + const char* cmdline, char delim, TRAPS) { if (cmdline == NULL) return; // Nothing to do! DCmdIter iter(cmdline, '\n'); + int count = 0; while (iter.has_next()) { + if(source == DCmd_Source_MBean && count > 0) { + // When diagnostic commands are invoked via JMX, each command line + // must contains one and only one command because of the Permission + // checks performed by the DiagnosticCommandMBean + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Invalid syntax"); + } CmdLine line = iter.next(); if (line.is_stop()) { break; } if (line.is_executable()) { - DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK); + DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK); assert(command != NULL, "command error must be handled before this line"); DCmdMark mark(command); command->parse(&line, delim, CHECK); - command->execute(CHECK); + command->execute(source, CHECK); } + count++; } } @@ -420,15 +430,78 @@ GrowableArray * DCmdWithParser::argument_info_array() { return _dcmdparser.argument_info_array(); } -Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true); +void DCmdFactory::push_jmx_notification_request() { + MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); + _has_pending_jmx_notification = true; + Service_lock->notify_all(); +} -DCmdFactory* DCmdFactory::factory(const char* name, size_t len) { +void DCmdFactory::send_notification(TRAPS) { + DCmdFactory::send_notification_internal(THREAD); + // Clearing pending exception to avoid premature termination of + // the service thread + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + } +} +void DCmdFactory::send_notification_internal(TRAPS) { + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + bool notif = false; + { + MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); + notif = _has_pending_jmx_notification; + _has_pending_jmx_notification = false; + } + if (notif) { + + Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK); + instanceKlassHandle mgmt_factory_helper_klass(THREAD, k); + + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + mgmt_factory_helper_klass, + vmSymbols::getDiagnosticCommandMBean_name(), + vmSymbols::getDiagnosticCommandMBean_signature(), + CHECK); + + instanceOop m = (instanceOop) result.get_jobject(); + instanceHandle dcmd_mbean_h(THREAD, m); + + Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK); + instanceKlassHandle dcmd_mbean_klass(THREAD, k2); + + if (!dcmd_mbean_h->is_a(k2)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance"); + } + + JavaValue result2(T_VOID); + JavaCallArguments args2(dcmd_mbean_h); + + JavaCalls::call_virtual(&result2, + dcmd_mbean_klass, + vmSymbols::createDiagnosticFrameworkNotification_name(), + vmSymbols::void_method_signature(), + &args2, + CHECK); + } +} + +Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true); +bool DCmdFactory::_send_jmx_notification = false; + +DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) { MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); DCmdFactory* factory = _DCmdFactoryList; while (factory != NULL) { if (strlen(factory->name()) == len && strncmp(name, factory->name(), len) == 0) { - return factory; + if(factory->export_flags() & source) { + return factory; + } else { + return NULL; + } } factory = factory->_next; } @@ -439,11 +512,16 @@ int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) { MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); factory->_next = _DCmdFactoryList; _DCmdFactoryList = factory; + if (_send_jmx_notification && !factory->_hidden + && (factory->_export_flags & DCmd_Source_MBean)) { + DCmdFactory::push_jmx_notification_request(); + } return 0; // Actually, there's no checks for duplicates } -DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) { - DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); +DCmd* DCmdFactory::create_global_DCmd(DCmdSource source, CmdLine &line, + outputStream* out, TRAPS) { + DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len()); if (f != NULL) { if (f->is_enabled()) { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), @@ -455,8 +533,9 @@ DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) { "Unknown diagnostic command"); } -DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) { - DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); +DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line, + outputStream* out, TRAPS) { + DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len()); if (f != NULL) { if (!f->is_enabled()) { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), @@ -468,12 +547,12 @@ DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) { "Unknown diagnostic command"); } -GrowableArray * DCmdFactory::DCmd_list() { +GrowableArray * DCmdFactory::DCmd_list(DCmdSource source) { MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); GrowableArray * array = new GrowableArray (); DCmdFactory* factory = _DCmdFactoryList; while (factory != NULL) { - if (!factory->is_hidden()) { + if (!factory->is_hidden() && (factory->export_flags() & source)) { array->append(factory->name()); } factory = factory->next(); @@ -481,15 +560,16 @@ GrowableArray * DCmdFactory::DCmd_list() { return array; } -GrowableArray * DCmdFactory::DCmdInfo_list() { +GrowableArray * DCmdFactory::DCmdInfo_list(DCmdSource source ) { MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); GrowableArray * array = new GrowableArray (); DCmdFactory* factory = _DCmdFactoryList; while (factory != NULL) { - if (!factory->is_hidden()) { + if (!factory->is_hidden() && (factory->export_flags() & source)) { array->append(new DCmdInfo(factory->name(), factory->description(), factory->impact(), - factory->num_arguments(), factory->is_enabled())); + factory->permission(), factory->num_arguments(), + factory->is_enabled())); } factory = factory->next(); } diff --git a/hotspot/src/share/vm/services/diagnosticFramework.hpp b/hotspot/src/share/vm/services/diagnosticFramework.hpp index 08b24e07f33..ca60f53ebc8 100644 --- a/hotspot/src/share/vm/services/diagnosticFramework.hpp +++ b/hotspot/src/share/vm/services/diagnosticFramework.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,22 @@ #include "utilities/ostream.hpp" +enum DCmdSource { + DCmd_Source_Internal = 0x01U, // invocation from the JVM + DCmd_Source_AttachAPI = 0x02U, // invocation via the attachAPI + DCmd_Source_MBean = 0x04U // invocation via a MBean +}; + +// Warning: strings referenced by the JavaPermission struct are passed to +// the native part of the JDK. Avoid use of dynamically allocated strings +// that could be de-allocated before the JDK native code had time to +// convert them into Java Strings. +struct JavaPermission { + const char* _class; + const char* _name; + const char* _action; +}; + // CmdLine is the class used to handle a command line containing a single // diagnostic command and its arguments. It provides methods to access the // command name and the beginning of the arguments. The class is also @@ -113,26 +129,30 @@ public: // used to export the description to the JMX interface of the framework. class DCmdInfo : public ResourceObj { protected: - const char* _name; - const char* _description; - const char* _impact; - int _num_arguments; - bool _is_enabled; + const char* _name; /* Name of the diagnostic command */ + const char* _description; /* Short description */ + const char* _impact; /* Impact on the JVM */ + JavaPermission _permission; /* Java Permission required to execute this command if any */ + int _num_arguments; /* Number of supported options or arguments */ + bool _is_enabled; /* True if the diagnostic command can be invoked, false otherwise */ public: DCmdInfo(const char* name, const char* description, const char* impact, + JavaPermission permission, int num_arguments, bool enabled) { this->_name = name; this->_description = description; this->_impact = impact; + this->_permission = permission; this->_num_arguments = num_arguments; this->_is_enabled = enabled; } const char* name() const { return _name; } const char* description() const { return _description; } const char* impact() const { return _impact; } + JavaPermission permission() const { return _permission; } int num_arguments() const { return _num_arguments; } bool is_enabled() const { return _is_enabled; } @@ -144,16 +164,20 @@ public: // framework. class DCmdArgumentInfo : public ResourceObj { protected: - const char* _name; - const char* _description; - const char* _type; - const char* _default_string; - bool _mandatory; - bool _option; - int _position; + const char* _name; /* Option/Argument name*/ + const char* _description; /* Short description */ + const char* _type; /* Type: STRING, BOOLEAN, etc. */ + const char* _default_string; /* Default value in a parsable string */ + bool _mandatory; /* True if the option/argument is mandatory */ + bool _option; /* True if it is an option, false if it is an argument */ + /* (see diagnosticFramework.hpp for option/argument definitions) */ + bool _multiple; /* True is the option can be specified several time */ + int _position; /* Expected position for this argument (this field is */ + /* meaningless for options) */ public: DCmdArgumentInfo(const char* name, const char* description, const char* type, - const char* default_string, bool mandatory, bool option) { + const char* default_string, bool mandatory, bool option, + bool multiple) { this->_name = name; this->_description = description; this->_type = type; @@ -161,11 +185,12 @@ public: this->_option = option; this->_mandatory = mandatory; this->_option = option; + this->_multiple = multiple; this->_position = -1; } DCmdArgumentInfo(const char* name, const char* description, const char* type, const char* default_string, bool mandatory, bool option, - int position) { + bool multiple, int position) { this->_name = name; this->_description = description; this->_type = type; @@ -173,6 +198,7 @@ public: this->_option = option; this->_mandatory = mandatory; this->_option = option; + this->_multiple = multiple; this->_position = position; } const char* name() const { return _name; } @@ -181,11 +207,29 @@ public: const char* default_string() const { return _default_string; } bool is_mandatory() const { return _mandatory; } bool is_option() const { return _option; } + bool is_multiple() const { return _multiple; } int position() const { return _position; } }; // The DCmdParser class can be used to create an argument parser for a // diagnostic command. It is not mandatory to use it to parse arguments. +// The DCmdParser parses a CmdLine instance according to the parameters that +// have been declared by its associated diagnostic command. A parameter can +// either be an option or an argument. Options are identified by the option name +// while arguments are identified by their position in the command line. The +// position of an argument is defined relative to all arguments passed on the +// command line, options are not considered when defining an argument position. +// The generic syntax of a diagnostic command is: +// +// [ java.util.GregorianCalendar
used to createXMLGregorianCalendar
- * - * @returnXMLGregorianCalendar
created fromjava.util.GregorianCalendar
- * - * @throws NullPointerException Ifcal
isnull
. - */ - public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal); + /** + *Create an
+ * + *XMLGregorianCalendar
from a {@link GregorianCalendar}.+ * + *
+ *+ * + *+ * Field by Field Conversion from + * {@link GregorianCalendar} to an {@link XMLGregorianCalendar} + * + *+ * + * + * + *+ * java.util.GregorianCalendar
field+ * javax.xml.datatype.XMLGregorianCalendar
field+ * + *+ * ERA == GregorianCalendar.BC ? -YEAR : YEAR
{@link XMLGregorianCalendar#setYear(int year)} + *+ * + *+ * MONTH + 1
{@link XMLGregorianCalendar#setMonth(int month)} + *+ * + *+ * DAY_OF_MONTH
{@link XMLGregorianCalendar#setDay(int day)} + *+ * + *+ * HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND
{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)} + *+ * + * + *+ * + *(ZONE_OFFSET + DST_OFFSET) / (60*1000)
+ * (in minutes) + *{@link XMLGregorianCalendar#setTimezone(int offset)}* + * + **conversion loss of information. It is not possible to represent + * a
+ * + *java.util.GregorianCalendar
daylight savings timezone id in the + * XML Schema 1.0 date/time datatype representation.To compute the return value's
TimeZone
field, + *+ *
* @@ -113,21 +106,16 @@ public abstract class DocumentBuilderFactory { * * @return New instance of a- when
+ *this.getTimezone() != FIELD_UNDEFINED
, + * create ajava.util.TimeZone
with a custom timezone id + * using thethis.getTimezone()
.- else use the
+ * + * @param calGregorianCalendar
default timezone value + * for the host is defined as specified by + *java.util.TimeZone.getDefault()
.java.util.GregorianCalendar
used to createXMLGregorianCalendar
+ * + * @returnXMLGregorianCalendar
created fromjava.util.GregorianCalendar
+ * + * @throws NullPointerException Ifcal
isnull
. + */ + public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal); - /** - *Constructor allowing for complete value spaces allowed by - * W3C XML Schema 1.0 recommendation for xsd:dateTime and related - * builtin datatypes. Note that
- * + /** + *year
parameter supports - * arbitrarily large numbers and fractionalSecond has infinite - * precision.Constructor allowing for complete value spaces allowed by + * W3C XML Schema 1.0 recommendation for xsd:dateTime and related + * builtin datatypes. Note that
+ * *year
parameter supports + * arbitrarily large numbers and fractionalSecond has infinite + * precision.A
* - * @param year ofnull
value indicates that field is not set.XMLGregorianCalendar
to be created. - * @param month ofXMLGregorianCalendar
to be created. - * @param day ofXMLGregorianCalendar
to be created. - * @param hour ofXMLGregorianCalendar
to be created. - * @param minute ofXMLGregorianCalendar
to be created. - * @param second ofXMLGregorianCalendar
to be created. - * @param fractionalSecond ofXMLGregorianCalendar
to be created. - * @param timezone ofXMLGregorianCalendar
to be created. - * - * @returnXMLGregorianCalendar
created from specified values. - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalidXMLGregorianCalendar
instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public abstract XMLGregorianCalendar newXMLGregorianCalendar( - final BigInteger year, - final int month, - final int day, - final int hour, - final int minute, - final int second, - final BigDecimal fractionalSecond, - final int timezone); + * @param year ofXMLGregorianCalendar
to be created. + * @param month ofXMLGregorianCalendar
to be created. + * @param day ofXMLGregorianCalendar
to be created. + * @param hour ofXMLGregorianCalendar
to be created. + * @param minute ofXMLGregorianCalendar
to be created. + * @param second ofXMLGregorianCalendar
to be created. + * @param fractionalSecond ofXMLGregorianCalendar
to be created. + * @param timezone ofXMLGregorianCalendar
to be created. + * + * @returnXMLGregorianCalendar
created from specified values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalidXMLGregorianCalendar
instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public abstract XMLGregorianCalendar newXMLGregorianCalendar( + final BigInteger year, + final int month, + final int day, + final int hour, + final int minute, + final int second, + final BigDecimal fractionalSecond, + final int timezone); - /** - *Constructor of value spaces that a - *
- * - *java.util.GregorianCalendar
instance would need to convert to an - *XMLGregorianCalendar
instance.- * + /** + *
XMLGregorianCalendar eon
and - *fractionalSecond
are set tonull
Constructor of value spaces that a + *
+ * + *java.util.GregorianCalendar
instance would need to convert to an + *XMLGregorianCalendar
instance.+ * *
XMLGregorianCalendar eon
and + *fractionalSecond
are set tonull
A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
* - * @param year ofXMLGregorianCalendar
to be created. - * @param month ofXMLGregorianCalendar
to be created. - * @param day ofXMLGregorianCalendar
to be created. - * @param hour ofXMLGregorianCalendar
to be created. - * @param minute ofXMLGregorianCalendar
to be created. - * @param second ofXMLGregorianCalendar
to be created. - * @param millisecond ofXMLGregorianCalendar
to be created. - * @param timezone ofXMLGregorianCalendar
to be created. - * - * @returnXMLGregorianCalendar
created from specified values. - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalidXMLGregorianCalendar
instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendar( - final int year, - final int month, - final int day, - final int hour, - final int minute, - final int second, - final int millisecond, - final int timezone) { + * @param year ofXMLGregorianCalendar
to be created. + * @param month ofXMLGregorianCalendar
to be created. + * @param day ofXMLGregorianCalendar
to be created. + * @param hour ofXMLGregorianCalendar
to be created. + * @param minute ofXMLGregorianCalendar
to be created. + * @param second ofXMLGregorianCalendar
to be created. + * @param millisecond ofXMLGregorianCalendar
to be created. + * @param timezone ofXMLGregorianCalendar
to be created. + * + * @returnXMLGregorianCalendar
created from specified values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalidXMLGregorianCalendar
instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendar( + final int year, + final int month, + final int day, + final int hour, + final int minute, + final int second, + final int millisecond, + final int timezone) { - // year may be undefined - BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null; + // year may be undefined + BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null; - // millisecond may be undefined - // millisecond must be >= 0 millisecond <= 1000 - BigDecimal realMillisecond = null; // undefined value - if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { - if (millisecond < 0 || millisecond > 1000) { - throw new IllegalArgumentException( - "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar(" - + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)" - + "with invalid millisecond: " + millisecond - ); - } + // millisecond may be undefined + // millisecond must be >= 0 millisecond <= 1000 + BigDecimal realMillisecond = null; // undefined value + if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { + if (millisecond < 0 || millisecond > 1000) { + throw new IllegalArgumentException( + "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar(" + + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)" + + "with invalid millisecond: " + millisecond + ); + } - realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3); - } + realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3); + } - return newXMLGregorianCalendar( - realYear, - month, - day, - hour, - minute, - second, - realMillisecond, - timezone - ); - } + return newXMLGregorianCalendar( + realYear, + month, + day, + hour, + minute, + second, + realMillisecond, + timezone + ); + } - /** - *Create a Java representation of XML Schema builtin datatype
- * - *date
org*
.For example, an instance of
- * + /** + *gYear
can be created invoking this factory - * withmonth
andday
parameters set to - * {@link DatatypeConstants#FIELD_UNDEFINED}.Create a Java representation of XML Schema builtin datatype
+ * + *date
org*
.For example, an instance of
+ * *gYear
can be created invoking this factory + * withmonth
andday
parameters set to + * {@link DatatypeConstants#FIELD_UNDEFINED}.A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
* - * @param year ofXMLGregorianCalendar
to be created. - * @param month ofXMLGregorianCalendar
to be created. - * @param day ofXMLGregorianCalendar
to be created. - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @returnXMLGregorianCalendar
created from parameter values. - * - * @see DatatypeConstants#FIELD_UNDEFINED - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalidXMLGregorianCalendar
instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendarDate( - final int year, - final int month, - final int day, - final int timezone) { + * @param year ofXMLGregorianCalendar
to be created. + * @param month ofXMLGregorianCalendar
to be created. + * @param day ofXMLGregorianCalendar
to be created. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @returnXMLGregorianCalendar
created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalidXMLGregorianCalendar
instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendarDate( + final int year, + final int month, + final int day, + final int timezone) { - return newXMLGregorianCalendar( - year, - month, - day, - DatatypeConstants.FIELD_UNDEFINED, // hour - DatatypeConstants.FIELD_UNDEFINED, // minute - DatatypeConstants.FIELD_UNDEFINED, // second - DatatypeConstants.FIELD_UNDEFINED, // millisecond - timezone); - } + return newXMLGregorianCalendar( + year, + month, + day, + DatatypeConstants.FIELD_UNDEFINED, // hour + DatatypeConstants.FIELD_UNDEFINED, // minute + DatatypeConstants.FIELD_UNDEFINED, // second + DatatypeConstants.FIELD_UNDEFINED, // millisecond + timezone); + } - /** - *Create a Java instance of XML Schema builtin datatype
- * + /** + *time
.Create a Java instance of XML Schema builtin datatype
+ * *time
.A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
* - * @param hours number of hours - * @param minutes number of minutes - * @param seconds number of seconds - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @returnXMLGregorianCalendar
created from parameter values. - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalidXMLGregorianCalendar
instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - * - * @see DatatypeConstants#FIELD_UNDEFINED - */ - public XMLGregorianCalendar newXMLGregorianCalendarTime( - final int hours, - final int minutes, - final int seconds, - final int timezone) { + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @returnXMLGregorianCalendar
created from parameter values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalidXMLGregorianCalendar
instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + * + * @see DatatypeConstants#FIELD_UNDEFINED + */ + public XMLGregorianCalendar newXMLGregorianCalendarTime( + final int hours, + final int minutes, + final int seconds, + final int timezone) { - return newXMLGregorianCalendar( - DatatypeConstants.FIELD_UNDEFINED, // Year - DatatypeConstants.FIELD_UNDEFINED, // Month - DatatypeConstants.FIELD_UNDEFINED, // Day - hours, - minutes, - seconds, - DatatypeConstants.FIELD_UNDEFINED, //Millisecond - timezone); - } + return newXMLGregorianCalendar( + DatatypeConstants.FIELD_UNDEFINED, // Year + DatatypeConstants.FIELD_UNDEFINED, // Month + DatatypeConstants.FIELD_UNDEFINED, // Day + hours, + minutes, + seconds, + DatatypeConstants.FIELD_UNDEFINED, //Millisecond + timezone); + } - /** - *Create a Java instance of XML Schema builtin datatype time.
- * + /** + *Create a Java instance of XML Schema builtin datatype time.
+ * *A
*null
value indicates that field is not set.A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
* - * @param hours number of hours - * @param minutes number of minutes - * @param seconds number of seconds - * @param fractionalSecond value ofnull
indicates that this optional field is not set. - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @returnXMLGregorianCalendar
created from parameter values. - * - * @see DatatypeConstants#FIELD_UNDEFINED - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalidXMLGregorianCalendar
instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendarTime( - final int hours, - final int minutes, - final int seconds, - final BigDecimal fractionalSecond, - final int timezone) { + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param fractionalSecond value ofnull
indicates that this optional field is not set. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @returnXMLGregorianCalendar
created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalidXMLGregorianCalendar
instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendarTime( + final int hours, + final int minutes, + final int seconds, + final BigDecimal fractionalSecond, + final int timezone) { - return newXMLGregorianCalendar( - null, // year - DatatypeConstants.FIELD_UNDEFINED, // month - DatatypeConstants.FIELD_UNDEFINED, // day - hours, - minutes, - seconds, - fractionalSecond, - timezone); - } + return newXMLGregorianCalendar( + null, // year + DatatypeConstants.FIELD_UNDEFINED, // month + DatatypeConstants.FIELD_UNDEFINED, // day + hours, + minutes, + seconds, + fractionalSecond, + timezone); + } - /** - *Create a Java instance of XML Schema builtin datatype time.
- * + /** + *Create a Java instance of XML Schema builtin datatype time.
+ * *A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
* - * @param hours number of hours - * @param minutes number of minutes - * @param seconds number of seconds - * @param milliseconds number of milliseconds - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @returnXMLGregorianCalendar
created from parameter values. - * - * @see DatatypeConstants#FIELD_UNDEFINED - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalidXMLGregorianCalendar
instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendarTime( - final int hours, - final int minutes, - final int seconds, - final int milliseconds, - final int timezone) { + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param milliseconds number of milliseconds + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @returnXMLGregorianCalendar
created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalidXMLGregorianCalendar
instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendarTime( + final int hours, + final int minutes, + final int seconds, + final int milliseconds, + final int timezone) { - // millisecond may be undefined - // millisecond must be >= 0 millisecond <= 1000 - BigDecimal realMilliseconds = null; // undefined value - if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) { - if (milliseconds < 0 || milliseconds > 1000) { - throw new IllegalArgumentException( - "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime(" - + "int hours, int minutes, int seconds, int milliseconds, int timezone)" - + "with invalid milliseconds: " + milliseconds - ); - } + // millisecond may be undefined + // millisecond must be >= 0 millisecond <= 1000 + BigDecimal realMilliseconds = null; // undefined value + if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) { + if (milliseconds < 0 || milliseconds > 1000) { + throw new IllegalArgumentException( + "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime(" + + "int hours, int minutes, int seconds, int milliseconds, int timezone)" + + "with invalid milliseconds: " + milliseconds + ); + } - realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3); - } + realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3); + } - return newXMLGregorianCalendarTime( - hours, - minutes, - seconds, - realMilliseconds, - timezone - ); - } + return newXMLGregorianCalendarTime( + hours, + minutes, + seconds, + realMilliseconds, + timezone + ); + } } diff --git a/jaxp/src/javax/xml/datatype/FactoryFinder.java b/jaxp/src/javax/xml/datatype/FactoryFinder.java index deb47eaa11c..ce982157240 100644 --- a/jaxp/src/javax/xml/datatype/FactoryFinder.java +++ b/jaxp/src/javax/xml/datatype/FactoryFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,14 +26,12 @@ package javax.xml.datatype; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** *Implements pluggable Datatypes.
@@ -54,19 +52,19 @@ class FactoryFinder { /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private final static Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties * have been cached. */ - static volatile boolean firstTime = true; + private static volatile boolean firstTime = true; /** * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private final static SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -99,31 +97,31 @@ class FactoryFinder { * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class> getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -135,6 +133,9 @@ class FactoryFinder { * Create an instance of a class. Delegates to method *getProviderClass()
in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -144,16 +145,19 @@ class FactoryFinder { * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, boolean doFallback) + throws DatatypeConfigurationException { - return newInstance(className, cl, doFallback, false); + return newInstance(type, className, cl, doFallback, false); } /** * Create an instance of a class. Delegates to method * getProviderClass()
in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -166,9 +170,12 @@ class FactoryFinder { * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useBSClsLoader) + throws DatatypeConfigurationException { + assert type != null; + // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -178,20 +185,23 @@ class FactoryFinder { } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( + throw new DatatypeConfigurationException( "Provider " + className + " not found", x); } catch (Exception x) { - throw new ConfigurationError( + throw new DatatypeConfigurationException( "Provider " + className + " could not be instantiated: " + x, x); } @@ -202,16 +212,17 @@ class FactoryFinder { * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws DatatypeConfigurationException { + final String factoryId = type.getName(); dPrint("find factoryId =" + factoryId); // Use the system property first @@ -219,7 +230,7 @@ class FactoryFinder { String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + return newInstance(type, systemProp, null, true); } } catch (SecurityException se) { @@ -228,7 +239,6 @@ class FactoryFinder { // try to read from $java.home/lib/jaxp.properties try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -243,11 +253,11 @@ class FactoryFinder { } } } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + return newInstance(type, factoryClassName, null, true); } } catch (Exception ex) { @@ -255,112 +265,46 @@ class FactoryFinder { } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + final T provider = findServiceProvider(type); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new DatatypeConfigurationException( + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true); + return newInstance(type, fallbackClassName, null, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError + private static T findServiceProvider(final Class type) + throws DatatypeConfigurationException { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + return AccessController.doPrivileged(new PrivilegedAction () { + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + final DatatypeConfigurationException error = + new DatatypeConfigurationException( + "Provider for " + type + " cannot be found", e); + throw error; } } diff --git a/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java b/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java index 98db9beed5d..0ef1c13cecb 100644 --- a/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java +++ b/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,9 +40,6 @@ import javax.xml.validation.Schema; public abstract class DocumentBuilderFactory { - /** The default property name according to the JAXP spec */ - private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.DocumentBuilderFactory"; - private boolean validating = false; private boolean namespaceAware = false; private boolean whitespace = false; @@ -50,8 +47,6 @@ public abstract class DocumentBuilderFactory { private boolean ignoreComments = false; private boolean coalescing = false; - private boolean canonicalState = false; - /** * Protected constructor to prevent instantiation. * Use {@link #newInstance()}.
@@ -85,14 +80,12 @@ public abstract class DocumentBuilderFactory { * of any property in jaxp.properties after it has been read for the first time. * *- - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - *
*META-INF/services/javax.xml.parsers.DocumentBuilderFactory
- * in jars available to the runtime. + * Uses the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. *- - * Platform default
*DocumentBuilderFactory
instance. + * Otherwise, the system-default implementation is returned. *DocumentBuilderFactory
* - * @throws FactoryConfigurationError if the implementation is not - * available or cannot be instantiated. + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static DocumentBuilderFactory newInstance() { - try { - return (DocumentBuilderFactory) FactoryFinder.find( + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.parsers.DocumentBuilderFactory", + DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory" /* The fallback implementation class name */ "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } - } /** @@ -165,13 +153,9 @@ public abstract class DocumentBuilderFactory { * @since 1.6 */ public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){ - try { //do not fallback if given classloader can't find the class, throw exception - return (DocumentBuilderFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + return FactoryFinder.newInstance(DocumentBuilderFactory.class, + factoryClassName, classLoader, false); } /** @@ -391,75 +375,64 @@ public abstract class DocumentBuilderFactory { public abstract Object getAttribute(String name) throws IllegalArgumentException; - /** - *Set a feature for this
- * - *DocumentBuilderFactory
andDocumentBuilder
s created by this factory.- * Feature names are fully qualified {@link java.net.URI}s. - * Implementations may define their own features. - * A {@link ParserConfigurationException} is thrown if this
- * - *DocumentBuilderFactory
or the - *DocumentBuilder
s it creates cannot support the feature. - * It is possible for aDocumentBuilderFactory
to expose a feature value but be unable to change its state. - *- * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. - * When the feature is:
- *- *
- * - * @param name Feature name. - * @param value Is feature state- - *
- *true
: the implementation will limit XML processing to conform to implementation limits. - * Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources. - * If XML processing is limited for security reasons, it will be reported via a call to the registered - * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. - * See {@link DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}. - *- - *
- *false
: the implementation will processing XML according to the XML specifications without - * regard to possible implementation limits. - *true
orfalse
. - * - * @throws ParserConfigurationException if thisDocumentBuilderFactory
or theDocumentBuilder
s - * it creates cannot support this feature. - * @throws NullPointerException If thename
parameter is null. - */ - public abstract void setFeature(String name, boolean value) - throws ParserConfigurationException; - - /** - *Get the state of the named feature.
- * - *- * Feature names are fully qualified {@link java.net.URI}s. - * Implementations may define their own features. - * An {@link ParserConfigurationException} is thrown if this
- * - * @param name Feature name. - * - * @return State of the named feature. - * - * @throws ParserConfigurationException if thisDocumentBuilderFactory
or the - *DocumentBuilder
s it creates cannot support the feature. - * It is possible for anDocumentBuilderFactory
to expose a feature value but be unable to change its state. - *DocumentBuilderFactory
- * or theDocumentBuilder
s it creates cannot support this feature. - */ - public abstract boolean getFeature(String name) - throws ParserConfigurationException; - - - /**Get current state of canonicalization.
+ /** + *Set a feature for this
* - * @return current state canonicalization control + *DocumentBuilderFactory
andDocumentBuilder
s created by this factory.+ * Feature names are fully qualified {@link java.net.URI}s. + * Implementations may define their own features. + * A {@link ParserConfigurationException} is thrown if this
+ * + *DocumentBuilderFactory
or the + *DocumentBuilder
s it creates cannot support the feature. + * It is possible for aDocumentBuilderFactory
to expose a feature value but be unable to change its state. + *+ * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. + * When the feature is:
+ *+ *
+ * + * @param name Feature name. + * @param value Is feature state- + *
+ *true
: the implementation will limit XML processing to conform to implementation limits. + * Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources. + * If XML processing is limited for security reasons, it will be reported via a call to the registered + * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. + * See {@link DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}. + *- + *
+ *false
: the implementation will processing XML according to the XML specifications without + * regard to possible implementation limits. + *true
orfalse
. + * + * @throws ParserConfigurationException if thisDocumentBuilderFactory
or theDocumentBuilder
s + * it creates cannot support this feature. + * @throws NullPointerException If thename
parameter is null. */ - /* - public boolean getCanonicalization() { - return canonicalState; - } - */ + public abstract void setFeature(String name, boolean value) + throws ParserConfigurationException; + + /** + *Get the state of the named feature.
+ * + *+ * Feature names are fully qualified {@link java.net.URI}s. + * Implementations may define their own features. + * An {@link ParserConfigurationException} is thrown if this
+ * + * @param name Feature name. + * + * @return State of the named feature. + * + * @throws ParserConfigurationException if thisDocumentBuilderFactory
or the + *DocumentBuilder
s it creates cannot support the feature. + * It is possible for anDocumentBuilderFactory
to expose a feature value but be unable to change its state. + *DocumentBuilderFactory
+ * or theDocumentBuilder
s it creates cannot support this feature. + */ + public abstract boolean getFeature(String name) + throws ParserConfigurationException; /** @@ -488,17 +461,6 @@ public abstract class DocumentBuilderFactory { } - /*Set canonicalization control to
- * - * @param state of canonicalization - */ - /* - public void setCanonicalization(boolean state) { - canonicalState = state; - } - */ - /** *true
or - * false.Set the {@link Schema} to be used by parsers created * from this factory. diff --git a/jaxp/src/javax/xml/parsers/FactoryFinder.java b/jaxp/src/javax/xml/parsers/FactoryFinder.java index 214f87f2239..9e186f512ef 100644 --- a/jaxp/src/javax/xml/parsers/FactoryFinder.java +++ b/jaxp/src/javax/xml/parsers/FactoryFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,16 @@ package javax.xml.parsers; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** - *
Implements pluggable Datatypes.
+ *Implements pluggable Parsers.
* *This class is duplicated for each JAXP subpackage so keep it in * sync. It is package private for secure class loading.
@@ -51,7 +52,7 @@ class FactoryFinder { /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties @@ -63,7 +64,7 @@ class FactoryFinder { * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private static final SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -96,31 +97,31 @@ class FactoryFinder { * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class> getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -132,6 +133,9 @@ class FactoryFinder { * Create an instance of a class. Delegates to method *getProviderClass()
in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -141,16 +145,20 @@ class FactoryFinder { * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, + boolean doFallback) + throws FactoryConfigurationError { - return newInstance(className, cl, doFallback, false); + return newInstance(type, className, cl, doFallback, false); } /** * Create an instance of a class. Delegates to method * getProviderClass()
in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -163,9 +171,11 @@ class FactoryFinder { * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useBSClsLoader) + throws FactoryConfigurationError { + assert type != null; // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -175,22 +185,24 @@ class FactoryFinder { } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); + throw new FactoryConfigurationError(x, + "Provider " + className + " not found"); } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); + throw new FactoryConfigurationError(x, + "Provider " + className + " could not be instantiated: " + x); } } @@ -199,16 +211,17 @@ class FactoryFinder { * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws FactoryConfigurationError { + final String factoryId = type.getName(); dPrint("find factoryId =" + factoryId); // Use the system property first @@ -216,7 +229,7 @@ class FactoryFinder { String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + return newInstance(type, systemProp, null, true); } } catch (SecurityException se) { @@ -225,7 +238,6 @@ class FactoryFinder { // try to read from $java.home/lib/jaxp.properties try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -240,11 +252,11 @@ class FactoryFinder { } } } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + return newInstance(type, factoryClassName, null, true); } } catch (Exception ex) { @@ -252,112 +264,52 @@ class FactoryFinder { } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + T provider = findServiceProvider(type); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new FactoryConfigurationError( + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true); + return newInstance(type, fallbackClassName, null, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; + private static T findServiceProvider(final Class type) { try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + return AccessController.doPrivileged(new PrivilegedAction () { + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final FactoryConfigurationError error = + new FactoryConfigurationError(x, x.getMessage()); + throw error; } } diff --git a/jaxp/src/javax/xml/parsers/SAXParserFactory.java b/jaxp/src/javax/xml/parsers/SAXParserFactory.java index 95c78042767..a7aef97bdf3 100644 --- a/jaxp/src/javax/xml/parsers/SAXParserFactory.java +++ b/jaxp/src/javax/xml/parsers/SAXParserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package javax.xml.parsers; import javax.xml.validation.Schema; - import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -42,8 +41,6 @@ import org.xml.sax.SAXNotSupportedException; * */ public abstract class SAXParserFactory { - /** The default property name according to the JAXP spec */ - private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory"; /** * Should Parsers be validating?
@@ -87,14 +84,12 @@ public abstract class SAXParserFactory { * of any property in jaxp.properties after it has been read for the first time. * *- * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - * *META-INF/services/javax.xml.parsers.SAXParserFactory
- * in jars available to the runtime. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. *- * Platform default * * @@ -109,7 +104,7 @@ public abstract class SAXParserFactory { * this method to print a lot of debug messages * toSAXParserFactory
instance. + * Otherwise the system-default implementation is returned. *System.err
about what it is doing and where it is looking at. * - *If you have problems loading {@link DocumentBuilder}s, try:
+ *If you have problems loading {@link SAXParser}s, try:
** java -Djaxp.debug=1 YourProgram .... *@@ -117,21 +112,17 @@ public abstract class SAXParserFactory { * * @return A new instance of a SAXParserFactory. * - * @throws FactoryConfigurationError if the implementation is - * not available or cannot be instantiated. + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static SAXParserFactory newInstance() { - try { - return (SAXParserFactory) FactoryFinder.find( + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.parsers.SAXParserFactory", + SAXParserFactory.class, /* The fallback implementation class name */ "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } } /** @@ -169,13 +160,9 @@ public abstract class SAXParserFactory { * @since 1.6 */ public static SAXParserFactory newInstance(String factoryClassName, ClassLoader classLoader){ - try { //do not fallback if given classloader can't find the class, throw exception - return (SAXParserFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + return FactoryFinder.newInstance(SAXParserFactory.class, + factoryClassName, classLoader, false); } /** @@ -266,22 +253,22 @@ public abstract class SAXParserFactory { * A list of the core features and properties can be found at * http://www.saxproject.org/ * - *All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. - * When the feature is
- *- *
- * + *- - *
- *true
: the implementation will limit XML processing to conform to implementation limits. - * Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources. - * If XML processing is limited for security reasons, it will be reported via a call to the registered - * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. - * See {@link SAXParser}parse
methods for handler specification. - *- - * When the feature is
- *false
, the implementation will processing XML according to the XML specifications without - * regard to possible implementation limits. - *All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. + * When the feature is
+ *+ *
+ * * @param name The name of the feature to be set. * @param value The value of the feature to be set. * @@ -320,17 +307,6 @@ public abstract class SAXParserFactory { SAXNotSupportedException; - - /*- + *
+ *true
: the implementation will limit XML processing to conform to implementation limits. + * Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources. + * If XML processing is limited for security reasons, it will be reported via a call to the registered + * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. + * See {@link SAXParser}parse
methods for handler specification. + *- + * When the feature is
+ *false
, the implementation will processing XML according to the XML specifications without + * regard to possible implementation limits. + *Get current state of canonicalization.
- * - * @return current state canonicalization control - */ - /* - public boolean getCanonicalization() { - return canonicalState; - } - */ - /** * Gets the {@link Schema} object specified through * the {@link #setSchema(Schema schema)} method. @@ -357,17 +333,6 @@ public abstract class SAXParserFactory { ); } - /**Set canonicalization control to
- * - * @param state of canonicalization - */ - /* - public void setCanonicalization(boolean state) { - canonicalState = state; - } - */ - /** *true
or - * false.Set the {@link Schema} to be used by parsers created * from this factory.
@@ -400,7 +365,7 @@ public abstract class SAXParserFactory { * Such configuration will cause a {@link SAXException} * exception when those properties are set on a {@link SAXParser}. * - *Note for implmentors
+ *Note for implementors
** A parser must be able to work with any {@link Schema} * implementation. However, parsers and schemas are allowed diff --git a/jaxp/src/javax/xml/stream/FactoryFinder.java b/jaxp/src/javax/xml/stream/FactoryFinder.java index bcfeba10e04..68f4ef21d66 100644 --- a/jaxp/src/javax/xml/stream/FactoryFinder.java +++ b/jaxp/src/javax/xml/stream/FactoryFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,16 @@ package javax.xml.stream; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** - *
Implements pluggable Datatypes.
+ *Implements pluggable streams.
* *This class is duplicated for each JAXP subpackage so keep it in * sync. It is package private for secure class loading.
@@ -52,19 +53,19 @@ class FactoryFinder { /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + final private static Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties * have been cached. */ - static volatile boolean firstTime = true; + private static volatile boolean firstTime = true; /** * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + final private static SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -103,25 +104,25 @@ class FactoryFinder { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -133,6 +134,9 @@ class FactoryFinder { * Create an instance of a class. Delegates to method *getProviderClass()
in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -142,16 +146,19 @@ class FactoryFinder { * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, boolean doFallback) + throws FactoryConfigurationError { - return newInstance(className, cl, doFallback, false); + return newInstance(type, className, cl, doFallback, false); } /** * Create an instance of a class. Delegates to method * getProviderClass()
in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -164,9 +171,12 @@ class FactoryFinder { * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useBSClsLoader) + throws FactoryConfigurationError { + assert type != null; + // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -176,20 +186,23 @@ class FactoryFinder { } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( + throw new FactoryConfigurationError( "Provider " + className + " not found", x); } catch (Exception x) { - throw new ConfigurationError( + throw new FactoryConfigurationError( "Provider " + className + " could not be instantiated: " + x, x); } @@ -200,17 +213,18 @@ class FactoryFinder { * * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. + * * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws FactoryConfigurationError { - return find(factoryId, null, fallbackClassName); + return find(type, type.getName(), null, fallbackClassName); } /** @@ -218,6 +232,9 @@ class FactoryFinder { * entry point. * @return Class object of factory, never null * + * @param type Base class / Service interface of the + * factory to find. + * * @param factoryId Name of the factory to find, same as * a property name * @@ -229,8 +246,8 @@ class FactoryFinder { * * Package private so this code can be shared. */ - static Object find(String factoryId, ClassLoader cl, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String factoryId, ClassLoader cl, String fallbackClassName) + throws FactoryConfigurationError { dPrint("find factoryId =" + factoryId); @@ -239,7 +256,9 @@ class FactoryFinder { String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + // There's a bug here - because 'cl' is ignored. + // This will be handled separately. + return newInstance(type, systemProp, null, true); } } catch (SecurityException se) { @@ -250,7 +269,6 @@ class FactoryFinder { // $java.home/lib/jaxp.properties if former not present String configFile = null; try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -269,130 +287,80 @@ class FactoryFinder { if (ss.doesFileExist(f)) { dPrint("Read properties file "+f); cacheProps.load(ss.getFileInputStream(f)); + } + } } } } - } - } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in " + configFile + " value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + // There's a bug here - because 'cl' is ignored. + // This will be handled separately. + return newInstance(type, factoryClassName, null, true); } } catch (Exception ex) { if (debug) ex.printStackTrace(); } - // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); - if (provider != null) { - return provider; + if (type.getName().equals(factoryId)) { + // Try Jar Service Provider Mechanism + final T provider = findServiceProvider(type); + if (provider != null) { + return provider; + } + } else { + // We're in the case where a 'custom' factoryId was provided, + // and in every case where that happens, we expect that + // fallbackClassName will be null. + assert fallbackClassName == null; } if (fallbackClassName == null) { - throw new ConfigurationError( + throw new FactoryConfigurationError( "Provider for " + factoryId + " cannot be found", null); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, cl, true); + return newInstance(type, fallbackClassName, cl, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; + private static T findServiceProvider(final Class type) { try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; - } - } + return AccessController.doPrivileged(new PrivilegedAction () { + @Override + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final FactoryConfigurationError error = + new FactoryConfigurationError(x, x.getMessage()); + throw error; + } + } } diff --git a/jaxp/src/javax/xml/stream/XMLEventFactory.java b/jaxp/src/javax/xml/stream/XMLEventFactory.java index f92d77805f7..d9e47ef0727 100644 --- a/jaxp/src/javax/xml/stream/XMLEventFactory.java +++ b/jaxp/src/javax/xml/stream/XMLEventFactory.java @@ -23,14 +23,14 @@ */ /* - * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved. + * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved. */ package javax.xml.stream; -import javax.xml.stream.events.*; +import java.util.Iterator; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; -import java.util.Iterator; +import javax.xml.stream.events.*; /** * This interface defines a utility class for creating instances of * XMLEvents @@ -54,48 +54,59 @@ public abstract class XMLEventFactory { /** - * Create a new instance of the factory + * Creates a new instance of the factory in exactly the same manner as the + * {@link #newFactory()} method. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLEventFactory newInstance() throws FactoryConfigurationError { - return (XMLEventFactory) FactoryFinder.find( - JAXPFACTORYID, - DEFAULIMPL); + return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL); } /** * Create a new instance of the factory. + * * This static method creates a new factory instance. * This method uses the following ordered lookup procedure to determine * the XMLEventFactory implementation class to load: + *
+ *+ *
+ *- * Use the javax.xml.stream.XMLEventFactory system property. + *
+ *- * Use the properties file "lib/stax.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format * and contains the fully qualified name of the implementation class * with the key being the system property defined above. - * Use the Services API (as detailed in the JAR specification), if available, - * to determine the classname. The Services API will look for a classname - * in the file META-INF/services/javax.xml.stream.XMLEventFactory in jars - * available to the runtime. - * Platform default XMLEventFactory instance. - * + *
+ *- + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ *- + * Otherwise, the system-default implementation is returned. + *
+ ** Once an application has obtained a reference to a XMLEventFactory it * can use the factory to configure and obtain stream instances. - * + *
+ ** Note that this is a new method that replaces the deprecated newInstance() method. * No changes in behavior are defined by this replacement method relative to * the deprecated method. - * - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + *
+ * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLEventFactory newFactory() throws FactoryConfigurationError { - return (XMLEventFactory) FactoryFinder.find( - JAXPFACTORYID, - DEFAULIMPL); + return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL); } /** @@ -116,40 +127,59 @@ public abstract class XMLEventFactory { public static XMLEventFactory newInstance(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null); } /** * Create a new instance of the factory. * If the classLoader argument is null, then the ContextClassLoader is used. + *+ * This method uses the following ordered lookup procedure to determine + * the XMLEventFactory implementation class to load: + *
+ *+ *
* + *- + * Use the value of the system property identified by {@code factoryId}. + *
+ *- + * Use the properties file "lib/stax.properties" in the JRE directory. + * This configuration file is in standard java.util.Properties format + * and contains the fully qualified name of the implementation class + * with the key being the given {@code factoryId}. + *
+ *- + * If {@code factoryId} is "javax.xml.stream.XMLEventFactory", + * use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ *- + * Otherwise, throws a {@link FactoryConfigurationError}. + *
+ ** Note that this is a new method that replaces the deprecated - * newInstance(String factoryId, ClassLoader classLoader) method. + * {@link #newInstance(java.lang.String, java.lang.ClassLoader) + * newInstance(String factoryId, ClassLoader classLoader)} method. * No changes in behavior are defined by this replacement method relative * to the deprecated method. + *
* * @param factoryId Name of the factory to find, same as * a property name * @param classLoader classLoader to use * @return the factory implementation - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLEventFactory newFactory(String factoryId, - ClassLoader classLoader) + ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null); } /** diff --git a/jaxp/src/javax/xml/stream/XMLInputFactory.java b/jaxp/src/javax/xml/stream/XMLInputFactory.java index 48dc3675fa5..2bfbad5d461 100644 --- a/jaxp/src/javax/xml/stream/XMLInputFactory.java +++ b/jaxp/src/javax/xml/stream/XMLInputFactory.java @@ -23,13 +23,13 @@ */ /* - * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved. + * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved. */ package javax.xml.stream; -import javax.xml.transform.Source; import javax.xml.stream.util.XMLEventAllocator; +import javax.xml.transform.Source; /** * Defines an abstract implementation of a factory for getting streams. @@ -144,48 +144,59 @@ public abstract class XMLInputFactory { protected XMLInputFactory(){} /** - * Create a new instance of the factory. + * Creates a new instance of the factory in exactly the same manner as the + * {@link #newFactory()} method. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLInputFactory newInstance() throws FactoryConfigurationError { - return (XMLInputFactory) FactoryFinder.find( - "javax.xml.stream.XMLInputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL); } /** * Create a new instance of the factory. + ** This static method creates a new factory instance. * This method uses the following ordered lookup procedure to determine * the XMLInputFactory implementation class to load: + *
+ *+ *
+ *- * Use the javax.xml.stream.XMLInputFactory system property. + *
+ *- * Use the properties file "lib/stax.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format * and contains the fully qualified name of the implementation class * with the key being the system property defined above. - * Use the Services API (as detailed in the JAR specification), if available, - * to determine the classname. The Services API will look for a classname - * in the file META-INF/services/javax.xml.stream.XMLInputFactory in jars - * available to the runtime. - * Platform default XMLInputFactory instance. - * + *
+ *- + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ *- + * Otherwise, the system-default implementation is returned. + *
+ ** Once an application has obtained a reference to a XMLInputFactory it * can use the factory to configure and obtain stream instances. - * + *
+ ** Note that this is a new method that replaces the deprecated newInstance() method. * No changes in behavior are defined by this replacement method relative to * the deprecated method. - * - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + *
+ * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLInputFactory newFactory() throws FactoryConfigurationError { - return (XMLInputFactory) FactoryFinder.find( - "javax.xml.stream.XMLInputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL); } /** @@ -206,40 +217,60 @@ public abstract class XMLInputFactory { public static XMLInputFactory newInstance(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null); } /** * Create a new instance of the factory. * If the classLoader argument is null, then the ContextClassLoader is used. + *+ * This method uses the following ordered lookup procedure to determine + * the XMLInputFactory implementation class to load: + *
+ *+ *
* + *- + * Use the value of the system property identified by {@code factoryId}. + *
+ *- + * Use the properties file "lib/stax.properties" in the JRE directory. + * This configuration file is in standard java.util.Properties format + * and contains the fully qualified name of the implementation class + * with the key being the given {@code factoryId}. + *
+ *- + * If {@code factoryId} is "javax.xml.stream.XMLInputFactory", + * use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ *- + * Otherwise, throws a {@link FactoryConfigurationError}. + *
+ ** Note that this is a new method that replaces the deprecated - * newInstance(String factoryId, ClassLoader classLoader) method. + * {@link #newInstance(java.lang.String, java.lang.ClassLoader) + * newInstance(String factoryId, ClassLoader classLoader)} method. * No changes in behavior are defined by this replacement method relative * to the deprecated method. + *
* * @param factoryId Name of the factory to find, same as * a property name * @param classLoader classLoader to use * @return the factory implementation + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLInputFactory newFactory(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null); } /** diff --git a/jaxp/src/javax/xml/stream/XMLOutputFactory.java b/jaxp/src/javax/xml/stream/XMLOutputFactory.java index b0d4f0b309f..a5a593c9cd0 100644 --- a/jaxp/src/javax/xml/stream/XMLOutputFactory.java +++ b/jaxp/src/javax/xml/stream/XMLOutputFactory.java @@ -23,7 +23,7 @@ */ /* - * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved. + * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved. */ package javax.xml.stream; @@ -120,46 +120,58 @@ public abstract class XMLOutputFactory { protected XMLOutputFactory(){} /** - * Create a new instance of the factory. + * Creates a new instance of the factory in exactly the same manner as the + * {@link #newFactory()} method. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLOutputFactory newInstance() throws FactoryConfigurationError { - return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL); } /** * Create a new instance of the factory. + ** This static method creates a new factory instance. This method uses the * following ordered lookup procedure to determine the XMLOutputFactory * implementation class to load: + *
+ *+ *
- * Use the javax.xml.stream.XMLOutputFactory system property. + *
+ *- * Use the properties file "lib/stax.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format * and contains the fully qualified name of the implementation class * with the key being the system property defined above. - * Use the Services API (as detailed in the JAR specification), if available, - * to determine the classname. The Services API will look for a classname - * in the file META-INF/services/javax.xml.stream.XMLOutputFactory in jars - * available to the runtime. - * Platform default XMLOutputFactory instance. - * + *
+ *- + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ *- + * Otherwise, the system-default implementation is returned. + *
+ ** Once an application has obtained a reference to a XMLOutputFactory it * can use the factory to configure and obtain stream instances. - * + *
+ ** Note that this is a new method that replaces the deprecated newInstance() method. * No changes in behavior are defined by this replacement method relative to the * deprecated method. - * - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + *
+ * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLOutputFactory newFactory() throws FactoryConfigurationError { - return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL); } /** @@ -179,42 +191,59 @@ public abstract class XMLOutputFactory { public static XMLInputFactory newInstance(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null); } /** * Create a new instance of the factory. * If the classLoader argument is null, then the ContextClassLoader is used. + *+ * This method uses the following ordered lookup procedure to determine + * the XMLOutputFactory implementation class to load: + *
+ *+ *
* + *- + * Use the value of the system property identified by {@code factoryId}. + *
+ *- + * Use the properties file "lib/stax.properties" in the JRE directory. + * This configuration file is in standard java.util.Properties format + * and contains the fully qualified name of the implementation class + * with the key being the given {@code factoryId}. + *
+ *- + * If {@code factoryId} is "javax.xml.stream.XMLOutputFactory", + * use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ *- + * Otherwise, throws a {@link FactoryConfigurationError}. + *
+ ** Note that this is a new method that replaces the deprecated - * newInstance(String factoryId, ClassLoader classLoader) method. - * - * No changes in behavior are defined by this replacement method relative - * to the deprecated method. - * + * {@link #newInstance(java.lang.String, java.lang.ClassLoader) + * newInstance(String factoryId, ClassLoader classLoader)} method. + * No changes in behavior are defined by this replacement method relative + * to the deprecated method. + *
* * @param factoryId Name of the factory to find, same as * a property name * @param classLoader classLoader to use * @return the factory implementation - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLOutputFactory newFactory(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLOutputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLOutputFactory.class, factoryId, classLoader, null); } /** diff --git a/jaxp/src/javax/xml/transform/FactoryFinder.java b/jaxp/src/javax/xml/transform/FactoryFinder.java index 63cc8cd3f22..4ae6568aa57 100644 --- a/jaxp/src/javax/xml/transform/FactoryFinder.java +++ b/jaxp/src/javax/xml/transform/FactoryFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,15 @@ package javax.xml.transform; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** *Implements pluggable Datatypes.
@@ -53,7 +55,7 @@ class FactoryFinder { /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private final static Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties @@ -65,7 +67,7 @@ class FactoryFinder { * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private final static SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -98,31 +100,31 @@ class FactoryFinder { * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class> getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -134,24 +136,8 @@ class FactoryFinder { * Create an instance of a class. Delegates to method *getProviderClass()
in order to load the class. * - * @param className Name of the concrete class corresponding to the - * service provider - * - * @param clClassLoader
used to load the factory class. Ifnull
- * currentThread
's context classLoader is used to load the factory class. - * - * @param doFallback True if the current ClassLoader should be tried as - * a fallback if the class is not found using cl - */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError - { - return newInstance(className, cl, doFallback, false, false); - } - - /** - * Create an instance of a class. Delegates to method - *getProviderClass()
in order to load the class. + * @param type Base class / Service interface of the factory to + * instantiate. * * @param className Name of the concrete class corresponding to the * service provider @@ -162,14 +148,15 @@ class FactoryFinder { * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl * - * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter - * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. - * * @param useServicesMechanism True use services mechanism */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader, boolean useServicesMechanism) - throws ConfigurationError + staticT newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useServicesMechanism) + throws TransformerFactoryConfigurationError { + assert type != null; + + boolean useBSClsLoader = false; // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -179,10 +166,13 @@ class FactoryFinder { } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = null; if (!useServicesMechanism) { - instance = newInstanceNoServiceLoader(providerClass); + instance = newInstanceNoServiceLoader(type, providerClass); } if (instance == null) { instance = providerClass.newInstance(); @@ -191,63 +181,87 @@ class FactoryFinder { dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); + throw new TransformerFactoryConfigurationError(x, + "Provider " + className + " not found"); } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); + throw new TransformerFactoryConfigurationError(x, + "Provider " + className + " could not be instantiated: " + x); } } + /** * Try to construct using newTransformerFactoryNoServiceLoader * method if available. */ - private static Object newInstanceNoServiceLoader( - Class> providerClass - ) { + private static T newInstanceNoServiceLoader(Class type, Class> providerClass) { // Retain maximum compatibility if no security manager. if (System.getSecurityManager() == null) { return null; } try { - Method creationMethod = - providerClass.getDeclaredMethod( - "newTransformerFactoryNoServiceLoader" - ); - return creationMethod.invoke(null, (Object[])null); - } catch (NoSuchMethodException exc) { - return null; - } catch (Exception exc) { + final Method creationMethod = + providerClass.getDeclaredMethod( + "newTransformerFactoryNoServiceLoader" + ); + final int modifiers = creationMethod.getModifiers(); + + // Do not call the method if it's not public static. + if (!Modifier.isPublic(modifiers) || !Modifier.isStatic(modifiers)) { return null; + } + + // Only call the method if it's declared to return an instance of + // TransformerFactory + final Class> returnType = creationMethod.getReturnType(); + if (type.isAssignableFrom(returnType)) { + final Object result = creationMethod.invoke(null, (Object[])null); + return type.cast(result); + } else { + // This should not happen, as + // TransformerFactoryImpl.newTransformerFactoryNoServiceLoader is + // declared to return TransformerFactory. + throw new ClassCastException(returnType + " cannot be cast to " + type); + } + } catch (ClassCastException e) { + throw new TransformerFactoryConfigurationError(e, e.getMessage()); + } catch (NoSuchMethodException exc) { + return null; + } catch (Exception exc) { + return null; } } + /** * Finds the implementation Class object in the specified order. Main * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. + * * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws TransformerFactoryConfigurationError { + assert type != null; + + final String factoryId = type.getName(); + dPrint("find factoryId =" + factoryId); // Use the system property first try { String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true, false, true); + return newInstance(type, systemProp, null, true, true); } } catch (SecurityException se) { @@ -256,7 +270,6 @@ class FactoryFinder { // try to read from $java.home/lib/jaxp.properties try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -271,11 +284,11 @@ class FactoryFinder { } } } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true, false, true); + return newInstance(type, factoryClassName, null, true, true); } } catch (Exception ex) { @@ -283,113 +296,54 @@ class FactoryFinder { } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + T provider = findServiceProvider(type); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new TransformerFactoryConfigurationError(null, + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true, false, true); + return newInstance(type, fallbackClassName, null, true, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader. + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError + private static T findServiceProvider(final Class type) + throws TransformerFactoryConfigurationError { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader, true); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + try { + return AccessController.doPrivileged(new PrivilegedAction () { + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final TransformerFactoryConfigurationError error = + new TransformerFactoryConfigurationError(x, x.getMessage()); + throw error; } } - } diff --git a/jaxp/src/javax/xml/transform/TransformerFactory.java b/jaxp/src/javax/xml/transform/TransformerFactory.java index 741740cf7aa..61528855be6 100644 --- a/jaxp/src/javax/xml/transform/TransformerFactory.java +++ b/jaxp/src/javax/xml/transform/TransformerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,8 @@ public abstract class TransformerFactory { /** * Obtain a new instance of a
+ *TransformerFactory
. - * This static method creates a new factory instance - * This method uses the following ordered lookup procedure to determine + * This static method creates a new factory instance.This method uses the following ordered lookup procedure to determine * the
*TransformerFactory
implementation class to * load:@@ -67,7 +67,7 @@ public abstract class TransformerFactory { * format and contains the fully qualified name of the * implementation class with the key being the system property defined * above. - * + *
* @@ -92,22 +90,18 @@ public abstract class TransformerFactory { * * @return new TransformerFactory instance, never null. * - * @throws TransformerFactoryConfigurationError Thrown if the implementation - * is not available or cannot be instantiated. + * @throws TransformerFactoryConfigurationError Thrown in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static TransformerFactory newInstance() throws TransformerFactoryConfigurationError { - try { - return (TransformerFactory) FactoryFinder.find( + + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.transform.TransformerFactory", + TransformerFactory.class, /* The fallback implementation class name, XSLTC */ "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new TransformerFactoryConfigurationError( - e.getException(), - e.getMessage()); - } } /** @@ -147,14 +141,10 @@ public abstract class TransformerFactory { */ public static TransformerFactory newInstance(String factoryClassName, ClassLoader classLoader) throws TransformerFactoryConfigurationError{ - try { - //do not fallback if given classloader can't find the class, throw exception - return (TransformerFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new TransformerFactoryConfigurationError( - e.getException(), - e.getMessage()); - } + + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.newInstance(TransformerFactory.class, + factoryClassName, classLoader, false, false); } /** *
* The jaxp.properties file is read only once by the JAXP implementation * and it's values are then cached for future use. If the file does not exist * when the first attempt is made to read from it, no further attempts are @@ -75,14 +75,12 @@ public abstract class TransformerFactory { * of any property in jaxp.properties after it has been read for the first time. * *- - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - *
*META-INF/services/javax.xml.transform.TransformerFactory
- * in jars available to the runtime. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. *- - * Platform default
*TransformerFactory
instance. + * Otherwise, the system-default implementation is returned. *Process the
Source
into aTransformer
diff --git a/jaxp/src/javax/xml/validation/SchemaFactory.java b/jaxp/src/javax/xml/validation/SchemaFactory.java index 97b31654069..6f156af0ff5 100644 --- a/jaxp/src/javax/xml/validation/SchemaFactory.java +++ b/jaxp/src/javax/xml/validation/SchemaFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,14 @@ package javax.xml.validation; import java.io.File; import java.net.URL; - import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; - import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; /** * Factory that creates {@link Schema} objects. Entry-point to @@ -79,7 +78,7 @@ import org.xml.sax.SAXNotSupportedException; * and has a significant effect on the parsing process, it is impossible * to define the DTD validation as a process independent from parsing. * For this reason, this specification does not define the semantics for - * the XML DTD. This doesn't prohibit implentors from implementing it + * the XML DTD. This doesn't prohibit implementors from implementing it * in a way they see fit, but users are warned that any DTD * validation implemented on this interface necessarily deviate from * the XML DTD semantics as defined in the XML 1.0. @@ -147,14 +146,17 @@ public abstract class SchemaFactory { * is looked for. If present, the value is processed just like above. * *- - *
*The class loader is asked for service provider provider-configuration files matching - *
- *javax.xml.validation.SchemaFactory
in the resource directory META-INF/services. - * See the JAR File Specification for file format and parsing rules. - * Each potential service provider is required to implement the method:- * {@link #isSchemaLanguageSupported(String schemaLanguage)} - *- * The first service provider found in class loader order that supports the specified schema language is returned. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service.
+ * Each potential service provider is required to implement the method + * {@link #isSchemaLanguageSupported(String schemaLanguage)}. + *
+ * The first service provider found that supports the specified schema + * language is returned. + *
+ * In case of {@link java.util.ServiceConfigurationError} a + * {@link SchemaFactoryConfigurationError} will be thrown. *- * Platform default
*SchemaFactory
is located @@ -186,10 +188,12 @@ public abstract class SchemaFactory { * If no implementation of the schema language is available. * @throws NullPointerException * If theschemaLanguage
parameter is null. + * @throws SchemaFactoryConfigurationError + * If a configuration error is encountered. * * @see #newInstance(String schemaLanguage, String factoryClassName, ClassLoader classLoader) */ - public static final SchemaFactory newInstance(String schemaLanguage) { + public static SchemaFactory newInstance(String schemaLanguage) { ClassLoader cl; cl = ss.getContextClassLoader(); @@ -275,19 +279,19 @@ public abstract class SchemaFactory { } - /** - *Is specified schema supported by this
- * - * @param schemaLanguage Specifies the schema language which the returnedSchemaFactory
?SchemaFactory
will understand. + /** + *Is specified schema supported by this
+ * + * @param schemaLanguage Specifies the schema language which the returnedSchemaFactory
?SchemaFactory
will understand. *schemaLanguage
must specify a valid schema language. - * - * @returntrue
ifSchemaFactory
supportsschemaLanguage
, elsefalse
. - * - * @throws NullPointerException IfschemaLanguage
isnull
. - * @throws IllegalArgumentException IfschemaLanguage.length() == 0
- * orschemaLanguage
does not specify a valid schema language. - */ - public abstract boolean isSchemaLanguageSupported(String schemaLanguage); + * + * @returntrue
ifSchemaFactory
supportsschemaLanguage
, elsefalse
. + * + * @throws NullPointerException IfschemaLanguage
isnull
. + * @throws IllegalArgumentException IfschemaLanguage.length() == 0
+ * orschemaLanguage
does not specify a valid schema language. + */ + public abstract boolean isSchemaLanguageSupported(String schemaLanguage); /** * Look up the value of a feature flag. diff --git a/jaxp/src/javax/xml/validation/SchemaFactoryConfigurationError.java b/jaxp/src/javax/xml/validation/SchemaFactoryConfigurationError.java new file mode 100644 index 00000000000..47c4dda1ee6 --- /dev/null +++ b/jaxp/src/javax/xml/validation/SchemaFactoryConfigurationError.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.xml.validation; + +/** + * Thrown when a problem with configuration with the Schema Factories + * exists. This error will typically be thrown when the class of a + * schema factory specified in the system properties cannot be found + * or instantiated. + * @since 1.8 + */ +public final class SchemaFactoryConfigurationError extends Error { + + static final long serialVersionUID = 3531438703147750126L; + + /** + * Create a newSchemaFactoryConfigurationError
with no + * detail message. + */ + public SchemaFactoryConfigurationError() { + } + + + /** + * Create a newSchemaFactoryConfigurationError
with + * theString
specified as an error message. + * + * @param message The error message for the exception. + */ + public SchemaFactoryConfigurationError(String message) { + super(message); + } + + /** + * Create a newSchemaFactoryConfigurationError
with the + * givenThrowable
base cause. + * + * @param cause The exception or error to be encapsulated in a + * SchemaFactoryConfigurationError. + */ + public SchemaFactoryConfigurationError(Throwable cause) { + super(cause); + } + + /** + * Create a newSchemaFactoryConfigurationError
with the + * givenThrowable
base cause and detail message. + * + * @param cause The exception or error to be encapsulated in a + * SchemaFactoryConfigurationError. + * @param message The detail message. + */ + public SchemaFactoryConfigurationError(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java index 6ae593a105c..907e67a66fa 100644 --- a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java +++ b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,19 +25,16 @@ package javax.xml.validation; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.NoSuchElementException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** * Implementation of {@link SchemaFactory#newInstance(String)}. @@ -53,17 +50,17 @@ class SchemaFactoryFinder { /** *Take care of restrictions imposed by java security model
*/ - private static SecuritySupport ss = new SecuritySupport(); + private static final SecuritySupport ss = new SecuritySupport(); private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal"; /** *Cache properties for performance.
*/ - private static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); - /** - *First time requires initialization overhead.
- */ - private static volatile boolean firstTime = true; + /** + *First time requires initialization overhead.
+ */ + private static volatile boolean firstTime = true; static { // Use try/catch block to support applets @@ -115,7 +112,7 @@ class SchemaFactoryFinder { return; } } catch( Throwable unused ) { - ; // getContextClassLoader() undefined in JDK1.1 + // getContextClassLoader() undefined in JDK1.1 } if( classLoader==ClassLoader.getSystemClassLoader() ) { @@ -138,9 +135,13 @@ class SchemaFactoryFinder { * * @throws NullPointerException * If theschemaLanguage
parameter is null. + * @throws SchemaFactoryConfigurationError + * If a configuration error is encountered. */ public SchemaFactory newFactory(String schemaLanguage) { - if(schemaLanguage==null) throw new NullPointerException(); + if(schemaLanguage==null) { + throw new NullPointerException(); + } SchemaFactory f = _newFactory(schemaLanguage); if (f != null) { debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage); @@ -183,7 +184,6 @@ class SchemaFactoryFinder { String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties"; - String factoryClassName = null ; // try to read from $java.home/lib/jaxp.properties try { @@ -199,7 +199,7 @@ class SchemaFactoryFinder { } } } - factoryClassName = cacheProps.getProperty(propertyName); + final String factoryClassName = cacheProps.getProperty(propertyName); debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { @@ -214,21 +214,15 @@ class SchemaFactoryFinder { } } - // try META-INF/services files - Iterator sitr = createServiceFileIterator(); - while(sitr.hasNext()) { - URL resource = (URL)sitr.next(); - debugPrintln("looking into " + resource); - try { - sf = loadFromService(schemaLanguage,resource.toExternalForm(), - ss.getURLInputStream(resource)); - if(sf!=null) return sf; - } catch(IOException e) { - if( debug ) { - debugPrintln("failed to read "+resource); - e.printStackTrace(); - } - } + // Try with ServiceLoader + final SchemaFactory factoryImpl = findServiceProvider(schemaLanguage); + + // The following assertion should always be true. + // Uncomment it, recompile, and run with -ea in case of doubts: + // assert factoryImpl == null || factoryImpl.isSchemaLanguageSupported(schemaLanguage); + + if (factoryImpl != null) { + return factoryImpl; } // platform default @@ -246,8 +240,8 @@ class SchemaFactoryFinder { * @param className Name of class to create. * @return Created class ornull
. */ - private Class createClass(String className) { - Class clazz; + private Class> createClass(String className) { + Class> clazz; // make sure we have access to restricted packages boolean internal = false; if (System.getSecurityManager() != null) { @@ -256,25 +250,27 @@ class SchemaFactoryFinder { } } - try { - if (classLoader != null && !internal) { - clazz = classLoader.loadClass(className); - } else { - clazz = Class.forName(className); - } - } catch (Throwable t) { - if(debug) t.printStackTrace(); - return null; + try { + if (classLoader != null && !internal) { + clazz = Class.forName(className, false, classLoader); + } else { + clazz = Class.forName(className); } + } catch (Throwable t) { + if(debug) { + t.printStackTrace(); + } + return null; + } - return clazz; + return clazz; } /** *Creates an instance of the specified and returns it.
* * @param className - * fully qualified class name to be instanciated. + * fully qualified class name to be instantiated. * * @return null * if it fails. Error messages will be printed by this method. @@ -289,7 +285,7 @@ class SchemaFactoryFinder { debugPrintln("createInstance(" + className + ")"); // get Class from className - Class clazz = createClass(className); + Class> clazz = createClass(className); if (clazz == null) { debugPrintln("failed to getClass(" + className + ")"); return null; @@ -298,9 +294,13 @@ class SchemaFactoryFinder { // instantiate Class as a SchemaFactory try { - if (!useServicesMechanism) { - schemaFactory = (SchemaFactory) newInstanceNoServiceLoader(clazz); - } + if (!SchemaFactory.class.isAssignableFrom(clazz)) { + throw new ClassCastException(clazz.getName() + + " cannot be cast to " + SchemaFactory.class); + } + if (!useServicesMechanism) { + schemaFactory = newInstanceNoServiceLoader(clazz); + } if (schemaFactory == null) { schemaFactory = (SchemaFactory) clazz.newInstance(); } @@ -326,11 +326,12 @@ class SchemaFactoryFinder { return schemaFactory; } + /** - * Try to construct using newTransformerFactoryNoServiceLoader + * Try to construct using newXMLSchemaFactoryNoServiceLoader * method if available. */ - private static Object newInstanceNoServiceLoader( + private static SchemaFactory newInstanceNoServiceLoader( Class> providerClass ) { // Retain maximum compatibility if no security manager. @@ -338,196 +339,87 @@ class SchemaFactoryFinder { return null; } try { - Method creationMethod = + final Method creationMethod = providerClass.getDeclaredMethod( "newXMLSchemaFactoryNoServiceLoader" ); - return creationMethod.invoke(null, (Object[])null); - } catch (NoSuchMethodException exc) { + final int modifiers = creationMethod.getModifiers(); + + // Do not call the method if it's not public static. + if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { return null; - } catch (Exception exc) { - return null; - } - } + } - /** Iterator that lazily computes one value and returns it. */ - private static abstract class SingleIterator implements Iterator { - private boolean seen = false; - - public final void remove() { throw new UnsupportedOperationException(); } - public final boolean hasNext() { return !seen; } - public final Object next() { - if(seen) throw new NoSuchElementException(); - seen = true; - return value(); - } - - protected abstract Object value(); - } - - /** - * Looks up a value in a property file - * while producing all sorts of debug messages. - * - * @return null - * if there was an error. - */ - private SchemaFactory loadFromProperty( String keyName, String resourceName, InputStream in ) - throws IOException { - debugPrintln("Reading "+resourceName ); - - Properties props=new Properties(); - props.load(in); - in.close(); - String factoryClassName = props.getProperty(keyName); - if(factoryClassName != null){ - debugPrintln("found "+keyName+" = " + factoryClassName); - return createInstance(factoryClassName); - } else { - debugPrintln(keyName+" is not in the property file"); + // Only calls "newXMLSchemaFactoryNoServiceLoader" if it's + // declared to return an instance of SchemaFactory. + final Class> returnType = creationMethod.getReturnType(); + if (SERVICE_CLASS.isAssignableFrom(returnType)) { + return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null)); + } else { + // Should not happen since + // XMLSchemaFactory.newXMLSchemaFactoryNoServiceLoader is + // declared to return XMLSchemaFactory. + throw new ClassCastException(returnType + + " cannot be cast to " + SERVICE_CLASS); + } + } catch(ClassCastException e) { + throw new SchemaFactoryConfigurationError(e.getMessage(), e); + } catch (NoSuchMethodException exc) { + return null; + } catch (Exception exc) { return null; } } - /** - *Look up a value in a property file.
- * - *Set
- * - * @param schemaLanguage Schema Language to support. - * @param inputName Name ofdebug
totrue
to trace property evaluation.InputStream
. - * @param inInputStream
of properties. - * - * @returnSchemaFactory
as determined bykeyName
value ornull
if there was an error. - * - * @throws IOException If IO error reading fromin
. - */ - private SchemaFactory loadFromService( - String schemaLanguage, - String inputName, - InputStream in) - throws IOException { - - SchemaFactory schemaFactory = null; - final Class[] stringClassArray = {"".getClass()}; - final Object[] schemaLanguageObjectArray = {schemaLanguage}; - final String isSchemaLanguageSupportedMethod = "isSchemaLanguageSupported"; - - debugPrintln("Reading " + inputName); - - // read from InputStream until a match is found - BufferedReader configFile = new BufferedReader(new InputStreamReader(in)); - String line = null; - while ((line = configFile.readLine()) != null) { - // '#' is comment char - int comment = line.indexOf("#"); - switch (comment) { - case -1: break; // no comment - case 0: line = ""; break; // entire line is a comment - default: line = line.substring(0, comment); break; // trim comment - } - - // trim whitespace - line = line.trim(); - - // any content left on line? - if (line.length() == 0) { - continue; - } - - // line content is now the name of the class - Class clazz = createClass(line); - if (clazz == null) { - continue; - } - - // create an instance of the Class - try { - schemaFactory = (SchemaFactory) clazz.newInstance(); - } catch (ClassCastException classCastExcpetion) { - schemaFactory = null; - continue; - } catch (InstantiationException instantiationException) { - schemaFactory = null; - continue; - } catch (IllegalAccessException illegalAccessException) { - schemaFactory = null; - continue; - } - - // does this Class support desired Schema? - try { - Method isSchemaLanguageSupported = clazz.getMethod(isSchemaLanguageSupportedMethod, stringClassArray); - Boolean supported = (Boolean) isSchemaLanguageSupported.invoke(schemaFactory, schemaLanguageObjectArray); - if (supported.booleanValue()) { - break; - } - } catch (NoSuchMethodException noSuchMethodException) { - - } catch (IllegalAccessException illegalAccessException) { - - } catch (InvocationTargetException invocationTargetException) { - - } - schemaFactory = null; + // Call isSchemaLanguageSupported with initial context. + private boolean isSchemaLanguageSupportedBy(final SchemaFactory factory, + final String schemaLanguage, + AccessControlContext acc) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return factory.isSchemaLanguageSupported(schemaLanguage); } - - // clean up - configFile.close(); - - // return new instance of SchemaFactory or null - return schemaFactory; + }, acc); } /** - * Returns an {@link Iterator} that enumerates all - * the META-INF/services files that we care. + * Finds a service provider subclass of SchemaFactory that supports the + * given schema language using the ServiceLoader. + * + * @param schemaLanguage The schema language for which we seek a factory. + * @return A SchemaFactory supporting the specified schema language, or null + * if none is found. + * @throws SchemaFactoryConfigurationError if a configuration error is found. */ - private Iterator createServiceFileIterator() { - if (classLoader == null) { - return new SingleIterator() { - protected Object value() { - ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader(); - //return (ClassLoader.getSystemResource( SERVICE_ID )); - return ss.getResourceAsURL(classLoader, SERVICE_ID); + private SchemaFactory findServiceProvider(final String schemaLanguage) { + assert schemaLanguage != null; + // store current context. + final AccessControlContext acc = AccessController.getContext(); + try { + return AccessController.doPrivileged(new PrivilegedAction () { + public SchemaFactory run() { + final ServiceLoader loader = + ServiceLoader.load(SERVICE_CLASS); + for (SchemaFactory factory : loader) { + // restore initial context to call + // factory.isSchemaLanguageSupported + if (isSchemaLanguageSupportedBy(factory, schemaLanguage, acc)) { + return factory; + } + } + return null; // no factory found. } - }; - } else { - try { - //final Enumeration e = classLoader.getResources(SERVICE_ID); - final Enumeration e = ss.getResources(classLoader, SERVICE_ID); - if(!e.hasMoreElements()) { - debugPrintln("no "+SERVICE_ID+" file was found"); - } - - // wrap it into an Iterator. - return new Iterator() { - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return e.hasMoreElements(); - } - - public Object next() { - return e.nextElement(); - } - }; - } catch (IOException e) { - debugPrintln("failed to enumerate resources "+SERVICE_ID); - if(debug) e.printStackTrace(); - return new ArrayList().iterator(); // empty iterator - } + }); + } catch (ServiceConfigurationError error) { + throw new SchemaFactoryConfigurationError( + "Provider for " + SERVICE_CLASS + " cannot be created", error); } } - private static final Class SERVICE_CLASS = SchemaFactory.class; - private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName(); + private static final Class SERVICE_CLASS = SchemaFactory.class; - - private static String which( Class clazz ) { + private static String which( Class> clazz ) { return which( clazz.getName(), clazz.getClassLoader() ); } diff --git a/jaxp/src/javax/xml/xpath/XPathFactory.java b/jaxp/src/javax/xml/xpath/XPathFactory.java index 1fd93a7a146..d4c60d60637 100644 --- a/jaxp/src/javax/xml/xpath/XPathFactory.java +++ b/jaxp/src/javax/xml/xpath/XPathFactory.java @@ -90,7 +90,7 @@ public abstract class XPathFactory { * @throws RuntimeException When there is a failure in creating an * XPathFactory
for the default object model. */ - public static final XPathFactory newInstance() { + public static XPathFactory newInstance() { try { return newInstance(DEFAULT_OBJECT_MODEL_URI); @@ -121,14 +121,17 @@ public abstract class XPathFactory { * If present, the value is processed just like above. *- - * The class loader is asked for service provider provider-configuration files matching
*javax.xml.xpath.XPathFactory
- * in the resource directory META-INF/services. - * See the JAR File Specification for file format and parsing rules. - * Each potential service provider is required to implement the method: - *- * {@link #isObjectModelSupported(String objectModel)} - *- * The first service provider found in class loader order that supports the specified object model is returned. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
+ * Each potential service provider is required to implement the method + * {@link #isObjectModelSupported(String objectModel)}. + * The first service provider found that supports the specified object + * model is returned. + *
+ * In case of {@link java.util.ServiceConfigurationError} an + * {@link XPathFactoryConfigurationException} will be thrown. *- * Platform default
XPathFactory
is located in a platform specific way. @@ -152,43 +155,41 @@ public abstract class XPathFactory { * * @return Instance of anXPathFactory
. * - * @throws XPathFactoryConfigurationException If the specified object model is unavailable. + * @throws XPathFactoryConfigurationException If the specified object model + * is unavailable, or if there is a configuration error. * @throws NullPointerException Ifuri
isnull
. - * @throws IllegalArgumentException Ifuri
isnull
+ * @throws IllegalArgumentException Ifuri
isnull
* oruri.length() == 0
. */ - public static final XPathFactory newInstance(final String uri) + public static XPathFactory newInstance(final String uri) throws XPathFactoryConfigurationException { if (uri == null) { - throw new NullPointerException( - "XPathFactory#newInstance(String uri) cannot be called with uri == null" - ); + throw new NullPointerException( + "XPathFactory#newInstance(String uri) cannot be called with uri == null"); } - if (uri.length() == 0) { - throw new IllegalArgumentException( - "XPathFactory#newInstance(String uri) cannot be called with uri == \"\"" - ); - } + if (uri.length() == 0) { + throw new IllegalArgumentException( + "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""); + } - ClassLoader classLoader = ss.getContextClassLoader(); + ClassLoader classLoader = ss.getContextClassLoader(); if (classLoader == null) { //use the current class loader classLoader = XPathFactory.class.getClassLoader(); } - XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri); + XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri); - if (xpathFactory == null) { - throw new XPathFactoryConfigurationException( - "No XPathFactory implementation found for the object model: " - + uri - ); - } + if (xpathFactory == null) { + throw new XPathFactoryConfigurationException( + "No XPathFactory implementation found for the object model: " + + uri); + } - return xpathFactory; + return xpathFactory; } /** @@ -242,16 +243,14 @@ public abstract class XPathFactory { ClassLoader cl = classLoader; if (uri == null) { - throw new NullPointerException( - "XPathFactory#newInstance(String uri) cannot be called with uri == null" - ); + throw new NullPointerException( + "XPathFactory#newInstance(String uri) cannot be called with uri == null"); } - if (uri.length() == 0) { - throw new IllegalArgumentException( - "XPathFactory#newInstance(String uri) cannot be called with uri == \"\"" - ); - } + if (uri.length() == 0) { + throw new IllegalArgumentException( + "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""); + } if (cl == null) { cl = ss.getContextClassLoader(); @@ -260,31 +259,32 @@ public abstract class XPathFactory { XPathFactory f = new XPathFactoryFinder(cl).createInstance(factoryClassName); if (f == null) { - throw new XPathFactoryConfigurationException( - "No XPathFactory implementation found for the object model: " - + uri - ); + throw new XPathFactoryConfigurationException( + "No XPathFactory implementation found for the object model: " + + uri); } //if this factory supports the given schemalanguage return this factory else thrown exception - if(f.isObjectModelSupported(uri)){ + if (f.isObjectModelSupported(uri)) { return f; - }else{ - throw new XPathFactoryConfigurationException("Factory " + factoryClassName + " doesn't support given " + uri + " object model"); + } else { + throw new XPathFactoryConfigurationException("Factory " + + factoryClassName + " doesn't support given " + uri + + " object model"); } } - /** - *Is specified object model supported by this
- * - * @param objectModel Specifies the object model which the returnedXPathFactory
?XPathFactory
will understand. - * - * @returntrue
ifXPathFactory
supportsobjectModel
, elsefalse
. - * - * @throws NullPointerException IfobjectModel
isnull
. - * @throws IllegalArgumentException IfobjectModel.length() == 0
. - */ - public abstract boolean isObjectModelSupported(String objectModel); + /** + *Is specified object model supported by this
+ * + * @param objectModel Specifies the object model which the returnedXPathFactory
?XPathFactory
will understand. + * + * @returntrue
ifXPathFactory
supportsobjectModel
, elsefalse
. + * + * @throws NullPointerException IfobjectModel
isnull
. + * @throws IllegalArgumentException IfobjectModel.length() == 0
. + */ + public abstract boolean isObjectModelSupported(String objectModel); /** *Set a feature for this
XPathFactory
and @@ -314,8 +314,8 @@ public abstract class XPathFactory { * it creates cannot support this feature. * @throws NullPointerException ifname
isnull
. */ - public abstract void setFeature(String name, boolean value) - throws XPathFactoryConfigurationException; + public abstract void setFeature(String name, boolean value) + throws XPathFactoryConfigurationException; /** *Get the state of the named feature.
@@ -339,8 +339,8 @@ public abstract class XPathFactory { * it creates cannot support this feature. * @throws NullPointerException ifname
isnull
. */ - public abstract boolean getFeature(String name) - throws XPathFactoryConfigurationException; + public abstract boolean getFeature(String name) + throws XPathFactoryConfigurationException; /** *Establish a default variable resolver.
@@ -359,19 +359,19 @@ public abstract class XPathFactory { public abstract void setXPathVariableResolver(XPathVariableResolver resolver); /** - *Establish a default function resolver.
- * - *Any
- * - *XPath
objects constructed from this factory will - * use the specified resolver by default.A
- * - * @param resolver XPath function resolver. - * - * @throws NullPointerException IfNullPointerException
is thrown if - *resolver
isnull
.resolver
is - *null
. - */ + *Establish a default function resolver.
+ * + *Any
+ * + *XPath
objects constructed from this factory will + * use the specified resolver by default.A
+ * + * @param resolver XPath function resolver. + * + * @throws NullPointerException IfNullPointerException
is thrown if + *resolver
isnull
.resolver
is + *null
. + */ public abstract void setXPathFunctionResolver(XPathFunctionResolver resolver); /** diff --git a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java index 797b9556a0a..f99ddc8a0c2 100644 --- a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java +++ b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,16 @@ package javax.xml.xpath; -import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.NoSuchElementException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** * Implementation of {@link XPathFactory#newInstance(String)}. @@ -50,7 +46,7 @@ import java.util.Properties; class XPathFactoryFinder { private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal"; - private static SecuritySupport ss = new SecuritySupport() ; + private static final SecuritySupport ss = new SecuritySupport() ; /** debug support code. */ private static boolean debug = false; static { @@ -65,12 +61,12 @@ class XPathFactoryFinder { /** *Cache properties for performance.
*/ - private static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); - /** - *First time requires initialization overhead.
- */ - private volatile static boolean firstTime = true; + /** + *First time requires initialization overhead.
+ */ + private volatile static boolean firstTime = true; /** *Conditional debug printing.
@@ -93,9 +89,8 @@ class XPathFactoryFinder { * to findXPathFactory
. * * @param loader - * to be used to load resource, {@link XPathFactory}, and - * {@link SchemaFactoryLoader} implementations during - * the resolution process. + * to be used to load resource and {@link XPathFactory} + * implementations during the resolution process. * If this parameter is null, the default system class loader * will be used. */ @@ -113,7 +108,7 @@ class XPathFactoryFinder { return; } } catch( Throwable unused ) { - ; // getContextClassLoader() undefined in JDK1.1 + // getContextClassLoader() undefined in JDK1.1 } if( classLoader==ClassLoader.getSystemClassLoader() ) { @@ -126,7 +121,7 @@ class XPathFactoryFinder { /** *Creates a new {@link XPathFactory} object for the specified - * schema language.
+ * object model. * * @param uri * Identifies the underlying object model. @@ -136,8 +131,10 @@ class XPathFactoryFinder { * @throws NullPointerException * If the parameter is null. */ - public XPathFactory newFactory(String uri) { - if(uri==null) throw new NullPointerException(); + public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException { + if (uri == null) { + throw new NullPointerException(); + } XPathFactory f = _newFactory(uri); if (f != null) { debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri); @@ -154,8 +151,8 @@ class XPathFactoryFinder { * * @return {@link XPathFactory} for the given object model. */ - private XPathFactory _newFactory(String uri) { - XPathFactory xpathFactory; + private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException { + XPathFactory xpathFactory = null; String propertyName = SERVICE_CLASS.getName() + ":" + uri; @@ -166,7 +163,9 @@ class XPathFactoryFinder { if(r!=null) { debugPrintln("The value is '"+r+"'"); xpathFactory = createInstance(r, true); - if(xpathFactory != null) return xpathFactory; + if (xpathFactory != null) { + return xpathFactory; + } } else debugPrintln("The property is undefined."); } catch( Throwable t ) { @@ -180,8 +179,6 @@ class XPathFactoryFinder { String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties"; - String factoryClassName = null ; - // try to read from $java.home/lib/jaxp.properties try { if(firstTime){ @@ -196,7 +193,7 @@ class XPathFactoryFinder { } } } - factoryClassName = cacheProps.getProperty(propertyName); + final String factoryClassName = cacheProps.getProperty(propertyName); debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { @@ -211,23 +208,16 @@ class XPathFactoryFinder { } } - // try META-INF/services files - Iterator sitr = createServiceFileIterator(); - while(sitr.hasNext()) { - URL resource = (URL)sitr.next(); - debugPrintln("looking into " + resource); - try { - xpathFactory = loadFromService(uri, resource.toExternalForm(), - ss.getURLInputStream(resource)); - if (xpathFactory != null) { - return xpathFactory; - } - } catch(IOException e) { - if( debug ) { - debugPrintln("failed to read "+resource); - e.printStackTrace(); - } - } + // Try with ServiceLoader + assert xpathFactory == null; + xpathFactory = findServiceProvider(uri); + + // The following assertion should always be true. + // Uncomment it, recompile, and run with -ea in case of doubts: + // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri); + + if (xpathFactory != null) { + return xpathFactory; } // platform default @@ -245,8 +235,8 @@ class XPathFactoryFinder { * @param className Name of class to create. * @return Created class ornull
. */ - private Class createClass(String className) { - Class clazz; + private Class> createClass(String className) { + Class clazz; // make sure we have access to restricted packages boolean internal = false; if (System.getSecurityManager() != null) { @@ -258,47 +248,54 @@ class XPathFactoryFinder { // use approprite ClassLoader try { if (classLoader != null && !internal) { - clazz = classLoader.loadClass(className); + clazz = Class.forName(className, false, classLoader); } else { clazz = Class.forName(className); } } catch (Throwable t) { - if(debug) t.printStackTrace(); - return null; + if(debug) { + t.printStackTrace(); + } + return null; } - return clazz; + return clazz; } /** *Creates an instance of the specified and returns it.
* * @param className - * fully qualified class name to be instanciated. + * fully qualified class name to be instantiated. * * @return null * if it fails. Error messages will be printed by this method. */ - XPathFactory createInstance( String className ) { + XPathFactory createInstance( String className ) + throws XPathFactoryConfigurationException + { return createInstance( className, false ); } - XPathFactory createInstance( String className, boolean useServicesMechanism ) { + + XPathFactory createInstance( String className, boolean useServicesMechanism ) + throws XPathFactoryConfigurationException + { XPathFactory xPathFactory = null; debugPrintln("createInstance(" + className + ")"); // get Class from className - Class clazz = createClass(className); + Class> clazz = createClass(className); if (clazz == null) { - debugPrintln("failed to getClass(" + className + ")"); - return null; + debugPrintln("failed to getClass(" + className + ")"); + return null; } debugPrintln("loaded " + className + " from " + which(clazz)); // instantiate Class as a XPathFactory try { if (!useServicesMechanism) { - xPathFactory = (XPathFactory) newInstanceNoServiceLoader(clazz); + xPathFactory = newInstanceNoServiceLoader(clazz); } if (xPathFactory == null) { xPathFactory = (XPathFactory) clazz.newInstance(); @@ -329,203 +326,94 @@ class XPathFactoryFinder { * Try to construct using newXPathFactoryNoServiceLoader * method if available. */ - private static Object newInstanceNoServiceLoader( + private static XPathFactory newInstanceNoServiceLoader( Class> providerClass - ) { + ) throws XPathFactoryConfigurationException { // Retain maximum compatibility if no security manager. if (System.getSecurityManager() == null) { return null; } try { Method creationMethod = - providerClass.getDeclaredMethod( - "newXPathFactoryNoServiceLoader" - ); - return creationMethod.invoke(null, (Object[])null); - } catch (NoSuchMethodException exc) { + providerClass.getDeclaredMethod( + "newXPathFactoryNoServiceLoader" + ); + final int modifiers = creationMethod.getModifiers(); + + // Do not call "newXPathFactoryNoServiceLoader" if it's + // not public static. + if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { return null; - } catch (Exception exc) { - return null; - } - } - - /** - *Look up a value in a property file.
- * - *Set
- * - * @param objectModel URI of object model to support. - * @param inputName Name ofdebug
totrue
to trace property evaluation.InputStream
. - * @param inInputStream
of properties. - * - * @returnXPathFactory
as determined bykeyName
value ornull
if there was an error. - * - * @throws IOException If IO error reading fromin
. - */ - private XPathFactory loadFromService( - String objectModel, - String inputName, - InputStream in) - throws IOException { - - XPathFactory xPathFactory = null; - final Class[] stringClassArray = {"".getClass()}; - final Object[] objectModelObjectArray = {objectModel}; - final String isObjectModelSupportedMethod = "isObjectModelSupported"; - - debugPrintln("Reading " + inputName); - - // read from InputStream until a match is found - BufferedReader configFile = new BufferedReader(new InputStreamReader(in)); - String line = null; - while ((line = configFile.readLine()) != null) { - // '#' is comment char - int comment = line.indexOf("#"); - switch (comment) { - case -1: break; // no comment - case 0: line = ""; break; // entire line is a comment - default: line = line.substring(0, comment); break; // trim comment - } - - // trim whitespace - line = line.trim(); - - // any content left on line? - if (line.length() == 0) { - continue; - } - - // line content is now the name of the class - Class clazz = createClass(line); - if (clazz == null) { - continue; - } - - // create an instance of the Class - try { - xPathFactory = (XPathFactory) clazz.newInstance(); - } catch (ClassCastException classCastExcpetion) { - xPathFactory = null; - continue; - } catch (InstantiationException instantiationException) { - xPathFactory = null; - continue; - } catch (IllegalAccessException illegalAccessException) { - xPathFactory = null; - continue; - } - - // does this Class support desired object model? - try { - Method isObjectModelSupported = clazz.getMethod(isObjectModelSupportedMethod, stringClassArray); - Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray); - if (supported.booleanValue()) { - break; - } - - } catch (NoSuchMethodException noSuchMethodException) { - - } catch (IllegalAccessException illegalAccessException) { - - } catch (InvocationTargetException invocationTargetException) { - - } - xPathFactory = null; } - // clean up - configFile.close(); - - // return new instance of XPathFactory or null - return xPathFactory; - } - - /** Iterator that lazily computes one value and returns it. */ - private static abstract class SingleIterator implements Iterator { - private boolean seen = false; - - public final void remove() { throw new UnsupportedOperationException(); } - public final boolean hasNext() { return !seen; } - public final Object next() { - if(seen) throw new NoSuchElementException(); - seen = true; - return value(); - } - - protected abstract Object value(); - } - - /** - * Looks up a value in a property file - * while producing all sorts of debug messages. - * - * @return null - * if there was an error. - */ - private XPathFactory loadFromProperty( String keyName, String resourceName, InputStream in ) - throws IOException { - debugPrintln("Reading "+resourceName ); - - Properties props = new Properties(); - props.load(in); - in.close(); - String factoryClassName = props.getProperty(keyName); - if(factoryClassName != null){ - debugPrintln("found "+keyName+" = " + factoryClassName); - return createInstance(factoryClassName, true); - } else { - debugPrintln(keyName+" is not in the property file"); + // Only calls "newXPathFactoryNoServiceLoader" if it's + // declared to return an instance of XPathFactory. + final Class> returnType = creationMethod.getReturnType(); + if (SERVICE_CLASS.isAssignableFrom(returnType)) { + return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null)); + } else { + // Should not happen since + // XPathFactoryImpl.newXPathFactoryNoServiceLoader is + // declared to return XPathFactory. + throw new ClassCastException(returnType + + " cannot be cast to " + SERVICE_CLASS); + } + } catch (ClassCastException e) { + throw new XPathFactoryConfigurationException(e); + } catch (NoSuchMethodException exc) { + return null; + } catch (Exception exc) { return null; } } + // Call isObjectModelSupportedBy with initial context. + private boolean isObjectModelSupportedBy(final XPathFactory factory, + final String objectModel, + AccessControlContext acc) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return factory.isObjectModelSupported(objectModel); + } + }, acc); + } + /** - * Returns an {@link Iterator} that enumerates all - * the META-INF/services files that we care. + * Finds a service provider subclass of XPathFactory that supports the + * given object model using the ServiceLoader. + * + * @param objectModel URI of object model to support. + * @return An XPathFactory supporting the specified object model, or null + * if none is found. + * @throws XPathFactoryConfigurationException if a configuration error is found. */ - private Iterator createServiceFileIterator() { - if (classLoader == null) { - return new SingleIterator() { - protected Object value() { - ClassLoader classLoader = XPathFactoryFinder.class.getClassLoader(); - return ss.getResourceAsURL(classLoader, SERVICE_ID); - //return (ClassLoader.getSystemResource( SERVICE_ID )); + private XPathFactory findServiceProvider(final String objectModel) + throws XPathFactoryConfigurationException { + + assert objectModel != null; + // store current context. + final AccessControlContext acc = AccessController.getContext(); + try { + return AccessController.doPrivileged(new PrivilegedAction () { + public XPathFactory run() { + final ServiceLoader loader = + ServiceLoader.load(SERVICE_CLASS); + for (XPathFactory factory : loader) { + // restore initial context to call + // factory.isObjectModelSupportedBy + if (isObjectModelSupportedBy(factory, objectModel, acc)) { + return factory; + } + } + return null; // no factory found. } - }; - } else { - try { - //final Enumeration e = classLoader.getResources(SERVICE_ID); - final Enumeration e = ss.getResources(classLoader, SERVICE_ID); - if(!e.hasMoreElements()) { - debugPrintln("no "+SERVICE_ID+" file was found"); - } - - // wrap it into an Iterator. - return new Iterator() { - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return e.hasMoreElements(); - } - - public Object next() { - return e.nextElement(); - } - }; - } catch (IOException e) { - debugPrintln("failed to enumerate resources "+SERVICE_ID); - if(debug) e.printStackTrace(); - return new ArrayList().iterator(); // empty iterator - } + }); + } catch (ServiceConfigurationError error) { + throw new XPathFactoryConfigurationException(error); } } - private static final Class SERVICE_CLASS = XPathFactory.class; - private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName(); - - + private static final Class SERVICE_CLASS = XPathFactory.class; private static String which( Class clazz ) { return which( clazz.getName(), clazz.getClassLoader() ); diff --git a/jaxws/.hgtags b/jaxws/.hgtags index c129b5def61..484ab7d1111 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -209,3 +209,4 @@ a1dcc0d83da1e07f3ada60ef110dd105d95d3554 jdk8-b83 8c0b6bccfe474576d6b30d1582c4329029330150 jdk8-b85 a5e7c2f093c9996ab3419db1565094a07b059e9c jdk8-b86 72e03566f0a61282cc48ebc869803b256cccd66c jdk8-b87 +24fa5452e5d4e9df8b85196283275a6ca4b4adb4 jdk8-b88 diff --git a/jdk/.hgtags b/jdk/.hgtags index 1c4e24bef66..116dcf0c38d 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -209,3 +209,4 @@ ac519af51769e92c51b597a730974e8607357709 jdk8-b83 296676d534c52888c36e305a2bf7f345c4ca70f8 jdk8-b85 7989cd0cc3a9149864589438ee2c949015d8aa9a jdk8-b86 d5228e624826a10ccc5b05f30ad8d839b58fe48d jdk8-b87 +8dbb4b159e04de3c447c9242c70505e71f8624c7 jdk8-b88 diff --git a/jdk/make/docs/CORE_PKGS.gmk b/jdk/make/docs/CORE_PKGS.gmk index d55bb8b664e..1a5e7363048 100644 --- a/jdk/make/docs/CORE_PKGS.gmk +++ b/jdk/make/docs/CORE_PKGS.gmk @@ -142,6 +142,7 @@ CORE_PKGS = \ java.util.prefs \ java.util.regex \ java.util.spi \ + java.util.stream \ java.util.zip \ javax.accessibility \ javax.activation \ diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index 47184e3dd7b..1bdbdf03b31 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -252,6 +252,7 @@ JAVA_JAVA_java = \ java/util/Scanner.java \ java/util/InputMismatchException.java \ java/util/Stack.java \ + java/util/StringJoiner.java \ java/util/StringTokenizer.java \ java/util/TimeZone.java \ java/util/SimpleTimeZone.java \ diff --git a/jdk/make/netbeans/common/closed-share-sources.ent b/jdk/make/netbeans/common/closed-share-sources.ent index 91c6b9cadbf..03c7cda142e 100644 --- a/jdk/make/netbeans/common/closed-share-sources.ent +++ b/jdk/make/netbeans/common/closed-share-sources.ent @@ -37,6 +37,7 @@ ${root}/src/closed/share/classes ${includes} ${excludes} +US-ASCII diff --git a/jdk/make/netbeans/common/demo-view.ent b/jdk/make/netbeans/common/demo-view.ent index 5ae4e5abe84..43aa3141f57 100644 --- a/jdk/make/netbeans/common/demo-view.ent +++ b/jdk/make/netbeans/common/demo-view.ent @@ -31,7 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + ${root}/src/share/demo ${demos} diff --git a/jdk/make/netbeans/common/java-data-native.ent b/jdk/make/netbeans/common/java-data-native.ent index 8db2a86d618..54c7486aafb 100644 --- a/jdk/make/netbeans/common/java-data-native.ent +++ b/jdk/make/netbeans/common/java-data-native.ent @@ -1,7 +1,7 @@ -+ ${root}/test ${jtreg.tests} diff --git a/jdk/make/netbeans/common/macosx-sources.ent b/jdk/make/netbeans/common/macosx-sources.ent new file mode 100644 index 00000000000..779ec604f63 --- /dev/null +++ b/jdk/make/netbeans/common/macosx-sources.ent @@ -0,0 +1,49 @@ + + + + + ++ + +java +${root}/src/macosx/classes +${includes} +${excludes} +US-ASCII ++ + diff --git a/jdk/make/netbeans/common/macosx-view.ent b/jdk/make/netbeans/common/macosx-view.ent new file mode 100644 index 00000000000..8696adb6e25 --- /dev/null +++ b/jdk/make/netbeans/common/macosx-view.ent @@ -0,0 +1,43 @@ + + + + + +${root}/src/macosx/classes ++ + diff --git a/jdk/make/netbeans/common/properties.ent b/jdk/make/netbeans/common/properties.ent index 482ea1a727b..dbf304e8d86 100644 --- a/jdk/make/netbeans/common/properties.ent +++ b/jdk/make/netbeans/common/properties.ent @@ -41,3 +41,5 @@${root}/src/macosx/classes +${includes} +${excludes} +${user.home}/.openjdk/build.properties build.properties ${java.home}/.. +${env.JT_HOME} +** diff --git a/jdk/make/netbeans/common/sample-view.ent b/jdk/make/netbeans/common/sample-view.ent index 5326f48122e..c2f63479901 100644 --- a/jdk/make/netbeans/common/sample-view.ent +++ b/jdk/make/netbeans/common/sample-view.ent @@ -1,7 +1,7 @@ -+ ${root}/src/share/sample ${samples} diff --git a/jdk/make/netbeans/common/share-sources.ent b/jdk/make/netbeans/common/share-sources.ent index efa90bacd0b..3d995a4489d 100644 --- a/jdk/make/netbeans/common/share-sources.ent +++ b/jdk/make/netbeans/common/share-sources.ent @@ -37,6 +37,7 @@${root}/src/share/classes ${includes} ${excludes} +US-ASCII diff --git a/jdk/make/netbeans/common/shared.xml b/jdk/make/netbeans/common/shared.xml index ba104445273..36d57de7c43 100644 --- a/jdk/make/netbeans/common/shared.xml +++ b/jdk/make/netbeans/common/shared.xml @@ -276,7 +276,7 @@ - + @@ -338,7 +338,7 @@ - diff --git a/jdk/make/netbeans/common/unix-sources.ent b/jdk/make/netbeans/common/unix-sources.ent index da3980b0835..0c55fe34642 100644 --- a/jdk/make/netbeans/common/unix-sources.ent +++ b/jdk/make/netbeans/common/unix-sources.ent @@ -41,6 +41,7 @@ ${root}/src/solaris/classes ${includes} ${excludes} +US-ASCII diff --git a/jdk/make/netbeans/common/windows-sources.ent b/jdk/make/netbeans/common/windows-sources.ent index d50a91b45b7..6d5425a912d 100644 --- a/jdk/make/netbeans/common/windows-sources.ent +++ b/jdk/make/netbeans/common/windows-sources.ent @@ -37,6 +37,7 @@ ${root}/src/windows/classes ${includes} ${excludes} +US-ASCII diff --git a/jdk/make/netbeans/j2se/nbproject/project.xml b/jdk/make/netbeans/j2se/nbproject/project.xml index 784ab7232b8..dd15578f98a 100644 --- a/jdk/make/netbeans/j2se/nbproject/project.xml +++ b/jdk/make/netbeans/j2se/nbproject/project.xml @@ -1,7 +1,7 @@ + + -+ + diff --git a/jdk/make/netbeans/jdbc/nbproject/project.xml b/jdk/make/netbeans/jdbc/nbproject/project.xml new file mode 100644 index 00000000000..af7e5580b69 --- /dev/null +++ b/jdk/make/netbeans/jdbc/nbproject/project.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + +]> ++ + + + + ++ + ++ ++ + + + + ++ + diff --git a/jdk/make/netbeans/world/nbproject/project.xml b/jdk/make/netbeans/world/nbproject/project.xml index 8c9ad4508d1..7f2f437905e 100644 --- a/jdk/make/netbeans/world/nbproject/project.xml +++ b/jdk/make/netbeans/world/nbproject/project.xml @@ -1,7 +1,7 @@ "); + assertEquals(sj.length(), 4); + assertEquals(sj.toString().length(), sj.length()); + sj.add("abcdef"); + assertEquals(sj.length(), 10); + assertEquals(sj.toString().length(), sj.length()); + sj.add("xyz"); + assertEquals(sj.length(), 15); + assertEquals(sj.toString().length(), sj.length()); + } + + public void noAddAndEmptyValue() { + StringJoiner sj = new StringJoiner(DASH, "", "").setEmptyValue(EMPTY); + assertEquals(sj.toString(), EMPTY); + + sj = new StringJoiner(DASH, "<..", ""); + assertEquals(sj.toString(), "<.."); + + sj = new StringJoiner(DASH, "<..", ""); + assertEquals(sj.toString(), "<.."); + + sj = new StringJoiner(DASH, "", "==>"); + assertEquals(sj.toString(), "==>"); + + sj = new StringJoiner(DASH, "{", "}"); + assertEquals(sj.toString(), "{}"); + } + + @Test(expectedExceptions = {NullPointerException.class}) + public void setEmptyValueNull() { + new StringJoiner(DASH, "{", "}").setEmptyValue(null); + } + + @Test(expectedExceptions = {NullPointerException.class}) + public void setDelimiterNull() { + new StringJoiner(null); + } + + @Test(expectedExceptions = {NullPointerException.class}) + public void setPrefixNull() { + new StringJoiner(DASH, null, "}"); + } + + @Test(expectedExceptions = {NullPointerException.class}) + public void setSuffixNull() { + new StringJoiner(DASH, "{", null); + } + + public void stringFromtoString() { + StringJoiner sj = new StringJoiner(", "); + assertEquals(sj.toString(), ""); + sj = new StringJoiner(",", "{", "}"); + assertEquals(sj.toString(), "{}"); + + sj = new StringJoiner(","); + sj.add(ONE); + assertEquals(sj.toString(), ONE); + + sj.add(TWO); + assertEquals(sj.toString(), ONE + "," + TWO); + + sj = new StringJoiner(",", "{--", "--}"); + sj.add(ONE); + sj.add(TWO); + assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}"); + + } + + public void stringFromtoStringWithEmptyValue() { + StringJoiner sj = new StringJoiner(" ", "", ""); + assertEquals(sj.toString(), ""); + sj = new StringJoiner(", "); + assertEquals(sj.toString(), ""); + sj = new StringJoiner(",", "{", "}"); + assertEquals(sj.toString(), "{}"); + + sj = new StringJoiner(",", "{", "}").setEmptyValue(""); + assertEquals(sj.toString(), ""); + + sj = new StringJoiner(","); + sj.add(ONE); + assertEquals(sj.toString(), ONE); + + sj.add(TWO); + assertEquals(sj.toString(), ONE + "," + TWO); + + sj = new StringJoiner(",", "{--", "--}"); + sj.add(ONE); + assertEquals(sj.toString(), "{--" + ONE + "--}" ); + + sj.add(TWO); + assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}"); + + } + + public void toStringWithCustomEmptyValue() { + StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY); + assertEquals(sj.toString(), EMPTY); + sj.add(""); + assertEquals(sj.toString(), "<>"); + sj.add(""); + assertEquals(sj.toString(), "<->"); + } + + private void testCombos(String infix, String prefix, String suffix) { + StringJoiner sj = new StringJoiner(infix, prefix, suffix); + assertEquals(sj.toString(), prefix + suffix); + assertEquals(sj.toString().length(), sj.length()); + // EmptyValue + sj = new StringJoiner(infix, prefix, suffix).setEmptyValue("org.netbeans.modules.ant.freeform ++ ++ + &java-data-no-native; +JDBC ++ +jdbc + &properties; ++ &share-sources; + &jtreg-sources; + &build-folder; + ++ &standard-bindings; + ++ +run ++ +debug ++ +debug ++ ++ &share-view; + &jtreg-view; + &file-view; + ++ &standard-actions; + ++ + + "); + assertEquals(sj.toString(), " "); + assertEquals(sj.toString().length(), sj.length()); + + // empty in front + sj.add(""); + assertEquals(sj.toString(), prefix + suffix); + // empty in middle + sj.add(""); + assertEquals(sj.toString(), prefix + infix + suffix); + sj.add("1"); + assertEquals(sj.toString(), prefix + infix + infix + "1" + suffix); + // empty at end + sj.add(""); + assertEquals(sj.toString(), prefix + infix + infix + "1" + infix + suffix); + + sj = new StringJoiner(infix, prefix, suffix).setEmptyValue(" "); + sj.add("1"); + assertEquals(sj.toString(), prefix + "1" + suffix); + sj.add("2"); + assertEquals(sj.toString(), prefix + "1" + infix + "2" + suffix); + sj.add(""); + assertEquals(sj.toString(), prefix + "1" + infix + "2" +infix + suffix); + sj.add("3"); + assertEquals(sj.toString(), prefix + "1" + infix + "2" +infix + infix + "3" + suffix); + } + + public void testDelimiterCombinations() { + testCombos("", "", ""); + testCombos("", "<", ""); + testCombos("", "", ">"); + testCombos("", "<", ">"); + testCombos(",", "", ""); + testCombos(",", "<", ""); + testCombos(",", "", ">"); + testCombos(",", "<", ">"); + } +} + diff --git a/jdk/test/java/util/logging/DrainFindDeadlockTest.java b/jdk/test/java/util/logging/DrainFindDeadlockTest.java new file mode 100644 index 00000000000..13a959c07ff --- /dev/null +++ b/jdk/test/java/util/logging/DrainFindDeadlockTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.lang.Thread.State; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.logging.LogManager; +import java.util.logging.Logger; +import java.util.Map; + +/** + * @test + * @bug 8010939 + * @summary check for deadlock between findLogger() and drainLoggerRefQueueBounded() + * @author jim.gish@oracle.com + * @build DrainFindDeadlockTest + * @run main/othervm/timeout=10 DrainFindDeadlockTest + */ + +/** + * This test is checking for a deadlock between + * LogManager$LoggerContext.findLogger() and + * LogManager.drainLoggerRefQueueBounded() (which could happen by calling + * Logger.getLogger() and LogManager.readConfiguration() in different threads) + */ +public class DrainFindDeadlockTest { + private LogManager mgr = LogManager.getLogManager(); + private final static int MAX_ITERATIONS = 100; + + // Get a ThreadMXBean so we can check for deadlock. N.B. this may + // not be supported on all platforms, which means we will have to + // resort to the traditional test timeout method. However, if + // we have the support we'll get the deadlock details if one + // is detected. + private final static ThreadMXBean threadMXBean = + ManagementFactory.getThreadMXBean(); + private final boolean threadMXBeanDeadlockSupported = + threadMXBean.isSynchronizerUsageSupported(); + + public static void main(String... args) throws IOException, Exception { + new DrainFindDeadlockTest().testForDeadlock(); + } + + public static void randomDelay() { + int runs = (int) Math.random() * 1000000; + int c = 0; + + for (int i=0; i threadMap = + Thread.getAllStackTraces(); + dumpStack(threadMap.get(x), x); + dumpStack(threadMap.get(y), y); + } + } + + private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) { + if (aStackElt != null) { + System.out.println("Thread:" + aThread.getName() + ": " + + aThread.getState()); + for (StackTraceElement element: aStackElt) { + System.out.println(" " + element); + } + } + } + + @Override + public void run() { + System.out.println("Running " + Thread.currentThread().getName()); + for (int i=0; i < MAX_ITERATIONS*2; i++) { + checkState(t1, t2); + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + }; + } + } + } +} diff --git a/jdk/test/java/util/logging/bundlesearch/ClassPathTestBundle_en.properties b/jdk/test/java/util/logging/bundlesearch/ClassPathTestBundle_en.properties new file mode 100644 index 00000000000..71848703ed2 --- /dev/null +++ b/jdk/test/java/util/logging/bundlesearch/ClassPathTestBundle_en.properties @@ -0,0 +1,25 @@ +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +sample1=translation #2 for sample1 +sample2=translation #2 for sample2 +supports-test=ResourceBundleSearchTest diff --git a/jdk/test/java/util/logging/bundlesearch/IndirectlyLoadABundle.java b/jdk/test/java/util/logging/bundlesearch/IndirectlyLoadABundle.java new file mode 100644 index 00000000000..76dc1232f22 --- /dev/null +++ b/jdk/test/java/util/logging/bundlesearch/IndirectlyLoadABundle.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; + +/** + * This class is used to ensure that a resource bundle loadable by a classloader + * is on the caller's stack, but not on the classpath or TCCL to ensure that + * Logger.getLogger() can't load the bundle via a stack search + * + * @author Jim Gish + */ +public class IndirectlyLoadABundle { + + private final static String rbName = "StackSearchableResource"; + + public boolean loadAndTest() throws Throwable { + // Find out where we are running from so we can setup the URLClassLoader URLs + // test.src and test.classes will be set if running in jtreg, but probably + // not otherwise + String testDir = System.getProperty("test.src", System.getProperty("user.dir")); + String testClassesDir = System.getProperty("test.classes", + System.getProperty("user.dir")); + String sep = System.getProperty("file.separator"); + + URL[] urls = new URL[2]; + + // Allow for both jtreg and standalone cases here + urls[0] = Paths.get(testDir, "resources").toUri().toURL(); + urls[1] = Paths.get(testClassesDir).toUri().toURL(); + + System.out.println("INFO: urls[0] = " + urls[0]); + System.out.println("INFO: urls[1] = " + urls[1]); + + // Make sure we can find it via the URLClassLoader + URLClassLoader yetAnotherResourceCL = new URLClassLoader(urls, null); + if (!testForValidResourceSetup(yetAnotherResourceCL)) { + throw new Exception("Couldn't directly load bundle " + rbName + + " as expected. Test config problem"); + } + // But it shouldn't be available via the system classloader + ClassLoader myCL = this.getClass().getClassLoader(); + if (testForValidResourceSetup(myCL)) { + throw new Exception("Was able to directly load bundle " + rbName + + " from " + myCL + " but shouldn't have been" + + " able to. Test config problem"); + } + + Class> loadItUpClazz = Class.forName("LoadItUp", true, yetAnotherResourceCL); + ClassLoader actual = loadItUpClazz.getClassLoader(); + if (actual != yetAnotherResourceCL) { + throw new Exception("LoadItUp was loaded by an unexpected CL: " + actual); + } + Object loadItUp = loadItUpClazz.newInstance(); + Method testMethod = loadItUpClazz.getMethod("test", String.class); + try { + return (Boolean) testMethod.invoke(loadItUp, rbName); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + private boolean testForValidResourceSetup(ClassLoader cl) { + // First make sure the test environment is setup properly and the bundle actually + // exists + return ResourceBundleSearchTest.isOnClassPath(rbName, cl); + } +} diff --git a/jdk/test/java/util/logging/bundlesearch/LoadItUp.java b/jdk/test/java/util/logging/bundlesearch/LoadItUp.java new file mode 100644 index 00000000000..d47b9a3e144 --- /dev/null +++ b/jdk/test/java/util/logging/bundlesearch/LoadItUp.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.util.MissingResourceException; +import java.util.logging.Logger; + +/* + * This class is loaded onto the call stack when the test method is called + * and then its classloader can be used to find a property bundle in the same + * directory as the class. However, Logger is not allowed + * to find the bundle by looking up the stack for this classloader. + * We verify that this cannot happen. + * + * @author Jim Gish + */ +public class LoadItUp { + + private final static boolean DEBUG = false; + + public Boolean test(String rbName) throws Exception { + // we should not be able to find the resource in this directory via + // getLogger calls. The only way that would be possible given this setup + // is that if Logger.getLogger searched up the call stack + return lookupBundle(rbName); + } + + private boolean lookupBundle(String rbName) { + // See if Logger.getLogger can find the resource in this directory + try { + Logger aLogger = Logger.getLogger("NestedLogger", rbName); + } catch (MissingResourceException re) { + if (DEBUG) { + System.out.println( + "As expected, LoadItUp.lookupBundle() did not find the bundle " + + rbName); + } + return false; + } + System.out.println("FAILED: LoadItUp.lookupBundle() found the bundle " + + rbName + " using a stack search."); + return true; + } +} diff --git a/jdk/test/java/util/logging/bundlesearch/ResourceBundleSearchTest.java b/jdk/test/java/util/logging/bundlesearch/ResourceBundleSearchTest.java new file mode 100644 index 00000000000..00f1840042b --- /dev/null +++ b/jdk/test/java/util/logging/bundlesearch/ResourceBundleSearchTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8002070 + * @summary Remove the stack search for a resource bundle Logger to use + * @author Jim Gish + * @build ResourceBundleSearchTest IndirectlyLoadABundle LoadItUp + * @run main ResourceBundleSearchTest + */ +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.logging.Logger; + +public class ResourceBundleSearchTest { + + private final static boolean DEBUG = false; + private final static String LOGGER_PREFIX = "myLogger."; + private static int loggerNum = 0; + private final static String PROP_RB_NAME = "ClassPathTestBundle"; + private final static String TCCL_TEST_BUNDLE = "ContextClassLoaderTestBundle"; + + private static int numPass = 0; + private static int numFail = 0; + private static List msgs = new ArrayList<>(); + + public static void main(String[] args) throws Throwable { + ResourceBundleSearchTest test = new ResourceBundleSearchTest(); + test.runTests(); + } + + private void runTests() throws Throwable { + // ensure we are using en as the default Locale so we can find the resource + Locale.setDefault(Locale.ENGLISH); + + String testClasses = System.getProperty("test.classes"); + System.out.println( "test.classes = " + testClasses ); + + ClassLoader myClassLoader = ClassLoader.getSystemClassLoader(); + + // Find out where we are running from so we can setup the URLClassLoader URL + String userDir = System.getProperty("user.dir"); + String testDir = System.getProperty("test.src", userDir); + String sep = System.getProperty("file.separator"); + + URL[] urls = new URL[1]; + + urls[0] = Paths.get(testDir, "resources").toUri().toURL(); + URLClassLoader rbClassLoader = new URLClassLoader(urls); + + // Test 1 - can we find a Logger bundle from doing a stack search? + // We shouldn't be able to + assertFalse(testGetBundleFromStackSearch(), "testGetBundleFromStackSearch"); + + // Test 2 - can we find a Logger bundle off of the Thread context class + // loader? We should be able to. + assertTrue( + testGetBundleFromTCCL(TCCL_TEST_BUNDLE, rbClassLoader), + "testGetBundleFromTCCL"); + + // Test 3 - Can we find a Logger bundle from the classpath? We should be + // able to, but .... + // We check to see if the bundle is on the classpath or not so that this + // will work standalone. In the case of jtreg/samevm, + // the resource bundles are not on the classpath. Running standalone + // (or othervm), they are + if (isOnClassPath(PROP_RB_NAME, myClassLoader)) { + debug("We should be able to see " + PROP_RB_NAME + " on the classpath"); + assertTrue(testGetBundleFromSystemClassLoader(PROP_RB_NAME), + "testGetBundleFromSystemClassLoader"); + } else { + debug("We should not be able to see " + PROP_RB_NAME + " on the classpath"); + assertFalse(testGetBundleFromSystemClassLoader(PROP_RB_NAME), + "testGetBundleFromSystemClassLoader"); + } + + report(); + } + + private void report() throws Exception { + System.out.println("Num passed = " + numPass + " Num failed = " + numFail); + if (numFail > 0) { + // We only care about the messages if they were errors + for (String msg : msgs) { + System.out.println(msg); + } + throw new Exception(numFail + " out of " + (numPass + numFail) + + " tests failed."); + } + } + + public void assertTrue(boolean testResult, String testName) { + if (testResult) { + numPass++; + } else { + numFail++; + System.out.println("FAILED: " + testName + + " was supposed to return true but did NOT!"); + } + } + + public void assertFalse(boolean testResult, String testName) { + if (!testResult) { + numPass++; + } else { + numFail++; + System.out.println("FAILED: " + testName + + " was supposed to return false but did NOT!"); + } + } + + public boolean testGetBundleFromStackSearch() throws Throwable { + // This should fail. This was the old functionality to search up the + // caller's call stack + IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); + return indirectLoader.loadAndTest(); + } + + public boolean testGetBundleFromTCCL(String bundleName, + ClassLoader setOnTCCL) throws InterruptedException { + // This should succeed. We should be able to get the bundle from the + // thread context class loader + debug("Looking for " + bundleName + " using TCCL"); + LoggingThread lr = new LoggingThread(bundleName, setOnTCCL); + lr.start(); + synchronized (lr) { + try { + lr.wait(); + } catch (InterruptedException ex) { + throw ex; + } + } + msgs.add(lr.msg); + return lr.foundBundle; + } + + /* + * @param String bundleClass + * @param ClassLoader to use for search + * @return true iff bundleClass is on system classpath + */ + public static boolean isOnClassPath(String baseName, ClassLoader cl) { + ResourceBundle rb = null; + try { + rb = ResourceBundle.getBundle(baseName, Locale.getDefault(), cl); + System.out.println("INFO: Found bundle " + baseName + " on " + cl); + } catch (MissingResourceException e) { + System.out.println("INFO: Could not find bundle " + baseName + " on " + cl); + return false; + } + return (rb != null); + } + + private static String newLoggerName() { + // we need a new logger name every time we attempt to find a bundle via + // the Logger.getLogger call, so we'll simply tack on an integer which + // we increment each time this is called + loggerNum++; + return LOGGER_PREFIX + loggerNum; + } + + public boolean testGetBundleFromSystemClassLoader(String bundleName) { + // this should succeed if the bundle is on the system classpath. + try { + Logger aLogger = Logger.getLogger(ResourceBundleSearchTest.newLoggerName(), + bundleName); + } catch (MissingResourceException re) { + msgs.add("INFO: testGetBundleFromSystemClassLoader() did not find bundle " + + bundleName); + return false; + } + msgs.add("INFO: testGetBundleFromSystemClassLoader() found the bundle " + + bundleName); + return true; + } + + public static class LoggingThread extends Thread { + + boolean foundBundle = false; + String msg = null; + ClassLoader clToSetOnTCCL = null; + String bundleName = null; + + public LoggingThread(String bundleName) { + this.bundleName = bundleName; + } + + public LoggingThread(String bundleName, ClassLoader setOnTCCL) { + this.clToSetOnTCCL = setOnTCCL; + this.bundleName = bundleName; + } + + public void run() { + boolean setTCCL = false; + try { + if (clToSetOnTCCL != null) { + Thread.currentThread().setContextClassLoader(clToSetOnTCCL); + setTCCL = true; + } + // this should succeed if the bundle is on the system classpath. + try { + Logger aLogger = Logger.getLogger(ResourceBundleSearchTest.newLoggerName(), + bundleName); + msg = "INFO: LoggingRunnable() found the bundle " + bundleName + + (setTCCL ? " with " : " without ") + "setting the TCCL"; + foundBundle = true; + } catch (MissingResourceException re) { + msg = "INFO: LoggingRunnable() did not find the bundle " + bundleName + + (setTCCL ? " with " : " without ") + "setting the TCCL"; + foundBundle = false; + } + } catch (Throwable e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + private void debug(String msg) { + if (DEBUG) { + System.out.println(msg); + } + } +} diff --git a/jdk/test/java/util/logging/bundlesearch/resources/ContextClassLoaderTestBundle_en.properties b/jdk/test/java/util/logging/bundlesearch/resources/ContextClassLoaderTestBundle_en.properties new file mode 100644 index 00000000000..ad4085ad164 --- /dev/null +++ b/jdk/test/java/util/logging/bundlesearch/resources/ContextClassLoaderTestBundle_en.properties @@ -0,0 +1,25 @@ +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +sample1=translation #3 for sample1 +sample2=translation #3 for sample2 +supports-test=ResourceBundleSearchTest diff --git a/jdk/test/java/util/logging/bundlesearch/resources/StackSearchableResource_en.properties b/jdk/test/java/util/logging/bundlesearch/resources/StackSearchableResource_en.properties new file mode 100644 index 00000000000..17ba4437d90 --- /dev/null +++ b/jdk/test/java/util/logging/bundlesearch/resources/StackSearchableResource_en.properties @@ -0,0 +1,25 @@ +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +sample1=translation #4 for sample1 +sample2=translation #4 for sample2 +supports-test=ResourceBundleSearchTest diff --git a/jdk/test/java/util/regex/RegExTest.java b/jdk/test/java/util/regex/RegExTest.java index 3f8679ae976..bc345eda853 100644 --- a/jdk/test/java/util/regex/RegExTest.java +++ b/jdk/test/java/util/regex/RegExTest.java @@ -33,7 +33,7 @@ * 5013885 5003322 4988891 5098443 5110268 6173522 4829857 5027748 6376940 * 6358731 6178785 6284152 6231989 6497148 6486934 6233084 6504326 6635133 * 6350801 6676425 6878475 6919132 6931676 6948903 6990617 7014645 7039066 - * 7067045 7014640 7189363 + * 7067045 7014640 7189363 8007395 */ import java.util.regex.*; @@ -144,6 +144,7 @@ public class RegExTest { horizontalAndVerticalWSTest(); linebreakTest(); branchTest(); + groupCurlyNotFoundSuppTest(); if (failure) { throw new RuntimeException("RegExTest failed, 1st failure: " + @@ -3947,4 +3948,27 @@ public class RegExTest { report("branchTest"); } + // This test is for 8007395 + private static void groupCurlyNotFoundSuppTest() throws Exception { + String input = "test this as \ud83d\ude0d"; + for (String pStr : new String[] { "test(.)+(@[a-zA-Z.]+)", + "test(.)*(@[a-zA-Z.]+)", + "test([^B])+(@[a-zA-Z.]+)", + "test([^B])*(@[a-zA-Z.]+)", + "test(\\P{IsControl})+(@[a-zA-Z.]+)", + "test(\\P{IsControl})*(@[a-zA-Z.]+)", + }) { + Matcher m = Pattern.compile(pStr, Pattern.CASE_INSENSITIVE) + .matcher(input); + try { + if (m.find()) { + failCount++; + } + } catch (Exception x) { + failCount++; + } + } + report("GroupCurly NotFoundSupp"); + } + } diff --git a/jdk/test/javax/swing/JInternalFrame/InternalFrameIsNotCollectedTest.java b/jdk/test/javax/swing/JInternalFrame/InternalFrameIsNotCollectedTest.java new file mode 100644 index 00000000000..182e57eef55 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/InternalFrameIsNotCollectedTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* @test + @bug 8012004 + @summary JINTERNALFRAME NOT BEING FINALIZED AFTER CLOSING + @author mcherkas + @run main InternalFrameIsNotCollectedTest + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.beans.PropertyVetoException; +import java.util.Date; + +public class InternalFrameIsNotCollectedTest { + + public static final int waitTime = 10000; + private static Robot robot; + + public static void sync() { + + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + toolkit.realSync(); + } + + public static void main(String[] args) throws Exception { + initRobot(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + initUI(); + try { + closeInternalFrame(); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + } + }); + sync(); + invokeGC(); + Thread.sleep(1000); // it's better to wait 1 sec now then 10 sec later + Date startWaiting = new Date(); + synchronized (CustomInternalFrame.waiter) { + // Sync with finalization thread. + Date now = new Date(); + while (now.getTime() - startWaiting.getTime() < waitTime && !CustomInternalFrame.finalized) { + CustomInternalFrame.waiter.wait(waitTime); + now = new Date(); + } + } + if (!CustomInternalFrame.finalized) { + throw new RuntimeException("Closed internal frame wasn't collected"); + } + } + + private static void initRobot() throws AWTException { + robot = new Robot(); + robot.setAutoDelay(100); + } + + private static void closeInternalFrame() throws PropertyVetoException { + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_F4); + robot.keyRelease(KeyEvent.VK_F4); + robot.keyRelease(KeyEvent.VK_CONTROL); + } + + private static void initUI() { + JFrame frame = new JFrame("Internal Frame Test"); + frame.getContentPane().setLayout(new BorderLayout()); + JDesktopPane desktopPane = new JDesktopPane(); + desktopPane.setDesktopManager(new DefaultDesktopManager()); + frame.getContentPane().add(desktopPane, BorderLayout.CENTER); + + CustomInternalFrame iFrame = new CustomInternalFrame("Dummy Frame"); + + iFrame.setSize(200, 200); + iFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + desktopPane.add(iFrame); + + frame.setSize(800, 600); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.setVisible(true); + iFrame.setVisible(true); + } + + private static void invokeGC() { + System.out.println("Firing garbage collection!"); + try { + StringBuilder sb = new StringBuilder(); + while (true) { + sb.append("any string. some test. a little bit more text." + sb.toString()); + } + } catch (Throwable e) { + // do nothing + } + } + + + public static class CustomInternalFrame extends JInternalFrame { + public static volatile boolean finalized = false; + public static Object waiter = new Object(); + + public CustomInternalFrame(String title) { + super(title, true, true, true, true); + } + + protected void finalize() { + System.out.println("Finalized!"); + finalized = true; + waiter.notifyAll(); + } + } +} \ No newline at end of file diff --git a/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java b/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java index 47761ec13d2..4cf1c750da5 100644 --- a/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java +++ b/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,43 +35,72 @@ import java.awt.event.*; import javax.swing.*; public class ActionListenerCalledTwiceTest { + static String menuItems[] = { "Item1", "Item2" }; + static KeyStroke keyStrokes[] = { + KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.META_MASK), + KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0) + }; + static volatile int listenerCallCounter = 0; public static void main(String[] args) throws Exception { if (sun.awt.OSInfo.getOSType() != sun.awt.OSInfo.OSType.MACOSX) { System.out.println("This test is for MacOS only. Automatically passed on other platforms."); return; } + System.setProperty("apple.laf.useScreenMenuBar", "true"); SwingUtilities.invokeAndWait(new Runnable() { public void run() { createAndShowGUI(); } }); + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); Robot robot = new Robot(); robot.setAutoDelay(100); - robot.keyPress(KeyEvent.VK_META); - robot.keyPress(KeyEvent.VK_E); - robot.keyRelease(KeyEvent.VK_E); - robot.keyRelease(KeyEvent.VK_META); - toolkit.realSync(); - if (listenerCallCounter != 1) { - throw new Exception("Test failed: ActionListener called " + listenerCallCounter + " times instead of 1!"); + + for (int i = 0; i < menuItems.length; ++i) { + KeyStroke ks = keyStrokes[i]; + int modKeyCode = getModKeyCode(ks.getModifiers()); + + if (modKeyCode != 0) { + robot.keyPress(modKeyCode); + } + + robot.keyPress(ks.getKeyCode()); + robot.keyRelease(ks.getKeyCode()); + + if (modKeyCode != 0) { + robot.keyRelease(modKeyCode); + } + + toolkit.realSync(); + + if (listenerCallCounter != 1) { + throw new Exception("Test failed: ActionListener for " + menuItems[i] + + " called " + listenerCallCounter + " times instead of 1!"); + } + + listenerCallCounter = 0; } } private static void createAndShowGUI() { - JMenuItem newItem = new JMenuItem("Exit"); - newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.META_MASK)); - newItem.addActionListener( - new ActionListener(){ - public void actionPerformed(ActionEvent e) { - listenerCallCounter++; - } - } - ); JMenu menu = new JMenu("Menu"); - menu.add(newItem); + + for (int i = 0; i < menuItems.length; ++i) { + JMenuItem newItem = new JMenuItem(menuItems[i]); + newItem.setAccelerator(keyStrokes[i]); + newItem.addActionListener( + new ActionListener(){ + public void actionPerformed(ActionEvent e) { + listenerCallCounter++; + } + } + ); + menu.add(newItem); + } + JMenuBar bar = new JMenuBar(); bar.add(menu); JFrame frame = new JFrame("Test"); @@ -80,4 +109,24 @@ public class ActionListenerCalledTwiceTest { frame.pack(); frame.setVisible(true); } + + private static int getModKeyCode(int mod) { + if ((mod & (InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK)) != 0) { + return KeyEvent.VK_SHIFT; + } + + if ((mod & (InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK)) != 0) { + return KeyEvent.VK_CONTROL; + } + + if ((mod & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_MASK)) != 0) { + return KeyEvent.VK_ALT; + } + + if ((mod & (InputEvent.META_DOWN_MASK | InputEvent.META_MASK)) != 0) { + return KeyEvent.VK_META; + } + + return 0; + } } diff --git a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java index 8dbb23503fc..135dfff0c40 100644 --- a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java +++ b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java @@ -46,10 +46,10 @@ import java.util.concurrent.FutureTask; * @bug 8010117 * @summary Verify if CallerSensitive methods are annotated with * sun.reflect.CallerSensitive annotation - * @build CallerSensitiveFinder MethodFinder + * @build CallerSensitiveFinder * @run main/othervm/timeout=900 -mx600m CallerSensitiveFinder */ -public class CallerSensitiveFinder extends MethodFinder { +public class CallerSensitiveFinder { private static int numThreads = 3; private static boolean verbose = false; public static void main(String[] args) throws Exception { @@ -71,8 +71,7 @@ public class CallerSensitiveFinder extends MethodFinder { if (classes.isEmpty()) { classes.addAll(PlatformClassPath.getJREClasses()); } - final String method = "sun/reflect/Reflection.getCallerClass"; - CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method); + CallerSensitiveFinder csfinder = new CallerSensitiveFinder(); List errors = csfinder.run(classes); if (!errors.isEmpty()) { @@ -82,8 +81,46 @@ public class CallerSensitiveFinder extends MethodFinder { } private final List csMethodsMissingAnnotation = new ArrayList<>(); - public CallerSensitiveFinder(String... methods) { - super(methods); + private final ReferenceFinder finder; + public CallerSensitiveFinder() { + this.finder = new ReferenceFinder(getFilter(), getVisitor()); + } + + private ReferenceFinder.Filter getFilter() { + final String classname = "sun/reflect/Reflection"; + final String method = "getCallerClass"; + return new ReferenceFinder.Filter() { + public boolean accept(ConstantPool cpool, CPRefInfo cpref) { + try { + CONSTANT_NameAndType_info nat = cpref.getNameAndTypeInfo(); + return cpref.getClassName().equals(classname) && nat.getName().equals(method); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + }; + } + + private ReferenceFinder.Visitor getVisitor() { + return new ReferenceFinder.Visitor() { + public void visit(ClassFile cf, Method m, List refs) { + try { + String name = String.format("%s#%s %s", cf.getName(), + m.getName(cf.constant_pool), + m.descriptor.getValue(cf.constant_pool)); + if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) { + csMethodsMissingAnnotation.add(name); + System.err.println("Missing @CallerSensitive: " + name); + } else { + if (verbose) { + System.out.format("@CS %s%n", name); + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + }; } public List run(List classes) throws IOException, InterruptedException, @@ -125,27 +162,12 @@ public class CallerSensitiveFinder extends MethodFinder { return false; } - public void referenceFound(ClassFile cf, Method m, Set refs) - throws ConstantPoolException - { - String name = String.format("%s#%s %s", cf.getName(), - m.getName(cf.constant_pool), - m.descriptor.getValue(cf.constant_pool)); - if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) { - csMethodsMissingAnnotation.add(name); - System.err.println("Missing @CallerSensitive: " + name); - } else { - if (verbose) { - System.out.format("@CS %s%n", name); - } - } - } - - private final List > tasks = new ArrayList >(); - private FutureTask getTask(final ClassFile cf) { - FutureTask task = new FutureTask (new Callable () { - public String call() throws Exception { - return parse(cf); + private final List > tasks = new ArrayList >(); + private FutureTask getTask(final ClassFile cf) { + FutureTask task = new FutureTask (new Callable () { + public Void call() throws Exception { + finder.parse(cf); + return null; } }); tasks.add(task); @@ -153,8 +175,8 @@ public class CallerSensitiveFinder extends MethodFinder { } private void waitForCompletion() throws InterruptedException, ExecutionException { - for (FutureTask t : tasks) { - String s = t.get(); + for (FutureTask t : tasks) { + t.get(); } System.out.println("Parsed " + tasks.size() + " classfiles"); } diff --git a/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java b/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java deleted file mode 100644 index 8ea78866dae..00000000000 --- a/jdk/test/sun/reflect/CallerSensitive/MethodFinder.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.util.*; -import com.sun.tools.classfile.*; -import static com.sun.tools.classfile.ConstantPool.*; -import com.sun.tools.classfile.Instruction.TypeKind; - -/** - * MethodFinder utility class to find references to the given methods. - */ -public abstract class MethodFinder { - final List methods; - public MethodFinder(String... methods) { - this.methods = Arrays.asList(methods); - } - - /** - * A callback method will be invoked when a method referencing - * any of the lookup methods. - * - * @param cf ClassFile - * @param m Method - * @param refs Set of constant pool indices that reference the methods - * matching the given lookup method names - */ - public abstract void referenceFound(ClassFile cf, Method m, Set refs) - throws ConstantPoolException; - - public String parse(ClassFile cf) throws ConstantPoolException { - List cprefs = new ArrayList (); - int index = 1; - for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) { - if (cpInfo.accept(cpVisitor, null)) { - cprefs.add(index); - } - index += cpInfo.size(); - } - - if (!cprefs.isEmpty()) { - for (Method m : cf.methods) { - Set refs = new HashSet (); - Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); - if (c_attr != null) { - for (Instruction instr : c_attr.getInstructions()) { - int idx = instr.accept(codeVisitor, cprefs); - if (idx > 0) { - refs.add(idx); - } - } - } - if (refs.size() > 0) { - referenceFound(cf, m, refs); - } - } - } - return cprefs.isEmpty() ? "" : cf.getName(); - } - - private ConstantPool.Visitor cpVisitor = - new ConstantPool.Visitor () - { - private boolean matches(CPRefInfo info) { - try { - CONSTANT_NameAndType_info nat = info.getNameAndTypeInfo(); - return matches(info.getClassName(), nat.getName(), nat.getType()); - } catch (ConstantPoolException ex) { - return false; - } - } - - private boolean matches(String cn, String name, String type) { - return methods.contains(cn + "." + name); - } - - public Boolean visitClass(CONSTANT_Class_info info, Void p) { - return false; - } - - public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { - return matches(info); - } - - public Boolean visitMethodref(CONSTANT_Methodref_info info, Void p) { - return matches(info); - } - - public Boolean visitDouble(CONSTANT_Double_info info, Void p) { - return false; - } - - public Boolean visitFieldref(CONSTANT_Fieldref_info info, Void p) { - return false; - } - - public Boolean visitFloat(CONSTANT_Float_info info, Void p) { - return false; - } - - public Boolean visitInteger(CONSTANT_Integer_info info, Void p) { - return false; - } - - public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) { - return false; - } - - public Boolean visitLong(CONSTANT_Long_info info, Void p) { - return false; - } - - public Boolean visitNameAndType(CONSTANT_NameAndType_info info, Void p) { - return false; - } - - public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) { - return false; - } - - public Boolean visitMethodType(CONSTANT_MethodType_info info, Void p) { - return false; - } - - public Boolean visitString(CONSTANT_String_info info, Void p) { - return false; - } - - public Boolean visitUtf8(CONSTANT_Utf8_info info, Void p) { - return false; - } - }; - - private Instruction.KindVisitor > codeVisitor = - new Instruction.KindVisitor >() - { - public Integer visitNoOperands(Instruction instr, List p) { - return 0; - } - - public Integer visitArrayType(Instruction instr, TypeKind kind, List p) { - return 0; - } - - public Integer visitBranch(Instruction instr, int offset, List p) { - return 0; - } - - public Integer visitConstantPoolRef(Instruction instr, int index, List p) { - return p.contains(index) ? index : 0; - } - - public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List p) { - return p.contains(index) ? index : 0; - } - - public Integer visitLocal(Instruction instr, int index, List p) { - return 0; - } - - public Integer visitLocalAndValue(Instruction instr, int index, int value, List p) { - return 0; - } - - public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List p) { - return 0; - } - - public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List p) { - return 0; - } - - public Integer visitValue(Instruction instr, int value, List p) { - return 0; - } - - public Integer visitUnknown(Instruction instr, List p) { - return 0; - } - }; -} - diff --git a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java index c60a8d0eca5..4fe6ba68a21 100644 --- a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java +++ b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java @@ -27,7 +27,7 @@ * @bug 8010117 * @summary Test CallerSensitiveFinder to find missing annotation * @compile -XDignore.symbol.file MissingCallerSensitive.java - * @build CallerSensitiveFinder MethodFinder + * @build CallerSensitiveFinder * @run main MissingCallerSensitive */ @@ -40,8 +40,7 @@ public class MissingCallerSensitive { List classes = new ArrayList<>(); classes.add(Paths.get(testclasses, "MissingCallerSensitive.class")); - final String method = "sun/reflect/Reflection.getCallerClass"; - CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method); + CallerSensitiveFinder csfinder = new CallerSensitiveFinder(); List errors = csfinder.run(classes); if (errors.size() != 1) { throw new RuntimeException("Unexpected number of methods found: " + errors.size()); diff --git a/jdk/test/sun/security/krb5/auto/SSL.java b/jdk/test/sun/security/krb5/auto/SSL.java index 353916e7578..8d64460430d 100644 --- a/jdk/test/sun/security/krb5/auto/SSL.java +++ b/jdk/test/sun/security/krb5/auto/SSL.java @@ -23,10 +23,11 @@ /* * @test - * @bug 6894643 6913636 + * @bug 6894643 6913636 8005523 * @summary Test JSSE Kerberos ciphersuite + * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_SHA - * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_MD5 + * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_SHA unbound * @run main/othervm SSL TLS_KRB5_WITH_3DES_EDE_CBC_SHA * @run main/othervm SSL TLS_KRB5_WITH_3DES_EDE_CBC_MD5 * @run main/othervm SSL TLS_KRB5_WITH_DES_CBC_SHA @@ -38,14 +39,17 @@ */ import java.io.*; import java.net.InetAddress; +import java.security.AccessControlException; +import java.security.Permission; import javax.net.ssl.*; import java.security.Principal; import java.util.Date; +import javax.security.auth.kerberos.ServicePermission; import sun.security.jgss.GSSUtil; import sun.security.krb5.PrincipalName; import sun.security.krb5.internal.ktab.KeyTab; -public class SSL { +public class SSL extends SecurityManager { private static String krb5Cipher; private static final int LOOP_LIMIT = 3; @@ -53,13 +57,32 @@ public class SSL { private static volatile String server; private static volatile int port; + private static String permChecks = ""; + // 0-Not started, 1-Start OK, 2-Failure private static volatile int serverState = 0; + @Override + public void checkPermission(Permission perm, Object context) { + checkPermission(perm); + } + + public void checkPermission(Permission perm) { + if (!(perm instanceof ServicePermission)) { + return; + } + ServicePermission p = (ServicePermission)perm; + permChecks = permChecks + p.getActions().toUpperCase().charAt(0); + } + public static void main(String[] args) throws Exception { krb5Cipher = args[0]; + boolean unbound = args.length > 1; + + System.setSecurityManager(new SSL()); + KDC kdc = KDC.create(OneKDC.REALM); // Run this after KDC, so our own DNS service can be started try { @@ -85,6 +108,7 @@ public class SSL { // and use the middle one as the real key kdc.addPrincipal("host/" + server, "pass2".toCharArray()); + // JAAS config entry name ssl System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF); File f = new File(OneKDC.JAAS_CONF); @@ -92,7 +116,9 @@ public class SSL { fos.write(( "ssl {\n" + " com.sun.security.auth.module.Krb5LoginModule required\n" + - " principal=\"host/" + server + "\"\n" + + (unbound ? + " principal=*\n" : + " principal=\"host/" + server + "\"\n") + " useKeyTab=true\n" + " keyTab=" + OneKDC.KTAB + "\n" + " isInitiator=false\n" + @@ -103,7 +129,6 @@ public class SSL { Context c; final Context s = Context.fromJAAS("ssl"); - // There's no keytab file when server starts. s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); Thread server = new Thread(new Runnable() { @@ -127,21 +152,6 @@ public class SSL { throw new Exception("Server already failed"); } - // Now create the keytab - - /* - // Add 3 versions of keys into keytab - KeyTab ktab = KeyTab.create(OneKDC.KTAB); - PrincipalName service = new PrincipalName( - "host/" + server, PrincipalName.KRB_NT_SRV_HST); - ktab.addEntry(service, "pass1".toCharArray(), 1); - ktab.addEntry(service, "pass2".toCharArray(), 2); - ktab.addEntry(service, "pass3".toCharArray(), 3); - ktab.save(); - - // and use the middle one as the real key - kdc.addPrincipal("host/" + server, "pass2".toCharArray()); - */ c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); @@ -157,20 +167,22 @@ public class SSL { c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); - // Revoke the old key - /*Thread.sleep(2000); - ktab = KeyTab.create(OneKDC.KTAB); - ktab.addEntry(service, "pass5".toCharArray(), 5, false); - ktab.save(); - - c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); - c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); - try { - c.doAs(new JsseClientAction(), null); - throw new Exception("Should fail this time."); - } catch (SSLException e) { - // Correct behavior. - }*/ + // Permission checking check. Please note this is highly + // implementation related. + if (unbound) { + // For unbound, server does not know what name to check. + // Client checks "initiate", then server gets the name + // and checks "accept". Second connection resume. + if (!permChecks.equals("IA")) { + throw new Exception(); + } + } else { + // For bound, JAAS checks "accept" once. Server checks again, + // client then checks "initiate". Second connection resume. + if (!permChecks.equals("AAI")) { + throw new Exception(); + } + } } // Following codes copied from diff --git a/jdk/test/sun/security/krb5/auto/SaslGSS.java b/jdk/test/sun/security/krb5/auto/SaslGSS.java new file mode 100644 index 00000000000..e497ab1a296 --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/SaslGSS.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8012082 + * @summary SASL: auth-conf negotiated, but unencrypted data is accepted, + * reset to unencrypt + * @compile -XDignore.symbol.file SaslGSS.java + * @run main/othervm SaslGSS + */ + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.RealmCallback; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServer; +import java.io.IOException; +import java.util.HashMap; +import java.util.Locale; +import org.ietf.jgss.*; +import sun.security.jgss.GSSUtil; + +public class SaslGSS { + + public static void main(String[] args) throws Exception { + + String name = "host." + OneKDC.REALM.toLowerCase(Locale.US); + + new OneKDC(null).writeJAASConf(); + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + // Client in JGSS so that it can control wrap privacy mode + GSSManager m = GSSManager.getInstance(); + GSSContext sc = m.createContext( + m.createName(OneKDC.SERVER, GSSUtil.NT_GSS_KRB5_PRINCIPAL), + GSSUtil.GSS_KRB5_MECH_OID, + null, + GSSContext.DEFAULT_LIFETIME); + sc.requestMutualAuth(false); + + // Server in SASL + final HashMap props = new HashMap(); + props.put(Sasl.QOP, "auth-conf"); + SaslServer ss = Sasl.createSaslServer("GSSAPI", "server", + name, props, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb : callbacks) { + if (cb instanceof RealmCallback) { + ((RealmCallback) cb).setText(OneKDC.REALM); + } else if (cb instanceof AuthorizeCallback) { + ((AuthorizeCallback) cb).setAuthorized(true); + } + } + } + }); + + // Handshake + byte[] token = new byte[0]; + token = sc.initSecContext(token, 0, token.length); + token = ss.evaluateResponse(token); + token = sc.unwrap(token, 0, token.length, new MessageProp(0, false)); + token[0] = (byte)(((token[0] & 4) != 0) ? 4 : 2); + token = sc.wrap(token, 0, token.length, new MessageProp(0, false)); + ss.evaluateResponse(token); + + // Talk + // 1. Client sends a auth-int message + byte[] hello = "hello".getBytes(); + MessageProp qop = new MessageProp(0, false); + token = sc.wrap(hello, 0, hello.length, qop); + // 2. Server accepts it anyway + ss.unwrap(token, 0, token.length); + // 3. Server sends a message + token = ss.wrap(hello, 0, hello.length); + // 4. Client accepts, should be auth-conf + sc.unwrap(token, 0, token.length, qop); + if (!qop.getPrivacy()) { + throw new Exception(); + } + } +} diff --git a/jdk/test/sun/security/provider/SecureRandom/StrongSeedReader.java b/jdk/test/sun/security/provider/SecureRandom/StrongSeedReader.java index 34f10f1d6a3..7057f9b2bb4 100644 --- a/jdk/test/sun/security/provider/SecureRandom/StrongSeedReader.java +++ b/jdk/test/sun/security/provider/SecureRandom/StrongSeedReader.java @@ -49,7 +49,7 @@ public class StrongSeedReader { File file = null; try { - file = new File(System.getProperty("java.io.tmpdir") + + file = new File(System.getProperty("java.io.tmpdir"), "StrongSeedReader.tmpdata"); // write a bunch of 0's to the file. diff --git a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java index 208f51943de..237d61f033e 100644 --- a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java +++ b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java @@ -260,6 +260,8 @@ public class TimestampCheck { jarsigner(cmd, 7, false); // tsbad2 jarsigner(cmd, 8, false); // tsbad3 jarsigner(cmd, 9, false); // no cert in timestamp + jarsigner(cmd + " -tsapolicyid 1.2.3.4", 0, true); + jarsigner(cmd + " -tsapolicyid 1.2.3.5", 0, false); } else { // Run as a standalone server System.err.println("Press Enter to quit server"); System.in.read(); diff --git a/jdk/test/sun/security/tools/jarsigner/ts.sh b/jdk/test/sun/security/tools/jarsigner/ts.sh index 43a3651f62a..e318ca677e0 100644 --- a/jdk/test/sun/security/tools/jarsigner/ts.sh +++ b/jdk/test/sun/security/tools/jarsigner/ts.sh @@ -22,7 +22,7 @@ # # @test -# @bug 6543842 6543440 6939248 +# @bug 6543842 6543440 6939248 8009636 # @summary checking response of timestamp # # @run shell/timeout=600 ts.sh diff --git a/jdk/test/sun/security/tools/keytool/console.sh b/jdk/test/sun/security/tools/keytool/console.sh index ec0f05961f8..ec338ca373d 100644 --- a/jdk/test/sun/security/tools/keytool/console.sh +++ b/jdk/test/sun/security/tools/keytool/console.sh @@ -1,5 +1,3 @@ -#! /bin/sh - # # Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -24,10 +22,11 @@ # # @test -# @bug 6418647 +# @bug 6418647 8005527 # @summary Doc bug 5035358 shows sun.security.util.Password.readPassword() is buggy. # @author Weijun Wang -# +# @ignore unable to test manual tools that have input from stdin, +# and output to stderr and stdout # @run shell/manual console.sh if [ "$ALT_PASS" = "" ]; then diff --git a/langtools/.hgtags b/langtools/.hgtags index 03ad6e96b7b..8231fc5e460 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -209,3 +209,4 @@ cfb65ca92082b2412aed66c8422c2466bde544ef jdk8-b84 4a48f31735349782ad13980267358c97076adc66 jdk8-b85 6ab578e141dfd17c4dc03869bb204aafa490c9f4 jdk8-b86 1329f9c38d93c8caf339d7687df8371d06fe9e56 jdk8-b87 +a1e10f3adc47c8602a72e43a41403a642e73e0b1 jdk8-b88 diff --git a/langtools/make/Makefile-classic b/langtools/make/Makefile-classic deleted file mode 100644 index c253ee8949b..00000000000 --- a/langtools/make/Makefile-classic +++ /dev/null @@ -1,396 +0,0 @@ -# -# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# Makefile for building the langtools workspace. -# - -# -# On Solaris, the standard 'make' utility will not work with these makefiles. -# This little rule is only understood by Solaris make, and is harmless -# when seen by the GNU make tool. If using Solaris make, this causes the -# make command to fail. -# -SUN_MAKE_TEST:sh = @echo "ERROR: PLEASE USE GNU VERSION OF MAKE"; exit 33 - -#----- cancel implicit rules - -%: %.o -%: %.obj -%: %.dll -%: %.c -%: %.cc -%: %.C -%: %.p -%: %.f -%: %.s -%: %.F -%: %.r -%: %.S -%: %.mod -%: %.sh -%: %,v -%: RCS/%,v - -#----- imports - -ifdef ALT_BOOT_JAVA_HOME - BOOT_JAVA_HOME = $(ALT_BOOT_JAVA_HOME) -else - ifdef ALT_BOOTDIR - BOOT_JAVA_HOME = $(ALT_BOOTDIR) - else - BOOT_JAVA_HOME=/java/re/jdk/1.5.0/archive/fcs/binaries/solaris-sparc - endif -endif - -BOOT_JAVA=$(BOOT_JAVA_HOME)/bin/java -BOOT_JAVAC=$(BOOT_JAVA_HOME)/bin/javac -BOOTJAR=$(BOOT_JAVA_HOME)/bin/jar - -ifdef ALT_TESTJAVA_HOME - TESTJAVA_HOME = $(ALT_TESTJAVA_HOME) -else - TESTJAVA_HOME=/java/re/jdk/1.6.0/archive/fcs/binaries/solaris-sparc -endif - -TESTJAVA=$(TESTJAVA_HOME)/bin/java - -ifdef ALT_FINDBUGS_HOME - FINDBUGS_HOME = $(ALT_FINDBUGS_HOME) -else - FINDBUGS_HOME = /java/devtools/share/findbugs/1.1.2-rc4 -endif - -FINDBUGS = $(FINDBUGS_HOME)/bin/findbugs - -#----- commands - -CHMOD = chmod -CP = cp -ECHO = echo # FIXME -FIND = find -MKDIR = mkdir -SED = sed -ZIP = zip - -#----- locations and deliverables - -TOPDIR = .. -SRC_BIN_DIR = $(TOPDIR)/src/share/bin -SRC_CLASSES_DIR = $(TOPDIR)/src/share/classes - -BUILD_DIR = $(TOPDIR)/build - -CLASSES_DIR = $(BUILD_DIR)/classes -GENSRC_DIR = $(BUILD_DIR)/gensrc - -DIST_DIR = $(TOPDIR)/dist -BIN_DIR = $(DIST_DIR)/bin -LIB_DIR = $(DIST_DIR)/lib - -JAVAC_JAR = $(LIB_DIR)/javac.jar -JAVADOC_JAR = $(LIB_DIR)/javadoc.jar -JAVAH_JAR = $(LIB_DIR)/javah.jar -JAVAP_JAR = $(LIB_DIR)/javap.jar - -CLASSES_JAR = $(DIST_DIR)/classes.jar -SRC_ZIP = $(DIST_DIR)/src.zip - -BUILDTOOLSRC_DIR = tools -BUILDTOOLCLASSES_DIR = $(BUILD_DIR)/toolclasses - -#----- - -ifndef JDK_MAJOR_VERSION - JDK_MAJOR_VERSION = 1 -endif - -ifndef JDK_MINOR_VERSION - JDK_MINOR_VERSION = 7 -endif - -ifndef JDK_MICRO_VERSION - JDK_MICRO_VERSION = 0 -endif - -ifndef JDK_VERSION - JDK_VERSION = $(JDK_MAJOR_VERSION).$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION) -endif - -ifndef MILESTONE - MILESTONE = internal -endif - -# RELEASE is JDK_VERSION and -MILESTONE if MILESTONE is set -ifneq ($(MILESTONE),fcs) - RELEASE = $(JDK_VERSION)-$(MILESTONE)$(BUILD_VARIANT_RELEASE) -else - RELEASE = $(JDK_VERSION)$(BUILD_VARIANT_RELEASE) -endif - -# FULL_VERSION is RELEASE and -BUILD_NUMBER if BUILD_NUMBER is set -ifdef BUILD_NUMBER - FULL_VERSION = $(RELEASE)-$(BUILD_NUMBER) -else - BUILD_NUMBER = b00 - USER_RELEASE_SUFFIX := $(shell echo $(USER)_`date '+%d_%b_%Y_%H_%M' | tr "A-Z" "a-z"`) - FULL_VERSION = $(RELEASE)-$(USER_RELEASE_SUFFIX)-$(BUILD_NUMBER) -endif - -#----- useful macros - -TOOLS = javac javadoc javah javap - -SOURCE_LEVEL = 5 -BOOTSTRAP_TARGET_LEVEL = 5 -TARGET_LEVEL = 6 - -ifndef TARGET_JAVA - TARGET_JAVA = java -endif - -NO_PROPRIETARY_API_WARNINGS = -XDignore.symbol.file=true - -SELF = $(lastword $(MAKEFILE_LIST)) - -#----- - -# the default is to generate the following: -# dist/{bin,lib}: -# lang tools compiled to run on the target JDK - -default: - $(MAKE) -f $(SELF) \ - MILESTONE=bootstrap \ - TARGET_LEVEL=$(BOOTSTRAP_TARGET_LEVEL) \ - TARGET_JAVA=$(BOOT_JAVA_HOME)/bin/java \ - GENSRC_DIR=$(BUILD_DIR)/bootstrap/gensrc \ - CLASSES_DIR=$(BUILD_DIR)/bootstrap/classes \ - BIN_DIR=$(BUILD_DIR)/bootstrap/bin \ - LIB_DIR=$(BUILD_DIR)/bootstrap/lib \ - $(BUILD_DIR)/bootstrap/lib/javac.jar \ - $(BUILD_DIR)/bootstrap/bin/javac - $(MAKE) -f $(SELF) \ - BOOT_JAVAC=$(BUILD_DIR)/bootstrap/bin/javac \ - tools - -# for jdk, we generate the following: -# dist/bootstrap/{bin,lib}: -# lang tools compiled to run on the boot JDK -# dist/lib/classes.jar: -# lang tools recompiled to run on the target JDK, -# ready for inclusion in rt.jar and tools.jar -# dist/lib/src.zip -# .properties and .java files for classes in classes.jar, -# ready for jdk src.zip - -jdk: - $(MAKE) -f $(SELF) \ - MILESTONE=bootstrap \ - TARGET_LEVEL=$(BOOTSTRAP_TARGET_LEVEL) \ - TARGET_JAVA=$(BOOT_JAVA_HOME)/bin/java \ - GENSRC_DIR=$(BUILD_DIR)/bootstrap/gensrc \ - CLASSES_DIR=$(BUILD_DIR)/bootstrap/classes \ - BIN_DIR=$(DIST_DIR)/bootstrap/bin \ - LIB_DIR=$(DIST_DIR)/bootstrap/lib \ - tools - $(MAKE) -f $(SELF) \ - BOOT_JAVAC=$(DIST_DIR)/bootstrap/bin/javac \ - LIB_DIR=$(BUILD_DIR)/jdk/lib \ - $(DIST_DIR)/lib/classes.jar \ - $(DIST_DIR)/lib/src.zip - -tools: $(TOOLS:%=$(LIB_DIR)/%.jar) $(TOOLS:%=$(BIN_DIR)/%) - -clean: - $(RM) -r $(BUILD_DIR) - -really-clean: clean - $(RM) -r $(DIST_DIR) - -jprt_product_build \ -jprt_debug_build \ -jprt_fastdebug_build: lib - -#----- javac - -JAVAC_DIRS = \ - javax/annotation/processing \ - javax/lang/model \ - javax/tools \ - jdk/ \ - com/sun/source \ - com/sun/tools/javac - -JAVAC_RESOURCE_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAC_DIRS)) -name SCCS -prune -o -name \*.properties -print ) - -JAVAC_JAVA_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAC_DIRS)) -name SCCS -prune -o -name \*.java -print ) \ - $(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAC_RESOURCE_FILES)) \ - $(GENSRC_DIR)/com/sun/tools/javac/resources/version.java - -$(JAVAC_JAR): $(JAVAC_JAVA_FILES) - $(MKDIR) -p $(CLASSES_DIR) $(@D) - $(BOOT_JAVAC) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(NO_PROPRIETARY_API_WARNINGS) $(JAVAC_JAVA_FILES) - ( $(ECHO) Main-Class: com.sun.tools.javac.Main ) > $(BUILD_DIR)/javac.mf - $(BOOTJAR) -cfm $@ $(BUILD_DIR)/javac.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVAC_DIRS)) - -#----- javadoc - -### FIXME -- javadoc has a couple of extra non-property resource files -### that need to be included - -JAVADOC_DIRS = \ - com/sun/javadoc \ - com/sun/tools/doclets \ - com/sun/tools/javadoc - -JAVADOC_RESOURCE_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVADOC_DIRS)) -name SCCS -prune -o -name \*.properties -print ) - -JAVADOC_JAVA_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVADOC_DIRS)) -name SCCS -prune -o -name \*.java -print ) \ - $(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVADOC_RESOURCE_FILES)) - -$(JAVADOC_JAR): $(JAVADOC_JAVA_FILES) $(JAVAC_JAR) - $(MKDIR) -p $(CLASSES_DIR) $(@D) - $(BOOT_JAVAC) -sourcepath "" -classpath $(JAVAC_JAR) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(JAVADOC_JAVA_FILES) - ( $(ECHO) Main-Class: com.sun.tools.javadoc.Main ; $(ECHO) Class-Path: javac.jar ) > $(BUILD_DIR)/javadoc.mf - $(BOOTJAR) -cfm $@ $(BUILD_DIR)/javadoc.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVADOC_DIRS)) - -#----- javah - -JAVAH_DIRS = \ - com/sun/tools/javah - -JAVAH_RESOURCE_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAH_DIRS)) -name SCCS -prune -o -name \*.properties -print ) - -JAVAH_JAVA_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAH_DIRS)) -name SCCS -prune -o -name \*.java -print ) \ - $(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAH_RESOURCE_FILES)) - -$(JAVAH_JAR): $(JAVAH_JAVA_FILES) $(JAVADOC_JAR) - $(MKDIR) -p $(CLASSES_DIR) $(@D) - $(BOOT_JAVAC) -sourcepath "" -classpath $(CLASSES_DIR) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(JAVAH_JAVA_FILES) - ( $(ECHO) Main-Class: com.sun.tools.javah.Main ; $(ECHO) Class-Path: javadoc.jar ) > $(BUILD_DIR)/javah.mf - $(BOOTJAR) -cfm $@ $(BUILD_DIR)/javah.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVAH_DIRS)) - -#----- javap - -JAVAP_DIRS = \ - sun/tools/javap - -JAVAP_RESOURCE_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAP_DIRS)) -name SCCS -prune -o -name \*.properties -print ) - -JAVAP_JAVA_FILES = \ - $(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAP_DIRS)) -name SCCS -prune -o -name \*.java -print ) \ - $(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAP_RESOURCE_FILES)) - -$(JAVAP_JAR): $(JAVAP_JAVA_FILES) \ - $(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAP_RESOURCE_FILES)) - $(MKDIR) -p $(CLASSES_DIR) - $(BOOT_JAVAC) -sourcepath "" -classpath $(CLASSES_DIR) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(JAVAP_JAVA_FILES) - ( $(ECHO) Main-Class: sun.tools.javap.Main ) > $(BUILD_DIR)/javap.mf - $(BOOTJAR) -cfm $@ $(BUILD_DIR)/javap.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVAP_DIRS)) - -#----- - -build-tools: $(BUILDTOOLCLASSES_DIR)/CompileProperties/CompileProperties.class - -$(GENSRC_DIR)/%.java: $(SRC_CLASSES_DIR)/%.properties $(BUILDTOOLCLASSES_DIR)/CompileProperties/CompileProperties.class - $(MKDIR) -p $(@D) - $(BOOT_JAVA) -cp $(BUILDTOOLCLASSES_DIR)/CompileProperties CompileProperties $< $(patsubst $(CLASSES_DIR)/%.class,$(GENSRC_DIR)/%.java,$@) - -$(GENSRC_DIR)/%.java: $(GENSRC_DIR)/%.properties $(BUILDTOOLCLASSES_DIR)/CompileProperties/CompileProperties.class - $(MKDIR) -p $(@D) - $(BOOT_JAVA) -cp $(BUILDTOOLCLASSES_DIR)/CompileProperties CompileProperties $< $(patsubst $(CLASSES_DIR)/%.class,$(GENSRC_DIR)/%.java,$@) - -$(GENSRC_DIR)/%.properties: $(SRC_CLASSES_DIR)/%.properties-template - $(MKDIR) -p $(@D) - $(SED) -e 's/$$(JDK_VERSION)/$(JDK_VERSION)/' \ - -e 's/$$(FULL_VERSION)/$(FULL_VERSION)/' \ - -e 's/$$(RELEASE)/$(RELEASE)/' \ - < $< > $@ - -$(BUILDTOOLCLASSES_DIR)/%.class : $(BUILDTOOLSRC_DIR)/%.java - $(MKDIR) -p $(@D) - $(BOOT_JAVAC) -d $(@D) $< - -#----- all classes - -$(DIST_DIR)/%/classes.jar: $(JAVAC_JAR) $(JAVADOC_JAR) $(JAVAH_JAR) $(JAVAP_JAR) - $(MKDIR) -p $(@D) - $(BOOTJAR) -cf $@ -C $(CLASSES_DIR) . - -#----- src.zip - -SRC_ZIP_FILES = $(shell $(FIND) $(SRC_CLASSES_DIR) \( -name SCCS -o -name \*-template \) -prune -o -type f -print ) - -$(DIST_DIR)/%/src.zip: $(SRC_ZIP_FILES) - abs_src_zip=`cd $(@D) ; pwd`/$(@F) ; \ - ( cd $(SRC_CLASSES_DIR) ; $(FIND) . \( -name SCCS -o -name \*-template \) -prune -o -type f -print | $(ZIP) -q $$abs_src_zip -@ ) ; \ - ( cd $(SRC_CLASSES_DIR) ; $(FIND) . -name SCCS -prune -o -name \*-template -print | $(SED) -e 's/-template//' ) | ( cd $(GENSRC_DIR) ; $(ZIP) -q $$abs_src_zip -@ ) - -#----- bin files - -$(BIN_DIR)/%: $(SRC_BIN_DIR)/launcher.sh-template - $(MKDIR) -p $(@D) - $(SED) -e 's|#PROGRAM#|$(@F)|' -e 's|#TARGET_JAVA#|$(TARGET_JAVA)|' $< > $@ - $(CHMOD) +x $@ - -#----- - -findbugs: $(BUILD_DIR)/findbugs.txt - -$(BUILD_DIR)/findbugs.txt: $(CLASSES_JAR) - $(MKDIR) -p $(@D) - $(FINDBUGS) -textui -javahome $(BOOT_JAVA_HOME) -high -emacs -outputFile $@ $< - -#----- - -quick-check: $(patsubst %, $(DIST_LIB_DIR)/%.jar, $(TOOLS)) - $(TESTJAVA) -jar $(JAVAC_JAR) -version - - $(TESTJAVA) -jar $(JAVADOC_JAR) -version - $(TESTJAVA) -jar $(JAVAH_JAR) -version - - $(TESTJAVA) -jar $(JAVAP_JAR) -version - -#----- - -.PHONY: \ - all \ - build \ - build-tools \ - clean \ - default \ - findbugs \ - jprt_product_build \ - jprt_debug_build \ - jprt_fastdebug_build \ - tools - diff --git a/langtools/make/build.xml b/langtools/make/build.xml index 2d3da00b0f4..d242e722141 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -716,6 +716,29 @@ + + + + + ++ + + + + @@ -811,6 +834,31 @@ ++ + ++ ++ + + + + + + + + ++ + ++ + ++ + + @@ -826,6 +874,7 @@ + @@ -868,6 +917,7 @@ + @@ -935,6 +985,32 @@ classpath="${build.toolclasses.dir}/"/> + ++ ++ ++ + ++ + + ++ ++ - - @@ -178,7 +178,7 @@ - @@ -239,10 +239,6 @@ build @@ -144,7 +144,7 @@${root}/make - - ${root}/src/share/classes -README @@ -250,7 +246,7 @@- @@ -305,11 +301,11 @@ - + diff --git a/langtools/make/tools/crules/AbstractCodingRulesAnalyzer.java b/langtools/make/tools/crules/AbstractCodingRulesAnalyzer.java new file mode 100644 index 00000000000..a4f3a3a2dc5 --- /dev/null +++ b/langtools/make/tools/crules/AbstractCodingRulesAnalyzer.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package crules; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.lang.model.element.TypeElement; +import javax.tools.JavaFileObject; + +import com.sun.source.tree.Tree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.Plugin; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.BasicJavacTask; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Log; + +import static com.sun.source.util.TaskEvent.Kind; + +public abstract class AbstractCodingRulesAnalyzer implements Plugin { + + protected Log log; + protected Trees trees; + protected TreeScanner treeVisitor; + protected Kind eventKind; + protected Messages messages; + + public void init(JavacTask task, String... args) { + BasicJavacTask impl = (BasicJavacTask)task; + Context context = impl.getContext(); + log = Log.instance(context); + trees = Trees.instance(task); + messages = new Messages(); + task.addTaskListener(new PostAnalyzeTaskListener()); + } + + public class PostAnalyzeTaskListener implements TaskListener { + + @Override + public void started(TaskEvent taskEvent) {} + + @Override + public void finished(TaskEvent taskEvent) { + if (taskEvent.getKind().equals(eventKind)) { + TypeElement typeElem = taskEvent.getTypeElement(); + Tree tree = trees.getTree(typeElem); + if (tree != null) { + JavaFileObject prevSource = log.currentSourceFile(); + try { + log.useSource(taskEvent.getCompilationUnit().getSourceFile()); + treeVisitor.scan((JCTree)tree); + } finally { + log.useSource(prevSource); + } + } + } + } + } + + class Messages { + ResourceBundle bundle; + + Messages() { + String name = getClass().getPackage().getName() + ".resources.crules"; + bundle = ResourceBundle.getBundle(name, Locale.ENGLISH); + } + + public void error(JCTree tree, String code, Object... args) { + String msg = (code == null) ? (String) args[0] : localize(code, args); + log.error(tree, "proc.messager", msg.toString()); + } + + private String localize(String code, Object... args) { + String msg = bundle.getString(code); + if (msg == null) { + StringBuilder sb = new StringBuilder(); + sb.append("message file broken: code=").append(code); + if (args.length > 0) { + sb.append(" arguments={0}"); + for (int i = 1; i < args.length; i++) { + sb.append(", {").append(i).append("}"); + } + } + msg = sb.toString(); + } + return MessageFormat.format(msg, args); + } + } + +} diff --git a/langtools/make/tools/crules/MutableFieldsAnalyzer.java b/langtools/make/tools/crules/MutableFieldsAnalyzer.java new file mode 100644 index 00000000000..0a7e6d190a0 --- /dev/null +++ b/langtools/make/tools/crules/MutableFieldsAnalyzer.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package crules; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.tree.TreeScanner; + +import static com.sun.source.util.TaskEvent.Kind; +import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.tree.JCTree.JCVariableDecl; + +public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer { + + public MutableFieldsAnalyzer() { + treeVisitor = new MutableFieldsVisitor(); + eventKind = Kind.ANALYZE; + } + + public String getName() { + return "mutable_fields_analyzer"; + } + + private boolean ignoreField(String className, String field) { + List ${root}/src/share/classes ${root}/build/classes -1.5 +1.7 currentFieldsToIgnore = + classFieldsToIgnoreMap.get(className); + if (currentFieldsToIgnore != null) { + for (String fieldToIgnore : currentFieldsToIgnore) { + if (field.equals(fieldToIgnore)) { + return true; + } + } + } + return false; + } + + class MutableFieldsVisitor extends TreeScanner { + + @Override + public void visitVarDef(JCVariableDecl tree) { + boolean isJavacPack = tree.sym.outermostClass().fullname.toString() + .contains(packageToCheck); + if (isJavacPack && + (tree.sym.flags() & SYNTHETIC) == 0 && + tree.sym.owner.kind == Kinds.TYP) { + if (!ignoreField(tree.sym.owner.flatName().toString(), + tree.getName().toString())) { + boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0; + boolean nonFinalStaticEnumField = + (tree.sym.flags() & (ENUM | FINAL)) == 0; + boolean nonFinalStaticField = + (tree.sym.flags() & STATIC) != 0 && + (tree.sym.flags() & FINAL) == 0; + if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) { + messages.error(tree, "crules.err.var.must.be.final", tree); + } + } + } + super.visitVarDef(tree); + } + + } + + private static final String packageToCheck = "com.sun.tools.javac"; + + private static final Map > classFieldsToIgnoreMap = + new HashMap >(); + + static { + classFieldsToIgnoreMap. + put("com.sun.tools.javac.util.JCDiagnostic", + Arrays.asList("fragmentFormatter")); + classFieldsToIgnoreMap. + put("com.sun.tools.javac.util.JavacMessages", + Arrays.asList("defaultBundle", "defaultMessages")); + classFieldsToIgnoreMap. + put("com.sun.tools.javac.file.ZipFileIndexCache", + Arrays.asList("sharedInstance")); + classFieldsToIgnoreMap. + put("com.sun.tools.javac.main.JavaCompiler", + Arrays.asList("versionRB")); + classFieldsToIgnoreMap. + put("com.sun.tools.javac.code.Type", + Arrays.asList("moreInfo")); + classFieldsToIgnoreMap. + put("com.sun.tools.javac.util.SharedNameTable", + Arrays.asList("freelist")); + classFieldsToIgnoreMap. + put("com.sun.tools.javac.util.Log", + Arrays.asList("useRawMessages")); + } + +} diff --git a/langtools/make/tools/crules/resources/crules.properties b/langtools/make/tools/crules/resources/crules.properties new file mode 100644 index 00000000000..9ae44b5258b --- /dev/null +++ b/langtools/make/tools/crules/resources/crules.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# 0: symbol +crules.err.var.must.be.final=\ + Static variable {0} must be final diff --git a/langtools/src/share/classes/com/sun/source/util/DocSourcePositions.java b/langtools/src/share/classes/com/sun/source/util/DocSourcePositions.java new file mode 100644 index 00000000000..d249da1c278 --- /dev/null +++ b/langtools/src/share/classes/com/sun/source/util/DocSourcePositions.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.source.util; + +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.tree.CompilationUnitTree; + +/** + * Provides methods to obtain the position of a DocTree within a javadoc comment. + * A position is defined as a simple character offset from the start of a + * CompilationUnit where the first character is at offset 0. + * + * @since 1.8 + */ +@jdk.Supported +public interface DocSourcePositions extends SourcePositions { + + /** + * Gets the starting position of the tree within the comment within the file. If tree is not found within + * file, or if the starting position is not available, + * return {@link javax.tools.Diagnostic#NOPOS}. + * The given tree should be under the given comment tree, and the given documentation + * comment tree should be returned from a {@link DocTrees#getDocCommentTree(com.sun.source.util.TreePath) } + * for a tree under the given file. + * The returned position must be at the start of the yield of this tree, that + * is for any sub-tree of this tree, the following must hold: + * + * + * {@code tree.getStartPosition() <= subtree.getStartPosition()} or
+ * + * @param file CompilationUnit in which to find tree. + * @param comment the comment tree that encloses the tree for which the + * position is being sought + * @param tree tree for which a position is sought. + * @return the start position of tree. + */ + long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree); + + /** + * Gets the ending position of the tree within the comment within the file. If tree is not found within + * file, or if the ending position is not available, + * return {@link javax.tools.Diagnostic#NOPOS}. + * The given tree should be under the given comment tree, and the given documentation + * comment tree should be returned from a {@link DocTrees#getDocCommentTree(com.sun.source.util.TreePath) } + * for a tree under the given file. + * The returned position must be at the end of the yield of this tree, + * that is for any sub-tree of this tree, the following must hold: + * + *
+ * {@code tree.getStartPosition() == NOPOS} or
+ * {@code subtree.getStartPosition() == NOPOS} + *+ * {@code tree.getEndPosition() >= subtree.getEndPosition()} or
+ * + * In addition, the following must hold: + * + *
+ * {@code tree.getEndPosition() == NOPOS} or
+ * {@code subtree.getEndPosition() == NOPOS} + *+ * {@code tree.getStartPosition() <= tree.getEndPosition()} or
+ * + * @param file CompilationUnit in which to find tree. + * @param comment the comment tree that encloses the tree for which the + * position is being sought + * @param tree tree for which a position is sought. + * @return the start position of tree. + */ + long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree); + +} diff --git a/langtools/src/share/classes/com/sun/source/util/DocTrees.java b/langtools/src/share/classes/com/sun/source/util/DocTrees.java index 63f6c899c20..94f68bbd4a7 100644 --- a/langtools/src/share/classes/com/sun/source/util/DocTrees.java +++ b/langtools/src/share/classes/com/sun/source/util/DocTrees.java @@ -72,6 +72,8 @@ public abstract class DocTrees extends Trees { */ public abstract Element getElement(TreePath path, ReferenceTree reference); + public abstract DocSourcePositions getSourcePositions(); + /** * Prints a message of the specified kind at the location of the * tree within the provided compilation unit diff --git a/langtools/src/share/classes/com/sun/source/util/SourcePositions.java b/langtools/src/share/classes/com/sun/source/util/SourcePositions.java index d55c73135ab..4494d320434 100644 --- a/langtools/src/share/classes/com/sun/source/util/SourcePositions.java +++ b/langtools/src/share/classes/com/sun/source/util/SourcePositions.java @@ -59,7 +59,7 @@ public interface SourcePositions { /** * Gets the ending position of tree within file. If tree is not found within - * file, or if the starting position is not available, + * file, or if the ending position is not available, * return {@link javax.tools.Diagnostic#NOPOS}. * The returned position must be at the end of the yield of this tree, * that is for any sub-tree of this tree, the following must hold: diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java index 39a58f30d1f..336a6876574 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java @@ -315,7 +315,7 @@ public class Dependencies { static class SimpleLocation implements Location { public SimpleLocation(String name) { this.name = name; - this.className = name.replace('/', '.').replace('$', '.'); + this.className = name.replace('/', '.'); } public String getName() { diff --git a/langtools/src/share/classes/com/sun/tools/classfile/ReferenceFinder.java b/langtools/src/share/classes/com/sun/tools/classfile/ReferenceFinder.java new file mode 100644 index 00000000000..1cc819c11b8 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/classfile/ReferenceFinder.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.classfile; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import com.sun.tools.classfile.Instruction.TypeKind; +import static com.sun.tools.classfile.ConstantPool.*; + +/** + * A utility class to find where in a ClassFile references + * a {@link CONSTANT_Methodref_info method}, + * a {@link CONSTANT_InterfaceMethodref_info interface method, + * or a {@link CONSTANT_Fieldref_info field}. + */ +public final class ReferenceFinder { + /** + * Filter for ReferenceFinder of what constant pool entries for reference lookup. + */ + public interface Filter { + /** + * Decides if the given CPRefInfo entry should be accepted or filtered. + * + * @param cpool ConstantPool of the ClassFile being parsed + * @param cpref constant pool entry representing a reference to + * a fields method, and interface method. + * @return {@code true} if accepted; otherwise {@code false} + */ + boolean accept(ConstantPool cpool, CPRefInfo cpref); + } + + /** + * Visitor of individual method of a ClassFile that references the + * accepted field, method, or interface method references. + */ + public interface Visitor { + /** + * Invoked for a method containing one or more accepted CPRefInfo entries + * + * @param cf ClassFile + * @param method Method that does the references the accepted references + * @param refs Accepted constant pool method/field reference + */ + void visit(ClassFile cf, Method method, List
+ * {@code tree.getStartPosition() == NOPOS} or
+ * {@code tree.getEndPosition() == NOPOS} + *refConstantPool); + } + + private final Filter filter; + private final Visitor visitor; + + /** + * Constructor. + */ + public ReferenceFinder(Filter filter, Visitor visitor) { + this.filter = Objects.requireNonNull(filter); + this.visitor = Objects.requireNonNull(visitor); + } + + /** + * Parses a given ClassFile and invoke the visitor if there is any reference + * to the constant pool entries referencing field, method, or + * interface method that are accepted. This method will return + * {@code true} if there is one or more accepted constant pool entries + * to lookup; otherwise, it will return {@code false}. + * + * @param cf ClassFile + * @return {@code true} if the given class file is processed to lookup + * references + * @throws ConstantPoolException if an error of the constant pool + */ + public boolean parse(ClassFile cf) throws ConstantPoolException { + List cprefs = new ArrayList (); + int index = 1; + for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) { + if (cpInfo.accept(cpVisitor, cf.constant_pool)) { + cprefs.add(index); + } + index += cpInfo.size(); + } + + if (cprefs.isEmpty()) { + return false; + } + + for (Method m : cf.methods) { + Set ids = new HashSet (); + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + for (Instruction instr : c_attr.getInstructions()) { + int idx = instr.accept(codeVisitor, cprefs); + if (idx > 0) { + ids.add(idx); + } + } + } + if (ids.size() > 0) { + List refInfos = new ArrayList (ids.size()); + for (int id : ids) { + refInfos.add(CPRefInfo.class.cast(cf.constant_pool.get(id))); + } + visitor.visit(cf, m, refInfos); + } + } + return true; + } + + private ConstantPool.Visitor cpVisitor = + new ConstantPool.Visitor () + { + public Boolean visitClass(CONSTANT_Class_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ConstantPool cpool) { + return filter.accept(cpool, info); + } + + public Boolean visitMethodref(CONSTANT_Methodref_info info, ConstantPool cpool) { + return filter.accept(cpool, info); + } + + public Boolean visitFieldref(CONSTANT_Fieldref_info info, ConstantPool cpool) { + return filter.accept(cpool, info); + } + + public Boolean visitDouble(CONSTANT_Double_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitFloat(CONSTANT_Float_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitInteger(CONSTANT_Integer_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitLong(CONSTANT_Long_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitNameAndType(CONSTANT_NameAndType_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitMethodType(CONSTANT_MethodType_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitString(CONSTANT_String_info info, ConstantPool cpool) { + return false; + } + + public Boolean visitUtf8(CONSTANT_Utf8_info info, ConstantPool cpool) { + return false; + } + }; + + private Instruction.KindVisitor > codeVisitor = + new Instruction.KindVisitor >() + { + public Integer visitNoOperands(Instruction instr, List p) { + return 0; + } + + public Integer visitArrayType(Instruction instr, TypeKind kind, List p) { + return 0; + } + + public Integer visitBranch(Instruction instr, int offset, List p) { + return 0; + } + + public Integer visitConstantPoolRef(Instruction instr, int index, List p) { + return p.contains(index) ? index : 0; + } + + public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List p) { + return p.contains(index) ? index : 0; + } + + public Integer visitLocal(Instruction instr, int index, List p) { + return 0; + } + + public Integer visitLocalAndValue(Instruction instr, int index, int value, List p) { + return 0; + } + + public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List p) { + return 0; + } + + public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List p) { + return 0; + } + + public Integer visitValue(Instruction instr, int value, List p) { + return 0; + } + + public Integer visitUnknown(Instruction instr, List p) { + return 0; + } + }; +} + diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java index 490490178fb..545b883f7f0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,14 +43,16 @@ import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; import com.sun.source.doctree.ReferenceTree; import com.sun.source.tree.CatchTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.Scope; import com.sun.source.tree.Tree; +import com.sun.source.util.DocSourcePositions; +import com.sun.source.util.DocTreeScanner; import com.sun.source.util.DocTrees; import com.sun.source.util.JavacTask; -import com.sun.source.util.SourcePositions; import com.sun.source.util.TreePath; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Kinds; @@ -76,8 +78,14 @@ import com.sun.tools.javac.comp.Resolve; import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.DCTree; +import com.sun.tools.javac.tree.DCTree.DCBlockTag; import com.sun.tools.javac.tree.DCTree.DCDocComment; +import com.sun.tools.javac.tree.DCTree.DCEndPosTree; +import com.sun.tools.javac.tree.DCTree.DCErroneous; +import com.sun.tools.javac.tree.DCTree.DCIdentifier; +import com.sun.tools.javac.tree.DCTree.DCParam; import com.sun.tools.javac.tree.DCTree.DCReference; +import com.sun.tools.javac.tree.DCTree.DCText; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; @@ -94,6 +102,7 @@ import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Pair; +import com.sun.tools.javac.util.Position; import static com.sun.tools.javac.code.TypeTag.*; /** @@ -166,8 +175,8 @@ public class JavacTrees extends DocTrees { javacTaskImpl = (JavacTaskImpl) t; } - public SourcePositions getSourcePositions() { - return new SourcePositions() { + public DocSourcePositions getSourcePositions() { + return new DocSourcePositions() { public long getStartPosition(CompilationUnitTree file, Tree tree) { return TreeInfo.getStartPos((JCTree) tree); } @@ -176,9 +185,80 @@ public class JavacTrees extends DocTrees { EndPosTable endPosTable = ((JCCompilationUnit) file).endPositions; return TreeInfo.getEndPos((JCTree) tree, endPosTable); } + + public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { + return ((DCTree) tree).getSourcePosition((DCDocComment) comment); + } + @SuppressWarnings("fallthrough") + public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { + DCDocComment dcComment = (DCDocComment) comment; + if (tree instanceof DCEndPosTree) { + int endPos = ((DCEndPosTree) tree).getEndPos(dcComment); + + if (endPos != Position.NOPOS) { + return endPos; + } + } + int correction = 0; + switch (tree.getKind()) { + case TEXT: + DCText text = (DCText) tree; + + return dcComment.comment.getSourcePos(text.pos + text.text.length()); + case ERRONEOUS: + DCErroneous err = (DCErroneous) tree; + + return dcComment.comment.getSourcePos(err.pos + err.body.length()); + case IDENTIFIER: + DCIdentifier ident = (DCIdentifier) tree; + + return dcComment.comment.getSourcePos(ident.pos + (ident.name != names.error ? ident.name.length() : 0)); + case PARAM: + DCParam param = (DCParam) tree; + + if (param.isTypeParameter && param.getDescription().isEmpty()) { + correction = 1; + } + case AUTHOR: case DEPRECATED: case RETURN: case SEE: + case SERIAL: case SERIAL_DATA: case SERIAL_FIELD: case SINCE: + case THROWS: case UNKNOWN_BLOCK_TAG: case VERSION: { + DocTree last = getLastChild(tree); + + if (last != null) { + return getEndPosition(file, comment, last) + correction; + } + + DCBlockTag block = (DCBlockTag) tree; + + return dcComment.comment.getSourcePos(block.pos + block.getTagName().length() + 1); + } + default: + DocTree last = getLastChild(tree); + + if (last != null) { + return getEndPosition(file, comment, last); + } + break; + } + + return Position.NOPOS; + } }; } + private DocTree getLastChild(DocTree tree) { + final DocTree[] last = new DocTree[] {null}; + + tree.accept(new DocTreeScanner () { + @Override public Void scan(DocTree node, Void p) { + if (node != null) last[0] = node; + return null; + } + }, null); + + return last[0]; + } + public JCClassDecl getTree(TypeElement element) { return (JCClassDecl) getTree((Element) element); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index 7276303b8b3..4072a948a7f 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -465,18 +465,11 @@ public abstract class Symbol implements Element { * This is the implementation for {@code * javax.lang.model.element.Element.getAnnotationMirrors()}. */ - public final List extends AnnotationMirror> getAnnotationMirrors() { + @Override + public List getAnnotationMirrors() { return getRawAttributes(); } - /** - * TODO: Should there be a {@code - * javax.lang.model.element.Element.getTypeAnnotationMirrors()}. - */ - public final List getTypeAnnotationMirrors() { - return getRawTypeAttributes(); - } - /** * @deprecated this method should never be used by javac internally. */ @@ -656,6 +649,24 @@ public abstract class Symbol implements Element { } } + @Override + public List getAnnotationMirrors() { + return onlyTypeVariableAnnotations(owner.getRawTypeAttributes()); + } + + private List onlyTypeVariableAnnotations( + List candidates) { + // Declaration annotations on TypeParameters are stored in type attributes + List res = List.nil(); + for (Attribute.TypeCompound a : candidates) { + if (a.position.type == TargetType.CLASS_TYPE_PARAMETER || + a.position.type == TargetType.METHOD_TYPE_PARAMETER) + res = res.prepend(a); + } + + return res = res.reverse(); + } + @Override public R accept(ElementVisitor v, P p) { return v.visitTypeParameter(this, p); diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 460f7e339af..94c57fe43b8 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -206,7 +206,7 @@ public class TypeAnnotations { sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { // Make sure all type annotations from the symbol are also // on the owner. - sym.owner.annotations.appendUniqueTypes(sym.getTypeAnnotationMirrors()); + sym.owner.annotations.appendUniqueTypes(sym.getRawTypeAttributes()); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index eb56d999459..01fc16abd95 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -1078,7 +1078,8 @@ public class Check { mask = MethodFlags; } // Imply STRICTFP if owner has STRICTFP set. - if (((flags|implicit) & Flags.ABSTRACT) == 0) + if (((flags|implicit) & Flags.ABSTRACT) == 0 || + ((flags) & Flags.DEFAULT) != 0) implicit |= sym.owner.flags_field & STRICTFP; break; case TYP: diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java index 5c1fc76e19a..1e6d7da1839 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -35,7 +35,6 @@ import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.comp.Resolve; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; @@ -276,6 +275,15 @@ public class Flow { allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); } + /** + * Utility method to reset several Bits instances. + */ + private void resetBits(Bits... bits) { + for (Bits b : bits) { + b.reset(); + } + } + /** * Base visitor class for all visitors implementing dataflow analysis logic. * This class define the shared logic for handling jumps (break/continue statements). @@ -1294,11 +1302,11 @@ public class Flow { /** The set of definitely assigned variables. */ - Bits inits; + final Bits inits; /** The set of definitely unassigned variables. */ - Bits uninits; + final Bits uninits; /** The set of variables that are definitely unassigned everywhere * in current try block. This variable is maintained lazily; it is @@ -1308,15 +1316,15 @@ public class Flow { * anywhere in current try block, intersect uninitsTry and * uninits. */ - Bits uninitsTry; + final Bits uninitsTry; /** When analyzing a condition, inits and uninits are null. * Instead we have: */ - Bits initsWhenTrue; - Bits initsWhenFalse; - Bits uninitsWhenTrue; - Bits uninitsWhenFalse; + final Bits initsWhenTrue; + final Bits initsWhenFalse; + final Bits uninitsWhenTrue; + final Bits uninitsWhenFalse; /** A mapping from addresses to variable symbols. */ @@ -1348,15 +1356,25 @@ public class Flow { /** The starting position of the analysed tree */ int startPos; + AssignAnalyzer() { + inits = new Bits(); + uninits = new Bits(); + uninitsTry = new Bits(); + initsWhenTrue = new Bits(true); + initsWhenFalse = new Bits(true); + uninitsWhenTrue = new Bits(true); + uninitsWhenFalse = new Bits(true); + } + class AssignPendingExit extends BaseAnalyzer.PendingExit { - Bits exit_inits; - Bits exit_uninits; + final Bits exit_inits = new Bits(true); + final Bits exit_uninits = new Bits(true); - AssignPendingExit(JCTree tree, Bits inits, Bits uninits) { + AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { super(tree); - this.exit_inits = inits.dup(); - this.exit_uninits = uninits.dup(); + this.exit_inits.assign(inits); + this.exit_uninits.assign(uninits); } void resolveJump() { @@ -1476,19 +1494,20 @@ public class Flow { /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets */ void split(boolean setToNull) { - initsWhenFalse = inits.dup(); - uninitsWhenFalse = uninits.dup(); - initsWhenTrue = inits; - uninitsWhenTrue = uninits; - if (setToNull) - inits = uninits = null; + initsWhenFalse.assign(inits); + uninitsWhenFalse.assign(uninits); + initsWhenTrue.assign(inits); + uninitsWhenTrue.assign(uninits); + if (setToNull) { + resetBits(inits, uninits); + } } /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. */ void merge() { - inits = initsWhenFalse.andSet(initsWhenTrue); - uninits = uninitsWhenFalse.andSet(uninitsWhenTrue); + inits.assign(initsWhenFalse.andSet(initsWhenTrue)); + uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); } /* ************************************************************************ @@ -1501,7 +1520,7 @@ public class Flow { void scanExpr(JCTree tree) { if (tree != null) { scan(tree); - if (inits == null) merge(); + if (inits.isReset()) merge(); } } @@ -1518,28 +1537,29 @@ public class Flow { */ void scanCond(JCTree tree) { if (tree.type.isFalse()) { - if (inits == null) merge(); - initsWhenTrue = inits.dup(); + if (inits.isReset()) merge(); + initsWhenTrue.assign(inits); initsWhenTrue.inclRange(firstadr, nextadr); - uninitsWhenTrue = uninits.dup(); + uninitsWhenTrue.assign(uninits); uninitsWhenTrue.inclRange(firstadr, nextadr); - initsWhenFalse = inits; - uninitsWhenFalse = uninits; + initsWhenFalse.assign(inits); + uninitsWhenFalse.assign(uninits); } else if (tree.type.isTrue()) { - if (inits == null) merge(); - initsWhenFalse = inits.dup(); + if (inits.isReset()) merge(); + initsWhenFalse.assign(inits); initsWhenFalse.inclRange(firstadr, nextadr); - uninitsWhenFalse = uninits.dup(); + uninitsWhenFalse.assign(uninits); uninitsWhenFalse.inclRange(firstadr, nextadr); - initsWhenTrue = inits; - uninitsWhenTrue = uninits; + initsWhenTrue.assign(inits); + uninitsWhenTrue.assign(uninits); } else { scan(tree); - if (inits != null) + if (!inits.isReset()) split(tree.type != syms.unknownType); } - if (tree.type != syms.unknownType) - inits = uninits = null; + if (tree.type != syms.unknownType) { + resetBits(inits, uninits); + } } /* ------------ Visitor methods for various sorts of trees -------------*/ @@ -1619,8 +1639,8 @@ public class Flow { public void visitMethodDef(JCMethodDecl tree) { if (tree.body == null) return; - Bits initsPrev = inits.dup(); - Bits uninitsPrev = uninits.dup(); + final Bits initsPrev = new Bits(inits); + final Bits uninitsPrev = new Bits(uninits); int nextadrPrev = nextadr; int firstadrPrev = firstadr; int returnadrPrev = returnadr; @@ -1658,14 +1678,14 @@ public class Flow { exits = exits.tail; Assert.check(exit.tree.hasTag(RETURN), exit.tree); if (isInitialConstructor) { - inits = exit.exit_inits; + inits.assign(exit.exit_inits); for (int i = firstadr; i < nextadr; i++) checkInit(exit.tree.pos(), vars[i]); } } } finally { - inits = initsPrev; - uninits = uninitsPrev; + inits.assign(initsPrev); + uninits.assign(uninitsPrev); nextadr = nextadrPrev; firstadr = firstadrPrev; returnadr = returnadrPrev; @@ -1698,31 +1718,31 @@ public class Flow { ListBuffer prevPendingExits = pendingExits; FlowKind prevFlowKind = flowKind; flowKind = FlowKind.NORMAL; - Bits initsSkip = null; - Bits uninitsSkip = null; + final Bits initsSkip = new Bits(true); + final Bits uninitsSkip = new Bits(true); pendingExits = new ListBuffer (); int prevErrors = log.nerrors; do { - Bits uninitsEntry = uninits.dup(); + final Bits uninitsEntry = new Bits(uninits); uninitsEntry.excludeFrom(nextadr); scan(tree.body); resolveContinues(tree); scanCond(tree.cond); if (!flowKind.isFinal()) { - initsSkip = initsWhenFalse; - uninitsSkip = uninitsWhenFalse; + initsSkip.assign(initsWhenFalse); + uninitsSkip.assign(uninitsWhenFalse); } if (log.nerrors != prevErrors || flowKind.isFinal() || - uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) + new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) break; - inits = initsWhenTrue; - uninits = uninitsEntry.andSet(uninitsWhenTrue); + inits.assign(initsWhenTrue); + uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); flowKind = FlowKind.SPECULATIVE_LOOP; } while (true); flowKind = prevFlowKind; - inits = initsSkip; - uninits = uninitsSkip; + inits.assign(initsSkip); + uninits.assign(uninitsSkip); resolveBreaks(tree, prevPendingExits); } @@ -1730,34 +1750,34 @@ public class Flow { ListBuffer prevPendingExits = pendingExits; FlowKind prevFlowKind = flowKind; flowKind = FlowKind.NORMAL; - Bits initsSkip = null; - Bits uninitsSkip = null; + final Bits initsSkip = new Bits(true); + final Bits uninitsSkip = new Bits(true); pendingExits = new ListBuffer (); int prevErrors = log.nerrors; - Bits uninitsEntry = uninits.dup(); + final Bits uninitsEntry = new Bits(uninits); uninitsEntry.excludeFrom(nextadr); do { scanCond(tree.cond); if (!flowKind.isFinal()) { - initsSkip = initsWhenFalse; - uninitsSkip = uninitsWhenFalse; + initsSkip.assign(initsWhenFalse) ; + uninitsSkip.assign(uninitsWhenFalse); } - inits = initsWhenTrue; - uninits = uninitsWhenTrue; + inits.assign(initsWhenTrue); + uninits.assign(uninitsWhenTrue); scan(tree.body); resolveContinues(tree); if (log.nerrors != prevErrors || flowKind.isFinal() || - uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1) + new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) break; - uninits = uninitsEntry.andSet(uninits); + uninits.assign(uninitsEntry.andSet(uninits)); flowKind = FlowKind.SPECULATIVE_LOOP; } while (true); flowKind = prevFlowKind; //a variable is DA/DU after the while statement, if it's DA/DU assuming the //branch is not taken AND if it's DA/DU before any break statement - inits = initsSkip; - uninits = uninitsSkip; + inits.assign(initsSkip); + uninits.assign(uninitsSkip); resolveBreaks(tree, prevPendingExits); } @@ -1767,25 +1787,25 @@ public class Flow { flowKind = FlowKind.NORMAL; int nextadrPrev = nextadr; scan(tree.init); - Bits initsSkip = null; - Bits uninitsSkip = null; + final Bits initsSkip = new Bits(true); + final Bits uninitsSkip = new Bits(true); pendingExits = new ListBuffer (); int prevErrors = log.nerrors; do { - Bits uninitsEntry = uninits.dup(); + final Bits uninitsEntry = new Bits(uninits); uninitsEntry.excludeFrom(nextadr); if (tree.cond != null) { scanCond(tree.cond); if (!flowKind.isFinal()) { - initsSkip = initsWhenFalse; - uninitsSkip = uninitsWhenFalse; + initsSkip.assign(initsWhenFalse); + uninitsSkip.assign(uninitsWhenFalse); } - inits = initsWhenTrue; - uninits = uninitsWhenTrue; + inits.assign(initsWhenTrue); + uninits.assign(uninitsWhenTrue); } else if (!flowKind.isFinal()) { - initsSkip = inits.dup(); + initsSkip.assign(inits); initsSkip.inclRange(firstadr, nextadr); - uninitsSkip = uninits.dup(); + uninitsSkip.assign(uninits); uninitsSkip.inclRange(firstadr, nextadr); } scan(tree.body); @@ -1793,16 +1813,16 @@ public class Flow { scan(tree.step); if (log.nerrors != prevErrors || flowKind.isFinal() || - uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1) + new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) break; - uninits = uninitsEntry.andSet(uninits); + uninits.assign(uninitsEntry.andSet(uninits)); flowKind = FlowKind.SPECULATIVE_LOOP; } while (true); flowKind = prevFlowKind; //a variable is DA/DU after a for loop, if it's DA/DU assuming the //branch is not taken AND if it's DA/DU before any break statement - inits = initsSkip; - uninits = uninitsSkip; + inits.assign(initsSkip); + uninits.assign(uninitsSkip); resolveBreaks(tree, prevPendingExits); nextadr = nextadrPrev; } @@ -1815,27 +1835,27 @@ public class Flow { flowKind = FlowKind.NORMAL; int nextadrPrev = nextadr; scan(tree.expr); - Bits initsStart = inits.dup(); - Bits uninitsStart = uninits.dup(); + final Bits initsStart = new Bits(inits); + final Bits uninitsStart = new Bits(uninits); letInit(tree.pos(), tree.var.sym); pendingExits = new ListBuffer (); int prevErrors = log.nerrors; do { - Bits uninitsEntry = uninits.dup(); + final Bits uninitsEntry = new Bits(uninits); uninitsEntry.excludeFrom(nextadr); scan(tree.body); resolveContinues(tree); if (log.nerrors != prevErrors || flowKind.isFinal() || - uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1) + new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) break; - uninits = uninitsEntry.andSet(uninits); + uninits.assign(uninitsEntry.andSet(uninits)); flowKind = FlowKind.SPECULATIVE_LOOP; } while (true); flowKind = prevFlowKind; - inits = initsStart; - uninits = uninitsStart.andSet(uninits); + inits.assign(initsStart); + uninits.assign(uninitsStart.andSet(uninits)); resolveBreaks(tree, prevPendingExits); nextadr = nextadrPrev; } @@ -1852,12 +1872,12 @@ public class Flow { pendingExits = new ListBuffer (); int nextadrPrev = nextadr; scanExpr(tree.selector); - Bits initsSwitch = inits; - Bits uninitsSwitch = uninits.dup(); + final Bits initsSwitch = new Bits(inits); + final Bits uninitsSwitch = new Bits(uninits); boolean hasDefault = false; for (List l = tree.cases; l.nonEmpty(); l = l.tail) { - inits = initsSwitch.dup(); - uninits = uninits.andSet(uninitsSwitch); + inits.assign(initsSwitch); + uninits.assign(uninits.andSet(uninitsSwitch)); JCCase c = l.head; if (c.pat == null) hasDefault = true; @@ -1875,8 +1895,8 @@ public class Flow { } // where /** Add any variables defined in stats to inits and uninits. */ - private void addVars(List stats, Bits inits, - Bits uninits) { + private void addVars(List stats, final Bits inits, + final Bits uninits) { for (;stats.nonEmpty(); stats = stats.tail) { JCTree stat = stats.head; if (stat.hasTag(VARDEF)) { @@ -1889,11 +1909,11 @@ public class Flow { public void visitTry(JCTry tree) { ListBuffer resourceVarDecls = ListBuffer.lb(); - Bits uninitsTryPrev = uninitsTry; + final Bits uninitsTryPrev = new Bits(uninitsTry); ListBuffer prevPendingExits = pendingExits; pendingExits = new ListBuffer (); - Bits initsTry = inits.dup(); - uninitsTry = uninits.dup(); + final Bits initsTry = new Bits(inits); + uninitsTry.assign(uninits); for (JCTree resource : tree.resources) { if (resource instanceof JCVariableDecl) { JCVariableDecl vdecl = (JCVariableDecl) resource; @@ -1908,8 +1928,8 @@ public class Flow { } scan(tree.body); uninitsTry.andSet(uninits); - Bits initsEnd = inits; - Bits uninitsEnd = uninits; + final Bits initsEnd = new Bits(inits); + final Bits uninitsEnd = new Bits(uninits); int nextadrCatch = nextadr; if (!resourceVarDecls.isEmpty() && @@ -1925,8 +1945,8 @@ public class Flow { for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { JCVariableDecl param = l.head.param; - inits = initsTry.dup(); - uninits = uninitsTry.dup(); + inits.assign(initsTry); + uninits.assign(uninitsTry); scan(param); inits.incl(param.sym.adr); uninits.excl(param.sym.adr); @@ -1936,8 +1956,8 @@ public class Flow { nextadr = nextadrCatch; } if (tree.finalizer != null) { - inits = initsTry.dup(); - uninits = uninitsTry.dup(); + inits.assign(initsTry); + uninits.assign(uninitsTry); ListBuffer exits = pendingExits; pendingExits = prevPendingExits; scan(tree.finalizer); @@ -1958,8 +1978,8 @@ public class Flow { inits.orSet(initsEnd); } } else { - inits = initsEnd; - uninits = uninitsEnd; + inits.assign(initsEnd); + uninits.assign(uninitsEnd); ListBuffer exits = pendingExits; pendingExits = prevPendingExits; while (exits.nonEmpty()) pendingExits.append(exits.next()); @@ -1969,10 +1989,10 @@ public class Flow { public void visitConditional(JCConditional tree) { scanCond(tree.cond); - Bits initsBeforeElse = initsWhenFalse; - Bits uninitsBeforeElse = uninitsWhenFalse; - inits = initsWhenTrue; - uninits = uninitsWhenTrue; + final Bits initsBeforeElse = new Bits(initsWhenFalse); + final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); + inits.assign(initsWhenTrue); + uninits.assign(uninitsWhenTrue); if (tree.truepart.type.hasTag(BOOLEAN) && tree.falsepart.type.hasTag(BOOLEAN)) { // if b and c are boolean valued, then @@ -1980,12 +2000,12 @@ public class Flow { // v is (un)assigned after b when true and // v is (un)assigned after c when true scanCond(tree.truepart); - Bits initsAfterThenWhenTrue = initsWhenTrue.dup(); - Bits initsAfterThenWhenFalse = initsWhenFalse.dup(); - Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup(); - Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup(); - inits = initsBeforeElse; - uninits = uninitsBeforeElse; + final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); + final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); + final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); + final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); + inits.assign(initsBeforeElse); + uninits.assign(uninitsBeforeElse); scanCond(tree.falsepart); initsWhenTrue.andSet(initsAfterThenWhenTrue); initsWhenFalse.andSet(initsAfterThenWhenFalse); @@ -1993,10 +2013,10 @@ public class Flow { uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); } else { scanExpr(tree.truepart); - Bits initsAfterThen = inits.dup(); - Bits uninitsAfterThen = uninits.dup(); - inits = initsBeforeElse; - uninits = uninitsBeforeElse; + final Bits initsAfterThen = new Bits(inits); + final Bits uninitsAfterThen = new Bits(uninits); + inits.assign(initsBeforeElse); + uninits.assign(uninitsBeforeElse); scanExpr(tree.falsepart); inits.andSet(initsAfterThen); uninits.andSet(uninitsAfterThen); @@ -2005,16 +2025,16 @@ public class Flow { public void visitIf(JCIf tree) { scanCond(tree.cond); - Bits initsBeforeElse = initsWhenFalse; - Bits uninitsBeforeElse = uninitsWhenFalse; - inits = initsWhenTrue; - uninits = uninitsWhenTrue; + final Bits initsBeforeElse = new Bits(initsWhenFalse); + final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); + inits.assign(initsWhenTrue); + uninits.assign(uninitsWhenTrue); scan(tree.thenpart); if (tree.elsepart != null) { - Bits initsAfterThen = inits.dup(); - Bits uninitsAfterThen = uninits.dup(); - inits = initsBeforeElse; - uninits = uninitsBeforeElse; + final Bits initsAfterThen = new Bits(inits); + final Bits uninitsAfterThen = new Bits(uninits); + inits.assign(initsBeforeElse); + uninits.assign(uninitsBeforeElse); scan(tree.elsepart); inits.andSet(initsAfterThen); uninits.andSet(uninitsAfterThen); @@ -2055,8 +2075,8 @@ public class Flow { @Override public void visitLambda(JCLambda tree) { - Bits prevUninits = uninits; - Bits prevInits = inits; + final Bits prevUninits = new Bits(uninits); + final Bits prevInits = new Bits(inits); int returnadrPrev = returnadr; ListBuffer prevPending = pendingExits; try { @@ -2076,8 +2096,8 @@ public class Flow { } finally { returnadr = returnadrPrev; - uninits = prevUninits; - inits = prevInits; + uninits.assign(prevUninits); + inits.assign(prevInits); pendingExits = prevPending; } } @@ -2088,17 +2108,17 @@ public class Flow { } public void visitAssert(JCAssert tree) { - Bits initsExit = inits.dup(); - Bits uninitsExit = uninits.dup(); + final Bits initsExit = new Bits(inits); + final Bits uninitsExit = new Bits(uninits); scanCond(tree.cond); uninitsExit.andSet(uninitsWhenTrue); if (tree.detail != null) { - inits = initsWhenFalse; - uninits = uninitsWhenFalse; + inits.assign(initsWhenFalse); + uninits.assign(uninitsWhenFalse); scanExpr(tree.detail); } - inits = initsExit; - uninits = uninitsExit; + inits.assign(initsExit); + uninits.assign(uninitsExit); } public void visitAssign(JCAssign tree) { @@ -2120,12 +2140,12 @@ public class Flow { switch (tree.getTag()) { case NOT: scanCond(tree.arg); - Bits t = initsWhenFalse; - initsWhenFalse = initsWhenTrue; - initsWhenTrue = t; - t = uninitsWhenFalse; - uninitsWhenFalse = uninitsWhenTrue; - uninitsWhenTrue = t; + final Bits t = new Bits(initsWhenFalse); + initsWhenFalse.assign(initsWhenTrue); + initsWhenTrue.assign(t); + t.assign(uninitsWhenFalse); + uninitsWhenFalse.assign(uninitsWhenTrue); + uninitsWhenTrue.assign(t); break; case PREINC: case POSTINC: case PREDEC: case POSTDEC: @@ -2141,20 +2161,20 @@ public class Flow { switch (tree.getTag()) { case AND: scanCond(tree.lhs); - Bits initsWhenFalseLeft = initsWhenFalse; - Bits uninitsWhenFalseLeft = uninitsWhenFalse; - inits = initsWhenTrue; - uninits = uninitsWhenTrue; + final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); + final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); + inits.assign(initsWhenTrue); + uninits.assign(uninitsWhenTrue); scanCond(tree.rhs); initsWhenFalse.andSet(initsWhenFalseLeft); uninitsWhenFalse.andSet(uninitsWhenFalseLeft); break; case OR: scanCond(tree.lhs); - Bits initsWhenTrueLeft = initsWhenTrue; - Bits uninitsWhenTrueLeft = uninitsWhenTrue; - inits = initsWhenFalse; - uninits = uninitsWhenFalse; + final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); + final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); + inits.assign(initsWhenFalse); + uninits.assign(uninitsWhenFalse); scanCond(tree.rhs); initsWhenTrue.andSet(initsWhenTrueLeft); uninitsWhenTrue.andSet(uninitsWhenTrueLeft); @@ -2200,11 +2220,7 @@ public class Flow { attrEnv = env; Flow.this.make = make; startPos = tree.pos().getStartPosition(); - inits = new Bits(); - uninits = new Bits(); - uninitsTry = new Bits(); - initsWhenTrue = initsWhenFalse = - uninitsWhenTrue = uninitsWhenFalse = null; + if (vars == null) vars = new VarSymbol[32]; else @@ -2219,9 +2235,8 @@ public class Flow { } finally { // note that recursive invocations of this method fail hard startPos = -1; - inits = uninits = uninitsTry = null; - initsWhenTrue = initsWhenFalse = - uninitsWhenTrue = uninitsWhenFalse = null; + resetBits(inits, uninits, uninitsTry, initsWhenTrue, + initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse); if (vars != null) for (int i=0; i attrEnv; /** the analyzer scanner */ - private LambdaAnalyzer analyzer; + private LambdaAnalyzerPreprocessor analyzer; /** map from lambda trees to translation contexts */ private Map > contextMap; @@ -156,7 +155,7 @@ public class LambdaToMethod extends TreeTranslator { make = TreeMaker.instance(context); types = Types.instance(context); transTypes = TransTypes.instance(context); - analyzer = new LambdaAnalyzer(); + analyzer = new LambdaAnalyzerPreprocessor(); } // @@ -206,7 +205,7 @@ public class LambdaToMethod extends TreeTranslator { public void visitClassDef(JCClassDecl tree) { if (tree.sym.owner.kind == PCK) { //analyze class - analyzer.analyzeClass(tree); + tree = analyzer.analyzeAndPreprocessClass(tree); } KlassInfo prevKlassInfo = kInfo; try { @@ -531,16 +530,25 @@ public class LambdaToMethod extends TreeTranslator { /** Make an attributed class instance creation expression. * @param ctype The class type. * @param args The constructor arguments. + * @param cons The constructor symbol */ - JCNewClass makeNewClass(Type ctype, List args) { + JCNewClass makeNewClass(Type ctype, List args, Symbol cons) { JCNewClass tree = make.NewClass(null, null, make.QualIdent(ctype.tsym), args, null); - tree.constructor = rs.resolveConstructor( - null, attrEnv, ctype, TreeInfo.types(args), List. nil()); + tree.constructor = cons; tree.type = ctype; return tree; } + /** Make an attributed class instance creation expression. + * @param ctype The class type. + * @param args The constructor arguments. + */ + JCNewClass makeNewClass(Type ctype, List args) { + return makeNewClass(ctype, args, + rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List. nil())); + } + private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, DiagnosticPosition pos, List
@@ -354,9 +359,14 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { **/ public String qualifiedName() { - return getClassName(tsym, true); + if (qualifiedName == null) { + qualifiedName = getClassName(tsym, true); + } + return qualifiedName; } + private String qualifiedName; + /** * Return unqualified name of type excluding any dimension information. *
@@ -380,9 +390,14 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
* Return the simple name of this type.
*/
public String simpleTypeName() {
- return tsym.name.toString();
+ if (simpleTypeName == null) {
+ simpleTypeName = tsym.name.toString();
+ }
+ return simpleTypeName;
}
+ private String simpleTypeName;
+
/**
* Return the qualified name and any type parameters.
* Each parameter is a type variable with optional bounds.
diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java
index e8e8f59d55c..1cec66ecd84 100644
--- a/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -252,13 +252,23 @@ public class FieldDocImpl extends MemberDocImpl implements FieldDoc {
}
public String name() {
- return sym.name.toString();
+ if (name == null) {
+ name = sym.name.toString();
+ }
+ return name;
}
+ private String name;
+
public String qualifiedName() {
- return sym.enclClass().getQualifiedName() + "." + name();
+ if (qualifiedName == null) {
+ qualifiedName = sym.enclClass().getQualifiedName() + "." + name();
+ }
+ return qualifiedName;
}
+ private String qualifiedName;
+
/**
* Return the source position of the entity, or null if
* no position is available.
diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java
index d8c03a8c980..4d5d191b929 100644
--- a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -203,13 +203,23 @@ public class MethodDocImpl
public String name() {
- return sym.name.toString();
+ if (name == null) {
+ name = sym.name.toString();
+ }
+ return name;
}
+ private String name;
+
public String qualifiedName() {
- return sym.enclClass().getQualifiedName() + "." + sym.name;
+ if (qualifiedName == null) {
+ qualifiedName = sym.enclClass().getQualifiedName() + "." + sym.name;
+ }
+ return qualifiedName;
}
+ private String qualifiedName;
+
/**
* Returns a string representation of this method. Includes the
* qualified signature, the qualified method name, and any type
diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java
index bc54bef6912..2f11b81134e 100644
--- a/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -334,12 +334,17 @@ public class PackageDocImpl extends DocImpl implements PackageDoc {
* Get package name.
*/
public String qualifiedName() {
- Name fullname = sym.getQualifiedName();
- // Some bogus tests depend on the interned "" being returned.
- // See 6457276.
- return fullname.isEmpty() ? "" : fullname.toString();
+ if (qualifiedName == null) {
+ Name fullname = sym.getQualifiedName();
+ // Some bogus tests depend on the interned "" being returned.
+ // See 6457276.
+ qualifiedName = fullname.isEmpty() ? "" : fullname.toString();
+ }
+ return qualifiedName;
}
+ private String qualifiedName;
+
/**
* set doc path for an unzipped directory
*/
diff --git a/langtools/test/tools/javac/api/TestJavacTaskScanner.java b/langtools/test/tools/javac/api/TestJavacTaskScanner.java
index da862644dc4..78ed5bb772c 100644
--- a/langtools/test/tools/javac/api/TestJavacTaskScanner.java
+++ b/langtools/test/tools/javac/api/TestJavacTaskScanner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -93,7 +93,7 @@ public class TestJavacTaskScanner extends ToolTester {
System.out.println("#allMembers: " + numAllMembers);
check(numTokens, "#Tokens", 1222);
- check(numParseTypeElements, "#parseTypeElements", 136);
+ check(numParseTypeElements, "#parseTypeElements", 158);
check(numAllMembers, "#allMembers", 52);
}
diff --git a/langtools/test/tools/javac/defaultMethods/CheckACC_STRICTFlagOnDefaultMethodTest.java b/langtools/test/tools/javac/defaultMethods/CheckACC_STRICTFlagOnDefaultMethodTest.java
new file mode 100644
index 00000000000..906b40a3c00
--- /dev/null
+++ b/langtools/test/tools/javac/defaultMethods/CheckACC_STRICTFlagOnDefaultMethodTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8012723
+ * @summary strictfp interface misses strictfp modifer on default method
+ * @run main CheckACC_STRICTFlagOnDefaultMethodTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.io.File;
+import java.io.IOException;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Descriptor;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.Method;
+
+import static com.sun.tools.classfile.AccessFlags.ACC_STRICT;
+
+public class CheckACC_STRICTFlagOnDefaultMethodTest {
+ private static final String AssertionErrorMessage =
+ "All methods should have the ACC_STRICT access flag " +
+ "please check output";
+ private static final String offendingMethodErrorMessage =
+ "Method %s of class %s doesn't have the ACC_STRICT access flag";
+
+ private List Description with {@link java.io.InputStream link}
+ *
+ * @param first description
+ * @param second description
+ * @return whatever
+ * @throws IllegalStateException why?
+ * @since 1.15
+ * @see java.util.List
+TEXT:First sentence.
+START_ELEMENT:
+TEXT:Description with!trailing-whitespace!
+LINK:{@link java.io.InputStream link}
+REFERENCE:java.io.InputStream
+TEXT:link
+PARAM:@param first description
+IDENTIFIER:first
+TEXT:description
+PARAM:@param second description
+IDENTIFIER:second
+TEXT:description
+RETURN:@return whatever
+TEXT:whatever
+THROWS:@throws IllegalStateException why?
+REFERENCE:IllegalStateException
+TEXT:why?
+SINCE:@since 1.15
+TEXT:1.15
+SEE:@see java.util.List
+REFERENCE:java.util.List
+erroneous:
+DOC_COMMENT:First sentence.
+ *
+ * Description with {@link}, {@link java.util.List}, {@link
+ *
+ * @param
+ * @param second
+ * @return
+ * @throws
+ * @throws IllegalStateException
+ * @since
+ * @see
+TEXT:First sentence.
+START_ELEMENT:
+TEXT:Description with!trailing-whitespace!
+LINK:{@link}
+TEXT:,!trailing-whitespace!
+LINK:{@link java.util.List}
+REFERENCE:java.util.List
+TEXT:,!trailing-whitespace!
+ERRONEOUS:{@link
+ERRONEOUS:@param
+PARAM:@param second
+IDENTIFIER:second
+RETURN:@return
+ERRONEOUS:@throws
+THROWS:@throws IllegalStateException
+REFERENCE:IllegalStateException
+SINCE:@since
+ERRONEOUS:@see
+withWhiteSpaces:
+DOC_COMMENT:First sentence.
+ *
+ * Description with {@link }, {@link java.util.List#add( int )},
+ * {@link java.util.List#add( int ) some text with whitespaces}, {@link
+ *
+ * @param first
+ * @param second some text with trailing whitespace
+ * @return some return
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalStateException some text
+TEXT:First sentence.
+START_ELEMENT:
+TEXT:Description with!trailing-whitespace!
+LINK:{@link }
+TEXT:,!trailing-whitespace!
+LINK:{@link java.util.List#add( int )}
+REFERENCE:java.util.List#add( int )
+TEXT:,
+ *!trailing-whitespace!
+LINK:{@link java.util.List#add( int ) some text with whitespaces}
+REFERENCE:java.util.List#add( int )
+TEXT:some text with whitespaces
+TEXT:,!trailing-whitespace!
+ERRONEOUS:{@link
+PARAM:@param first
+IDENTIFIER:first
+PARAM:@param second some text with trailing whitespace
+IDENTIFIER:second
+TEXT:some text with trailing whitespace
+RETURN:@return some return
+TEXT:some return
+THROWS:@throws java.lang.IllegalStateException
+REFERENCE:java.lang.IllegalStateException
+THROWS:@throws java.lang.IllegalStateException some text
+REFERENCE:java.lang.IllegalStateException
+TEXT:some text
\ No newline at end of file
diff --git a/langtools/test/tools/javac/doctree/positions/TestPositionSource.java b/langtools/test/tools/javac/doctree/positions/TestPositionSource.java
new file mode 100644
index 00000000000..801af3d687c
--- /dev/null
+++ b/langtools/test/tools/javac/doctree/positions/TestPositionSource.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+public class TestPositionSource {
+
+ /**First sentence.
+ *
+ * Description with {@link java.io.InputStream link}
+ *
+ * @param first description
+ * @param second description
+ * @return whatever
+ * @throws IllegalStateException why?
+ * @since 1.15
+ * @see java.util.List
+ */
+ public boolean valid(int first, int second) throws IllegalStateException {
+ return true;
+ }
+
+ /**First sentence.
+ *
+ * Description with {@link}, {@link java.util.List}, {@link
+ *
+ * @param
+ * @param second
+ * @return
+ * @throws
+ * @throws IllegalStateException
+ * @since
+ * @see
+ */
+ public boolean erroneous(int first, int second) throws IllegalStateException {
+ return true;
+ }
+
+ /**First sentence.
+ *
+ * Description with {@link }, {@link java.util.List#add( int )},
+ * {@link java.util.List#add( int ) some text with whitespaces}, {@link
+ *
+ * @param first
+ * @param second some text with trailing whitespace
+ * @return some return
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalStateException some text
+ */
+ public boolean withWhiteSpaces(int first, int second) throws IllegalStateException {
+ return true;
+ }
+
+}
diff --git a/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestNewInnerImplicitArgs.java b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestNewInnerImplicitArgs.java
new file mode 100644
index 00000000000..4f910572f09
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestNewInnerImplicitArgs.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8011591
+ * @summary BootstrapMethodError when capturing constructor ref to local classes
+ * @run testng MethodReferenceTestNewInnerImplicitArgs
+ */
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Test the case that a constructor has implicit parameters added to
+ * access local variables and that this constructor is used in a
+ * method reference.
+ * @author Robert Field
+ */
+
+@Test
+public class MethodReferenceTestNewInnerImplicitArgs {
+
+
+ static class S {
+ String b;
+ S(String s, String s2) { b = s + s2; }
+ }
+
+ interface I {
+ S m();
+ }
+
+ interface I2 {
+ S m(int i, int j);
+ }
+
+ public static void testConstructorReferenceImplicitParameters() {
+ String title = "Hey";
+ String a2 = "!!!";
+ class MS extends S {
+ MS() {
+ super(title, a2);
+ }
+ }
+
+ I result = MS::new;
+ assertEquals(result.m().b, "Hey!!!");
+
+ class MS2 extends S {
+ MS2(int x, int y) {
+ super(title+x, a2+y);
+ }
+ }
+
+ I2 result2 = MS2::new;
+ assertEquals(result2.m(8, 4).b, "Hey8!!!4");
+ }
+}
diff --git a/langtools/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java b/langtools/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java
new file mode 100644
index 00000000000..d0b5cc8ef7f
--- /dev/null
+++ b/langtools/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8011027
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor TestTypeParameterAnnotations
+ * @compile -processor TestTypeParameterAnnotations -proc:only TestTypeParameterAnnotations.java
+ */
+
+import java.util.*;
+import java.lang.annotation.*;
+import javax.annotation.processing.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import javax.tools.*;
+
+public class TestTypeParameterAnnotations<@Foo @Bar @Baz T> extends JavacTestingAbstractProcessor {
+ int round = 0;
+
+ public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (++round == 1) {
+ int found = (new Scanner()).scan(roundEnv.getRootElements(), null);
+ if (found == expect) {
+ ; //nop
+ } else {
+ error("unexpected number of results: expected " + expect
+ + ", found " + found);
+ }
+
+ }
+ return true;
+ }
+
+ class Scanner extends JavacTestingAbstractProcessor.ElementScanner