This commit is contained in:
J. Duke 2017-07-05 19:10:03 +02:00
commit 44b5df1ac8
193 changed files with 8712 additions and 2002 deletions

View File

@ -226,3 +226,4 @@ d2dcb110e9dbaf9903c05b211df800e78e4b394e jdk8-b100
5eb3c1dc348f72a7f84f7d9d07834e8bbe09a799 jdk8-b102 5eb3c1dc348f72a7f84f7d9d07834e8bbe09a799 jdk8-b102
b7e64be81c8a7690703df5711f4fc2375da8a9cb jdk8-b103 b7e64be81c8a7690703df5711f4fc2375da8a9cb jdk8-b103
96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104 96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104
5166118c59178b5d31001bc4058e92486ee07d9b jdk8-b105

View File

@ -69,11 +69,11 @@ else
# Run the makefile with an arbitraty SPEC using -p -q (quiet dry-run and dump rules) to find # Run the makefile with an arbitraty SPEC using -p -q (quiet dry-run and dump rules) to find
# available PHONY targets. Use this list as valid targets to pass on to the repeated calls. # available PHONY targets. Use this list as valid targets to pass on to the repeated calls.
all_phony_targets=$(filter-out $(global_targets) bundles-only, $(strip $(shell \ all_phony_targets=$(filter-out $(global_targets) bundles-only, $(strip $(shell \
$(MAKE) -p -q -f common/makefiles/Main.gmk SPEC=$(firstword $(SPEC)) | \ $(MAKE) -p -q -f common/makefiles/Main.gmk FRC SPEC=$(firstword $(SPEC)) | \
grep ^.PHONY: | head -n 1 | cut -d " " -f 2-))) grep ^.PHONY: | head -n 1 | cut -d " " -f 2-)))
$(all_phony_targets): $(all_phony_targets):
$(foreach spec,$(SPEC),($(MAKE) -f NewMakefile.gmk SPEC=$(spec) \ @$(foreach spec,$(SPEC),($(MAKE) -f NewMakefile.gmk SPEC=$(spec) \
$(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $@) &&) true $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $@) &&) true
.PHONY: $(all_phony_targets) .PHONY: $(all_phony_targets)
@ -98,6 +98,7 @@ help:
$(info . # corba and jdk) $(info . # corba and jdk)
$(info . make all # Compile everything, all repos and images) $(info . make all # Compile everything, all repos and images)
$(info . make images # Create complete j2sdk and j2re images) $(info . make images # Create complete j2sdk and j2re images)
$(info . make docs # Create javadocs)
$(info . make overlay-images # Create limited images for sparc 64 bit platforms) $(info . make overlay-images # Create limited images for sparc 64 bit platforms)
$(info . make profiles # Create complete j2re compact profile images) $(info . make profiles # Create complete j2re compact profile images)
$(info . make bootcycle-images # Build images twice, second time with newly build JDK) $(info . make bootcycle-images # Build images twice, second time with newly build JDK)
@ -109,7 +110,7 @@ help:
$(info . make test # Run tests, default is all tests (see TEST below)) $(info . make test # Run tests, default is all tests (see TEST below))
$(info ) $(info )
$(info Targets for specific components) $(info Targets for specific components)
$(info (Component is any of langtools, corba, jaxp, jaxws, hotspot, jdk, images or overlay-images)) $(info (Component is any of langtools, corba, jaxp, jaxws, hotspot, jdk, nashorn, images, overlay-images, docs or test))
$(info . make <component> # Build <component> and everything it depends on. ) $(info . make <component> # Build <component> and everything it depends on. )
$(info . make <component>-only # Build <component> only, without dependencies. This) $(info . make <component>-only # Build <component> only, without dependencies. This)
$(info . # is faster but can result in incorrect build results!) $(info . # is faster but can result in incorrect build results!)

View File

@ -1210,19 +1210,18 @@
<blockquote> <blockquote>
<p> <p>
<b>Q:</b> The <code>configure</code> file looks horrible! <b>Q:</b> The <code>generated-configure.sh</code> file looks horrible!
How are you going to edit it? How are you going to edit it?
<br> <br>
<b>A:</b> The <code>configure</code> file is generated (think <b>A:</b> The <code>generated-configure.sh</code> file is generated (think
"compiled") by the autoconf tools. The source code is "compiled") by the autoconf tools. The source code is
in <code>configure.ac</code> various .m4 files in common/autoconf, in <code>configure.ac</code> and various .m4 files in common/autoconf,
which are which are much more readable.
much more readable.
</p> </p>
<p> <p>
<b>Q:</b> <b>Q:</b>
Why is the <code>configure</code> file checked in, Why is the <code>generated-configure.sh</code> file checked in,
if it is generated? if it is generated?
<br> <br>
<b>A:</b> <b>A:</b>
@ -1237,13 +1236,29 @@
<p> <p>
<b>Q:</b> <b>Q:</b>
Do you require a specific version of autoconf for regenerating Do you require a specific version of autoconf for regenerating
<code>configure</code>? <code>generated-configure.sh</code>?
<br> <br>
<b>A:</b> <b>A:</b>
Currently, no, but this will likely be the case when things have Yes, version 2.69 is required and should be easy
settled down a bit more. (The reason for this is to avoid enough to aquire on all supported operating
large spurious changes in <code>configure</code> systems. The reason for this is to avoid
in commits that made small changes to <code>configure.ac</code>). large spurious changes in <code>generated-configure.sh</code>.
</p>
<p>
<b>Q:</b>
How do you regenerate <code>generated-configure.sh</code>
after making changes to the input files?
<br>
<b>A:</b>
Regnerating <code>generated-configure.sh</code>
should always be done using the
script <code>common/autoconf/autogen.sh</code> to
ensure that the correct files get updated. This
script should also be run after mercurial tries to
merge <code>generated-configure.sh</code> as a
merge of the generated file is not guaranteed to
be correct.
</p> </p>
<p> <p>

View File

@ -44,10 +44,8 @@ fi
custom_hook=$custom_script_dir/custom-hook.m4 custom_hook=$custom_script_dir/custom-hook.m4
AUTOCONF="`which autoconf 2> /dev/null | grep -v '^no autoconf in'`" AUTOCONF="`which autoconf 2> /dev/null | grep -v '^no autoconf in'`"
AUTOCONF_267="`which autoconf-2.67 2> /dev/null | grep -v '^no autoconf-2.67 in'`"
echo "Autoconf found: ${AUTOCONF}" echo "Autoconf found: ${AUTOCONF}"
echo "Autoconf-2.67 found: ${AUTOCONF_267}"
if test "x${AUTOCONF}" = x; then if test "x${AUTOCONF}" = x; then
echo You need autoconf installed to be able to regenerate the configure script echo You need autoconf installed to be able to regenerate the configure script
@ -55,10 +53,6 @@ if test "x${AUTOCONF}" = x; then
exit 1 exit 1
fi fi
if test "x${AUTOCONF_267}" != x; then
AUTOCONF=${AUTOCONF_267};
fi
echo Generating generated-configure.sh with ${AUTOCONF} echo Generating generated-configure.sh with ${AUTOCONF}
cat $script_dir/configure.ac | sed -e "s|@DATE_WHEN_GENERATED@|$TIMESTAMP|" | ${AUTOCONF} -W all -I$script_dir - > $script_dir/generated-configure.sh cat $script_dir/configure.ac | sed -e "s|@DATE_WHEN_GENERATED@|$TIMESTAMP|" | ${AUTOCONF} -W all -I$script_dir - > $script_dir/generated-configure.sh
rm -rf autom4te.cache rm -rf autom4te.cache

View File

@ -30,7 +30,7 @@
############################################################################### ###############################################################################
AC_PREREQ([2.61]) AC_PREREQ([2.69])
AC_INIT(OpenJDK, jdk8, build-dev@openjdk.java.net,,http://openjdk.java.net) AC_INIT(OpenJDK, jdk8, build-dev@openjdk.java.net,,http://openjdk.java.net)
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,7 @@ apt_help() {
pulse) pulse)
PKGHANDLER_COMMAND="sudo apt-get install libpulse-dev" ;; PKGHANDLER_COMMAND="sudo apt-get install libpulse-dev" ;;
x11) x11)
PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev" ;; PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev" ;;
ccache) ccache)
PKGHANDLER_COMMAND="sudo apt-get install ccache" ;; PKGHANDLER_COMMAND="sudo apt-get install ccache" ;;
* ) * )
@ -102,11 +102,11 @@ yum_help() {
cups) cups)
PKGHANDLER_COMMAND="sudo yum install cups-devel" ;; PKGHANDLER_COMMAND="sudo yum install cups-devel" ;;
freetype2) freetype2)
PKGHANDLER_COMMAND="sudo yum install freetype2-devel" ;; PKGHANDLER_COMMAND="sudo yum install freetype-devel" ;;
pulse) pulse)
PKGHANDLER_COMMAND="sudo yum install pulseaudio-libs-devel" ;; PKGHANDLER_COMMAND="sudo yum install pulseaudio-libs-devel" ;;
x11) x11)
PKGHANDLER_COMMAND="sudo yum install libXtst-devel" ;; PKGHANDLER_COMMAND="sudo yum install libXtst-devel libXt-devel libXrender-devel" ;;
ccache) ccache)
PKGHANDLER_COMMAND="sudo yum install ccache" ;; PKGHANDLER_COMMAND="sudo yum install ccache" ;;
* ) * )

View File

@ -185,7 +185,7 @@ OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS" CFLAGS="$CFLAGS $X_CFLAGS"
# Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10 # Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10
AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h], AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h X11/Intrinsic.h],
[X11_A_OK=yes], [X11_A_OK=yes],
[X11_A_OK=no; break], [X11_A_OK=no; break],
[ # include <X11/Xlib.h> [ # include <X11/Xlib.h>
@ -197,7 +197,7 @@ AC_LANG_POP(C)
if test "x$X11_A_OK" = xno && test "x$X11_NOT_NEEDED" != xyes; then if test "x$X11_A_OK" = xno && test "x$X11_NOT_NEEDED" != xyes; then
HELP_MSG_MISSING_DEPENDENCY([x11]) HELP_MSG_MISSING_DEPENDENCY([x11])
AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h XTest.h). $HELP_MSG]) AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h XTest.h Intrinsic.h). $HELP_MSG])
fi fi
AC_SUBST(X_CFLAGS) AC_SUBST(X_CFLAGS)

View File

@ -183,7 +183,7 @@ bootcycle-images-only: start-make
test: images test-only test: images test-only
test-only: start-make test-only: start-make
@$(call TargetEnter) @$(call TargetEnter)
@($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= JT_HOME=$(JT_HOME) PRODUCT_HOME=$(JDK_IMAGE_DIR) JPRT_JAVA_HOME=$(JDK_IMAGE_DIR) ALT_OUTPUTDIR=$(OUTPUT_ROOT) CONCURRENCY=$(JOBS) $(TEST)) || true @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= JT_HOME=$(JT_HOME) PRODUCT_HOME=$(JDK_IMAGE_DIR) ALT_OUTPUTDIR=$(OUTPUT_ROOT) CONCURRENCY=$(JOBS) $(TEST)) || true
@$(call TargetExit) @$(call TargetExit)
# Stores the tips for each repository. This file is be used when constructing the jdk image and can be # Stores the tips for each repository. This file is be used when constructing the jdk image and can be
@ -242,7 +242,7 @@ clean-test:
.PHONY: langtools corba jaxp jaxws hotspot jdk nashorn images overlay-images install test docs .PHONY: langtools corba jaxp jaxws hotspot jdk nashorn images overlay-images install test docs
.PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only nashorn-only images-only overlay-images-only install-only test-only docs-only .PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only nashorn-only images-only overlay-images-only install-only test-only docs-only
.PHONY: all clean dist-clean bootcycle-images start-make .PHONY: default all clean dist-clean bootcycle-images start-make
.PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-docs clean-test clean-overlay-images clean-bootcycle-build .PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-docs clean-test clean-overlay-images clean-bootcycle-build
.PHONY: profiles profiles-only profiles-oscheck .PHONY: profiles profiles-only profiles-oscheck

View File

@ -371,3 +371,5 @@ c4697c1c448416108743b59118b4a2498b339d0c jdk8-b102
580430d131ccd475e2f2ad4006531b8c4813d102 hs25-b46 580430d131ccd475e2f2ad4006531b8c4813d102 hs25-b46
104743074675359cfbf7f4dcd9ab2a5974a16627 jdk8-b104 104743074675359cfbf7f4dcd9ab2a5974a16627 jdk8-b104
c1604d5885a6f2adc0bcea2fa142a8f6bafad2f0 hs25-b47 c1604d5885a6f2adc0bcea2fa142a8f6bafad2f0 hs25-b47
acac3bde66b2c22791c257a8d99611d6d08c6713 jdk8-b105
18b4798adbc42c6fa16f5ecb7d5cd3ca130754bf hs25-b48

View File

@ -35,8 +35,9 @@ sapkg.c1 = sapkg.hotspot.c1;
sapkg.code = sapkg.hotspot.code; sapkg.code = sapkg.hotspot.code;
sapkg.compiler = sapkg.hotspot.compiler; sapkg.compiler = sapkg.hotspot.compiler;
// 'debugger' is a JavaScript keyword :-( // 'debugger' is a JavaScript keyword, but ES5 relaxes the
// sapkg.debugger = sapkg.hotspot.debugger; // restriction of using keywords as property name
sapkg.debugger = sapkg.hotspot.debugger;
sapkg.interpreter = sapkg.hotspot.interpreter; sapkg.interpreter = sapkg.hotspot.interpreter;
sapkg.jdi = sapkg.hotspot.jdi; sapkg.jdi = sapkg.hotspot.jdi;
@ -116,27 +117,36 @@ function main(globals, jvmarg) {
return args; return args;
} }
// Handle __has__ specially to avoid metacircularity problems
// when called from __get__.
// Calling
// this.__has__(name)
// will in turn call
// this.__call__('__has__', name)
// which is not handled below
function __has__(name) {
if (typeof(name) == 'number') {
return so["has(int)"](name);
} else {
if (name == '__wrapped__') {
return true;
} else if (so["has(java.lang.String)"](name)) {
return true;
} else if (name.equals('toString')) {
return true;
} else {
return false;
}
}
}
if (so instanceof sapkg.utilities.soql.ScriptObject) { if (so instanceof sapkg.utilities.soql.ScriptObject) {
return new JSAdapter() { return new JSAdapter() {
__getIds__: function() { __getIds__: function() {
return so.getIds(); return so.getIds();
}, },
__has__ : function(name) { __has__ : __has__,
if (typeof(name) == 'number') {
return so["has(int)"](name);
} else {
if (name == '__wrapped__') {
return true;
} else if (so["has(java.lang.String)"](name)) {
return true;
} else if (name.equals('toString')) {
return true;
} else {
return false;
}
}
},
__delete__ : function(name) { __delete__ : function(name) {
if (typeof(name) == 'number') { if (typeof(name) == 'number') {
@ -147,7 +157,8 @@ function main(globals, jvmarg) {
}, },
__get__ : function(name) { __get__ : function(name) {
if (! this.__has__(name)) { // don't call this.__has__(name); see comments above function __has__
if (! __has__.call(this, name)) {
return undefined; return undefined;
} }
if (typeof(name) == 'number') { if (typeof(name) == 'number') {
@ -162,7 +173,7 @@ function main(globals, jvmarg) {
var args = prepareArgsArray(arguments); var args = prepareArgsArray(arguments);
var r; var r;
try { try {
r = value.call(args); r = value.call(Java.to(args, 'java.lang.Object[]'));
} catch (e) { } catch (e) {
println("call to " + name + " failed!"); println("call to " + name + " failed!");
throw e; throw e;
@ -204,6 +215,18 @@ function main(globals, jvmarg) {
} }
// define "writeln" and "write" if not defined // define "writeln" and "write" if not defined
if (typeof(println) == 'undefined') {
println = function (str) {
java.lang.System.out.println(String(str));
}
}
if (typeof(print) == 'undefined') {
print = function (str) {
java.lang.System.out.print(String(str));
}
}
if (typeof(writeln) == 'undefined') { if (typeof(writeln) == 'undefined') {
writeln = println; writeln = println;
} }
@ -235,7 +258,7 @@ function main(globals, jvmarg) {
this.jclasses = function() { this.jclasses = function() {
forEachKlass(function (clazz) { forEachKlass(function (clazz) {
writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
}); });
} }
registerCommand("classes", "classes", "jclasses"); registerCommand("classes", "classes", "jclasses");
@ -490,14 +513,14 @@ function systemLoader() {
function forEachKlass(callback) { function forEachKlass(callback) {
var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor; var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor;
var visitor = new VisitorClass() { visit: callback }; var visitor = new VisitorClass() { visit: callback };
sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassVisitor)"](visitor); sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassVisitor)"](visitor);
} }
// iterate system dictionary for each 'Klass' and initiating loader // iterate system dictionary for each 'Klass' and initiating loader
function forEachKlassAndLoader(callback) { function forEachKlassAndLoader(callback) {
var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor; var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
var visitor = new VisitorClass() { visit: callback }; var visitor = new VisitorClass() { visit: callback };
sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassAndLoaderVisitor)"](visitor); sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassAndLoaderVisitor)"](visitor);
} }
// iterate system dictionary for each primitive array klass // iterate system dictionary for each primitive array klass
@ -522,7 +545,12 @@ function obj2oop(obj) {
// iterates Java heap for each Oop // iterates Java heap for each Oop
function forEachOop(callback) { function forEachOop(callback) {
sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { doObj: callback }); function empty() { }
sa.objHeap.iterate(new sapkg.oops.HeapVisitor() {
prologue: empty,
doObj: callback,
epilogue: empty
});
} }
// iterates Java heap for each Oop of given 'klass'. // iterates Java heap for each Oop of given 'klass'.
@ -536,8 +564,14 @@ function forEachOopOfKlass(callback, klass, includeSubtypes) {
if (includeSubtypes == undefined) { if (includeSubtypes == undefined) {
includeSubtypes = true; includeSubtypes = true;
} }
function empty() { }
sa.objHeap.iterateObjectsOfKlass( sa.objHeap.iterateObjectsOfKlass(
new sapkg.oops.HeapVisitor() { doObj: callback }, new sapkg.oops.HeapVisitor() {
prologue: empty,
doObj: callback,
epilogue: empty
},
klass, includeSubtypes); klass, includeSubtypes);
} }
@ -746,9 +780,9 @@ while (tmp.itr.hasNext()) {
// ignore; // ignore;
continue; continue;
} else { } else {
// some type names have ':'. replace to make it as a // some type names have ':', '<', '>', '*', ' '. replace to make it as a
// JavaScript identifier // JavaScript identifier
tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_'); tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_');
eval("function read" + tmp.name + "(addr) {" + eval("function read" + tmp.name + "(addr) {" +
" return readVMType('" + tmp.name + "', addr);}"); " return readVMType('" + tmp.name + "', addr);}");
eval("function print" + tmp.name + "(addr) {" + eval("function print" + tmp.name + "(addr) {" +

View File

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
HS_MAJOR_VER=25 HS_MAJOR_VER=25
HS_MINOR_VER=0 HS_MINOR_VER=0
HS_BUILD_NUMBER=47 HS_BUILD_NUMBER=48
JDK_MAJOR_VER=1 JDK_MAJOR_VER=1
JDK_MINOR_VER=8 JDK_MINOR_VER=8

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2003, 2010, 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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -31,9 +31,4 @@ CFLAGS += -DVM_LITTLE_ENDIAN
CFLAGS += -D_LP64=1 CFLAGS += -D_LP64=1
# The serviceability agent relies on frame pointer (%rbp) to walk thread stack
ifndef USE_SUNCC
CFLAGS += -fno-omit-frame-pointer
endif
OPT_CFLAGS/compactingPermGenGen.o = -O1 OPT_CFLAGS/compactingPermGenGen.o = -O1

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 1999, 2012, 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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -398,3 +398,10 @@ endif
ifdef MINIMIZE_RAM_USAGE ifdef MINIMIZE_RAM_USAGE
CFLAGS += -DMINIMIZE_RAM_USAGE CFLAGS += -DMINIMIZE_RAM_USAGE
endif endif
# Stack walking in the JVM relies on frame pointer (%rbp) to walk thread stack.
# Explicitly specify -fno-omit-frame-pointer because it is off by default
# starting with gcc 4.6.
ifndef USE_SUNCC
CFLAGS += -fno-omit-frame-pointer
endif

View File

@ -42,8 +42,6 @@ else
MKS_HOME=`dirname "$SH"` MKS_HOME=`dirname "$SH"`
fi fi
echo "EXPORTS" > vm1.def
AWK="$MKS_HOME/awk.exe" AWK="$MKS_HOME/awk.exe"
if [ ! -e $AWK ]; then if [ ! -e $AWK ]; then
AWK="$MKS_HOME/gawk.exe" AWK="$MKS_HOME/gawk.exe"
@ -55,6 +53,22 @@ CAT="$MKS_HOME/cat.exe"
RM="$MKS_HOME/rm.exe" RM="$MKS_HOME/rm.exe"
DUMPBIN="link.exe /dump" DUMPBIN="link.exe /dump"
if [ "$1" = "-nosa" ]; then
echo EXPORTS > vm.def
echo ""
echo "***"
echo "*** Not building SA: BUILD_WIN_SA != 1"
echo "*** C++ Vtables NOT included in vm.def"
echo "*** This jvm.dll will NOT work properly with SA."
echo "***"
echo "*** When in doubt, set BUILD_WIN_SA=1, clean and rebuild."
echo "***"
echo ""
exit
fi
echo "EXPORTS" > vm1.def
# When called from IDE the first param should contain the link version, otherwise may be nill # When called from IDE the first param should contain the link version, otherwise may be nill
if [ "x$1" != "x" ]; then if [ "x$1" != "x" ]; then
LD_VER="$1" LD_VER="$1"

View File

@ -49,9 +49,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-debug
# Force resources to be rebuilt every time # Force resources to be rebuilt every time
$(Res_Files): FORCE $(Res_Files): FORCE
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh
$(AOUT): $(Res_Files) $(Obj_Files) vm.def $(AOUT): $(Res_Files) $(Obj_Files) vm.def
$(LD) @<< $(LD) @<<
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)

View File

@ -48,9 +48,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-fastdebug
# Force resources to be rebuilt every time # Force resources to be rebuilt every time
$(Res_Files): FORCE $(Res_Files): FORCE
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh
$(AOUT): $(Res_Files) $(Obj_Files) vm.def $(AOUT): $(Res_Files) $(Obj_Files) vm.def
$(LD) @<< $(LD) @<<
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)

View File

@ -51,9 +51,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)
# Force resources to be rebuilt every time # Force resources to be rebuilt every time
$(Res_Files): FORCE $(Res_Files): FORCE
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh
$(AOUT): $(Res_Files) $(Obj_Files) vm.def $(AOUT): $(Res_Files) $(Obj_Files) vm.def
$(LD) @<< $(LD) @<<
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)

View File

@ -92,6 +92,10 @@ ProjectCreatorIDEOptions = \
-disablePch getThread_windows_$(Platform_arch).cpp \ -disablePch getThread_windows_$(Platform_arch).cpp \
-disablePch_compiler2 opcodes.cpp -disablePch_compiler2 opcodes.cpp
!if "$(BUILD_WIN_SA)" != "1"
BUILD_VM_DEF_FLAG=-nosa
!endif
# Common options for the IDE builds for c1, and c2 # Common options for the IDE builds for c1, and c2
ProjectCreatorIDEOptions=\ ProjectCreatorIDEOptions=\
$(ProjectCreatorIDEOptions) \ $(ProjectCreatorIDEOptions) \
@ -104,7 +108,7 @@ ProjectCreatorIDEOptions=\
-jdkTargetRoot $(HOTSPOTJDKDIST) \ -jdkTargetRoot $(HOTSPOTJDKDIST) \
-define ALIGN_STACK_FRAMES \ -define ALIGN_STACK_FRAMES \
-define VM_LITTLE_ENDIAN \ -define VM_LITTLE_ENDIAN \
-prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LD_VER)" \ -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(BUILD_VM_DEF_FLAG) $(LD_VER)" \
-ignoreFile jsig.c \ -ignoreFile jsig.c \
-ignoreFile jvmtiEnvRecommended.cpp \ -ignoreFile jvmtiEnvRecommended.cpp \
-ignoreFile jvmtiEnvStub.cpp \ -ignoreFile jvmtiEnvStub.cpp \

View File

@ -393,3 +393,11 @@ default::
_build_pch_file.obj: _build_pch_file.obj:
@echo #include "precompiled.hpp" > ../generated/_build_pch_file.cpp @echo #include "precompiled.hpp" > ../generated/_build_pch_file.cpp
$(CXX) $(CXX_FLAGS) /Fp"vm.pch" /Yc"precompiled.hpp" /c ../generated/_build_pch_file.cpp $(CXX) $(CXX_FLAGS) /Fp"vm.pch" /Yc"precompiled.hpp" /c ../generated/_build_pch_file.cpp
!if "$(BUILD_WIN_SA)" != "1"
BUILD_VM_DEF_FLAG=-nosa
!endif
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh $(BUILD_VM_DEF_FLAG)

View File

@ -642,13 +642,14 @@ objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NU
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
static uint64_t locate_unique_thread_id() { static uint64_t locate_unique_thread_id(mach_port_t mach_thread_port) {
// Additional thread_id used to correlate threads in SA // Additional thread_id used to correlate threads in SA
thread_identifier_info_data_t m_ident_info; thread_identifier_info_data_t m_ident_info;
mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO, thread_info(mach_thread_port, THREAD_IDENTIFIER_INFO,
(thread_info_t) &m_ident_info, &count); (thread_info_t) &m_ident_info, &count);
return m_ident_info.thread_id; return m_ident_info.thread_id;
} }
#endif #endif
@ -679,9 +680,14 @@ static void *java_start(Thread *thread) {
} }
#ifdef __APPLE__ #ifdef __APPLE__
// thread_id is mach thread on macos // thread_id is mach thread on macos, which pthreads graciously caches and provides for us
osthread->set_thread_id(::mach_thread_self()); mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self());
osthread->set_unique_thread_id(locate_unique_thread_id()); guarantee(thread_id != 0, "thread id missing from pthreads");
osthread->set_thread_id(thread_id);
uint64_t unique_thread_id = locate_unique_thread_id(thread_id);
guarantee(unique_thread_id != 0, "unique thread id was not found");
osthread->set_unique_thread_id(unique_thread_id);
#else #else
// thread_id is pthread_id on BSD // thread_id is pthread_id on BSD
osthread->set_thread_id(::pthread_self()); osthread->set_thread_id(::pthread_self());
@ -843,8 +849,14 @@ bool os::create_attached_thread(JavaThread* thread) {
// Store pthread info into the OSThread // Store pthread info into the OSThread
#ifdef __APPLE__ #ifdef __APPLE__
osthread->set_thread_id(::mach_thread_self()); // thread_id is mach thread on macos, which pthreads graciously caches and provides for us
osthread->set_unique_thread_id(locate_unique_thread_id()); mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self());
guarantee(thread_id != 0, "just checking");
osthread->set_thread_id(thread_id);
uint64_t unique_thread_id = locate_unique_thread_id(thread_id);
guarantee(unique_thread_id != 0, "just checking");
osthread->set_unique_thread_id(unique_thread_id);
#else #else
osthread->set_thread_id(::pthread_self()); osthread->set_thread_id(::pthread_self());
#endif #endif
@ -1115,7 +1127,7 @@ size_t os::lasterror(char *buf, size_t len) {
intx os::current_thread_id() { intx os::current_thread_id() {
#ifdef __APPLE__ #ifdef __APPLE__
return (intx)::mach_thread_self(); return (intx)::pthread_mach_thread_np(::pthread_self());
#else #else
return (intx)::pthread_self(); return (intx)::pthread_self();
#endif #endif
@ -2313,7 +2325,9 @@ void os::large_page_init() {
} }
char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
fatal("This code is not used or maintained.");
// "exec" is passed in but not used. Creating the shared image for // "exec" is passed in but not used. Creating the shared image for
// the code cache doesn't have an SHM_X executable permission to check. // the code cache doesn't have an SHM_X executable permission to check.
assert(UseLargePages && UseSHM, "only for SHM large pages"); assert(UseLargePages && UseSHM, "only for SHM large pages");
@ -3275,11 +3289,15 @@ void os::Bsd::install_signal_handlers() {
// and if UserSignalHandler is installed all bets are off // and if UserSignalHandler is installed all bets are off
if (CheckJNICalls) { if (CheckJNICalls) {
if (libjsig_is_loaded) { if (libjsig_is_loaded) {
tty->print_cr("Info: libjsig is activated, all active signal checking is disabled"); if (PrintJNIResolving) {
tty->print_cr("Info: libjsig is activated, all active signal checking is disabled");
}
check_signals = false; check_signals = false;
} }
if (AllowUserSignalHandlers) { if (AllowUserSignalHandlers) {
tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); if (PrintJNIResolving) {
tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
}
check_signals = false; check_signals = false;
} }
} }
@ -4736,3 +4754,8 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
return n; return n;
} }
#ifndef PRODUCT
void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif

View File

@ -40,6 +40,9 @@
product(bool, UseHugeTLBFS, false, \ product(bool, UseHugeTLBFS, false, \
"Use MAP_HUGETLB for large pages") \ "Use MAP_HUGETLB for large pages") \
\ \
product(bool, UseTransparentHugePages, false, \
"Use MADV_HUGEPAGE for large pages") \
\
product(bool, LoadExecStackDllInVMThread, true, \ product(bool, LoadExecStackDllInVMThread, true, \
"Load DLLs with executable-stack attribute in the VM Thread") \ "Load DLLs with executable-stack attribute in the VM Thread") \
\ \

View File

@ -2720,36 +2720,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec,
int os::Linux::commit_memory_impl(char* addr, size_t size, int os::Linux::commit_memory_impl(char* addr, size_t size,
size_t alignment_hint, bool exec) { size_t alignment_hint, bool exec) {
int err; int err = os::Linux::commit_memory_impl(addr, size, exec);
if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
uintptr_t res =
(uintptr_t) ::mmap(addr, size, prot,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB,
-1, 0);
if (res != (uintptr_t) MAP_FAILED) {
if (UseNUMAInterleaving) {
numa_make_global(addr, size);
}
return 0;
}
err = errno; // save errno from mmap() call above
if (!recoverable_mmap_error(err)) {
// However, it is not clear that this loss of our reserved mapping
// happens with large pages on Linux or that we cannot recover
// from the loss. For now, we just issue a warning and we don't
// call vm_exit_out_of_memory(). This issue is being tracked by
// JBS-8007074.
warn_fail_commit_memory(addr, size, alignment_hint, exec, err);
// vm_exit_out_of_memory(size, OOM_MMAP_ERROR,
// "committing reserved memory.");
}
// Fall through and try to use small pages
}
err = os::Linux::commit_memory_impl(addr, size, exec);
if (err == 0) { if (err == 0) {
realign_memory(addr, size, alignment_hint); realign_memory(addr, size, alignment_hint);
} }
@ -2774,7 +2745,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size,
} }
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { if (UseTransparentHugePages && alignment_hint > (size_t)vm_page_size()) {
// We don't check the return value: madvise(MADV_HUGEPAGE) may not // We don't check the return value: madvise(MADV_HUGEPAGE) may not
// be supported or the memory may already be backed by huge pages. // be supported or the memory may already be backed by huge pages.
::madvise(addr, bytes, MADV_HUGEPAGE); ::madvise(addr, bytes, MADV_HUGEPAGE);
@ -2787,7 +2758,7 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) {
// uncommitted at all. We don't do anything in this case to avoid creating a segment with // uncommitted at all. We don't do anything in this case to avoid creating a segment with
// small pages on top of the SHM segment. This method always works for small pages, so we // small pages on top of the SHM segment. This method always works for small pages, so we
// allow that in any case. // allow that in any case.
if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) { if (alignment_hint <= (size_t)os::vm_page_size() || can_commit_large_page_memory()) {
commit_memory(addr, bytes, alignment_hint, !ExecMem); commit_memory(addr, bytes, alignment_hint, !ExecMem);
} }
} }
@ -3157,11 +3128,31 @@ bool os::unguard_memory(char* addr, size_t size) {
return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); return linux_mprotect(addr, size, PROT_READ|PROT_WRITE);
} }
bool os::Linux::transparent_huge_pages_sanity_check(bool warn, size_t page_size) {
bool result = false;
void *p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE,
-1, 0);
if (p != MAP_FAILED) {
void *aligned_p = align_ptr_up(p, page_size);
result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0;
munmap(p, page_size * 2);
}
if (warn && !result) {
warning("TransparentHugePages is not supported by the operating system.");
}
return result;
}
bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
bool result = false; bool result = false;
void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE, void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
-1, 0); -1, 0);
if (p != MAP_FAILED) { if (p != MAP_FAILED) {
// We don't know if this really is a huge page or not. // We don't know if this really is a huge page or not.
@ -3182,12 +3173,10 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
} }
fclose(fp); fclose(fp);
} }
munmap (p, page_size); munmap(p, page_size);
if (result)
return true;
} }
if (warn) { if (warn && !result) {
warning("HugeTLBFS is not supported by the operating system."); warning("HugeTLBFS is not supported by the operating system.");
} }
@ -3235,82 +3224,114 @@ static void set_coredump_filter(void) {
static size_t _large_page_size = 0; static size_t _large_page_size = 0;
void os::large_page_init() { size_t os::Linux::find_large_page_size() {
if (!UseLargePages) { size_t large_page_size = 0;
UseHugeTLBFS = false;
UseSHM = false;
return;
}
if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) { // large_page_size on Linux is used to round up heap size. x86 uses either
// If UseLargePages is specified on the command line try both methods, // 2M or 4M page, depending on whether PAE (Physical Address Extensions)
// if it's default, then try only HugeTLBFS. // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
if (FLAG_IS_DEFAULT(UseLargePages)) { // page as large as 256M.
UseHugeTLBFS = true; //
} else { // Here we try to figure out page size by parsing /proc/meminfo and looking
UseHugeTLBFS = UseSHM = true; // for a line with the following format:
} // Hugepagesize: 2048 kB
} //
// If we can't determine the value (e.g. /proc is not mounted, or the text
if (LargePageSizeInBytes) { // format has been changed), we'll use the largest page size supported by
_large_page_size = LargePageSizeInBytes; // the processor.
} else {
// large_page_size on Linux is used to round up heap size. x86 uses either
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
// page as large as 256M.
//
// Here we try to figure out page size by parsing /proc/meminfo and looking
// for a line with the following format:
// Hugepagesize: 2048 kB
//
// If we can't determine the value (e.g. /proc is not mounted, or the text
// format has been changed), we'll use the largest page size supported by
// the processor.
#ifndef ZERO #ifndef ZERO
_large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
ARM_ONLY(2 * M) PPC_ONLY(4 * M); ARM_ONLY(2 * M) PPC_ONLY(4 * M);
#endif // ZERO #endif // ZERO
FILE *fp = fopen("/proc/meminfo", "r"); FILE *fp = fopen("/proc/meminfo", "r");
if (fp) { if (fp) {
while (!feof(fp)) { while (!feof(fp)) {
int x = 0; int x = 0;
char buf[16]; char buf[16];
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
_large_page_size = x * K; large_page_size = x * K;
break; break;
} }
} else { } else {
// skip to next line // skip to next line
for (;;) { for (;;) {
int ch = fgetc(fp); int ch = fgetc(fp);
if (ch == EOF || ch == (int)'\n') break; if (ch == EOF || ch == (int)'\n') break;
}
} }
} }
fclose(fp);
} }
fclose(fp);
} }
// print a warning if any large page related flag is specified on command line if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) {
bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is "
SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size),
proper_unit_for_byte_size(large_page_size));
}
return large_page_size;
}
size_t os::Linux::setup_large_page_size() {
_large_page_size = Linux::find_large_page_size();
const size_t default_page_size = (size_t)Linux::page_size(); const size_t default_page_size = (size_t)Linux::page_size();
if (_large_page_size > default_page_size) { if (_large_page_size > default_page_size) {
_page_sizes[0] = _large_page_size; _page_sizes[0] = _large_page_size;
_page_sizes[1] = default_page_size; _page_sizes[1] = default_page_size;
_page_sizes[2] = 0; _page_sizes[2] = 0;
} }
UseHugeTLBFS = UseHugeTLBFS &&
Linux::hugetlbfs_sanity_check(warn_on_failure, _large_page_size);
if (UseHugeTLBFS) return _large_page_size;
}
bool os::Linux::setup_large_page_type(size_t page_size) {
if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
FLAG_IS_DEFAULT(UseSHM) &&
FLAG_IS_DEFAULT(UseTransparentHugePages)) {
// If UseLargePages is specified on the command line try all methods,
// if it's default, then try only UseTransparentHugePages.
if (FLAG_IS_DEFAULT(UseLargePages)) {
UseTransparentHugePages = true;
} else {
UseHugeTLBFS = UseTransparentHugePages = UseSHM = true;
}
}
if (UseTransparentHugePages) {
bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages);
if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) {
UseHugeTLBFS = false;
UseSHM = false;
return true;
}
UseTransparentHugePages = false;
}
if (UseHugeTLBFS) {
bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
if (hugetlbfs_sanity_check(warn_on_failure, page_size)) {
UseSHM = false;
return true;
}
UseHugeTLBFS = false;
}
return UseSHM;
}
void os::large_page_init() {
if (!UseLargePages) {
UseHugeTLBFS = false;
UseTransparentHugePages = false;
UseSHM = false; UseSHM = false;
return;
}
UseLargePages = UseHugeTLBFS || UseSHM; size_t large_page_size = Linux::setup_large_page_size();
UseLargePages = Linux::setup_large_page_type(large_page_size);
set_coredump_filter(); set_coredump_filter();
} }
@ -3319,16 +3340,22 @@ void os::large_page_init() {
#define SHM_HUGETLB 04000 #define SHM_HUGETLB 04000
#endif #endif
char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec) {
// "exec" is passed in but not used. Creating the shared image for // "exec" is passed in but not used. Creating the shared image for
// the code cache doesn't have an SHM_X executable permission to check. // the code cache doesn't have an SHM_X executable permission to check.
assert(UseLargePages && UseSHM, "only for SHM large pages"); assert(UseLargePages && UseSHM, "only for SHM large pages");
assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address");
if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) {
return NULL; // Fallback to small pages.
}
key_t key = IPC_PRIVATE; key_t key = IPC_PRIVATE;
char *addr; char *addr;
bool warn_on_failure = UseLargePages && bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) || (!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(UseSHM) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes) !FLAG_IS_DEFAULT(LargePageSizeInBytes)
); );
char msg[128]; char msg[128];
@ -3376,42 +3403,219 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
return NULL; return NULL;
} }
if ((addr != NULL) && UseNUMAInterleaving) { return addr;
numa_make_global(addr, bytes); }
static void warn_on_large_pages_failure(char* req_addr, size_t bytes, int error) {
assert(error == ENOMEM, "Only expect to fail if no memory is available");
bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(UseHugeTLBFS) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes));
if (warn_on_failure) {
char msg[128];
jio_snprintf(msg, sizeof(msg), "Failed to reserve large pages memory req_addr: "
PTR_FORMAT " bytes: " SIZE_FORMAT " (errno = %d).", req_addr, bytes, error);
warning(msg);
}
}
char* os::Linux::reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec) {
assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
assert(is_size_aligned(bytes, os::large_page_size()), "Unaligned size");
assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address");
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
char* addr = (char*)::mmap(req_addr, bytes, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB,
-1, 0);
if (addr == MAP_FAILED) {
warn_on_large_pages_failure(req_addr, bytes, errno);
return NULL;
} }
// The memory is committed assert(is_ptr_aligned(addr, os::large_page_size()), "Must be");
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
return addr; return addr;
} }
char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec) {
size_t large_page_size = os::large_page_size();
assert(bytes >= large_page_size, "Shouldn't allocate large pages for small sizes");
// Allocate small pages.
char* start;
if (req_addr != NULL) {
assert(is_ptr_aligned(req_addr, alignment), "Must be");
assert(is_size_aligned(bytes, alignment), "Must be");
start = os::reserve_memory(bytes, req_addr);
assert(start == NULL || start == req_addr, "Must be");
} else {
start = os::reserve_memory_aligned(bytes, alignment);
}
if (start == NULL) {
return NULL;
}
assert(is_ptr_aligned(start, alignment), "Must be");
// os::reserve_memory_special will record this memory area.
// Need to release it here to prevent overlapping reservations.
MemTracker::record_virtual_memory_release((address)start, bytes);
char* end = start + bytes;
// Find the regions of the allocated chunk that can be promoted to large pages.
char* lp_start = (char*)align_ptr_up(start, large_page_size);
char* lp_end = (char*)align_ptr_down(end, large_page_size);
size_t lp_bytes = lp_end - lp_start;
assert(is_size_aligned(lp_bytes, large_page_size), "Must be");
if (lp_bytes == 0) {
// The mapped region doesn't even span the start and the end of a large page.
// Fall back to allocate a non-special area.
::munmap(start, end - start);
return NULL;
}
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
void* result;
if (start != lp_start) {
result = ::mmap(start, lp_start - start, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
-1, 0);
if (result == MAP_FAILED) {
::munmap(lp_start, end - lp_start);
return NULL;
}
}
result = ::mmap(lp_start, lp_bytes, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB,
-1, 0);
if (result == MAP_FAILED) {
warn_on_large_pages_failure(req_addr, bytes, errno);
// If the mmap above fails, the large pages region will be unmapped and we
// have regions before and after with small pages. Release these regions.
//
// | mapped | unmapped | mapped |
// ^ ^ ^ ^
// start lp_start lp_end end
//
::munmap(start, lp_start - start);
::munmap(lp_end, end - lp_end);
return NULL;
}
if (lp_end != end) {
result = ::mmap(lp_end, end - lp_end, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
-1, 0);
if (result == MAP_FAILED) {
::munmap(start, lp_end - start);
return NULL;
}
}
return start;
}
char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec) {
assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
assert(is_ptr_aligned(req_addr, alignment), "Must be");
assert(is_power_of_2(alignment), "Must be");
assert(is_power_of_2(os::large_page_size()), "Must be");
assert(bytes >= os::large_page_size(), "Shouldn't allocate large pages for small sizes");
if (is_size_aligned(bytes, os::large_page_size()) && alignment <= os::large_page_size()) {
return reserve_memory_special_huge_tlbfs_only(bytes, req_addr, exec);
} else {
return reserve_memory_special_huge_tlbfs_mixed(bytes, alignment, req_addr, exec);
}
}
char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
assert(UseLargePages, "only for large pages");
char* addr;
if (UseSHM) {
addr = os::Linux::reserve_memory_special_shm(bytes, alignment, req_addr, exec);
} else {
assert(UseHugeTLBFS, "must be");
addr = os::Linux::reserve_memory_special_huge_tlbfs(bytes, alignment, req_addr, exec);
}
if (addr != NULL) {
if (UseNUMAInterleaving) {
numa_make_global(addr, bytes);
}
// The memory is committed
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
}
return addr;
}
bool os::Linux::release_memory_special_shm(char* base, size_t bytes) {
// detaching the SHM segment will also delete it, see reserve_memory_special_shm()
return shmdt(base) == 0;
}
bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) {
return pd_release_memory(base, bytes);
}
bool os::release_memory_special(char* base, size_t bytes) { bool os::release_memory_special(char* base, size_t bytes) {
assert(UseLargePages, "only for large pages");
MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
// detaching the SHM segment will also delete it, see reserve_memory_special()
int rslt = shmdt(base); bool res;
if (rslt == 0) { if (UseSHM) {
res = os::Linux::release_memory_special_shm(base, bytes);
} else {
assert(UseHugeTLBFS, "must be");
res = os::Linux::release_memory_special_huge_tlbfs(base, bytes);
}
if (res) {
tkr.record((address)base, bytes); tkr.record((address)base, bytes);
return true;
} else { } else {
tkr.discard(); tkr.discard();
return false;
} }
return res;
} }
size_t os::large_page_size() { size_t os::large_page_size() {
return _large_page_size; return _large_page_size;
} }
// HugeTLBFS allows application to commit large page memory on demand; // With SysV SHM the entire memory region must be allocated as shared
// with SysV SHM the entire memory region must be allocated as shared
// memory. // memory.
// HugeTLBFS allows application to commit large page memory on demand.
// However, when committing memory with HugeTLBFS fails, the region
// that was supposed to be committed will lose the old reservation
// and allow other threads to steal that memory region. Because of this
// behavior we can't commit HugeTLBFS memory.
bool os::can_commit_large_page_memory() { bool os::can_commit_large_page_memory() {
return UseHugeTLBFS; return UseTransparentHugePages;
} }
bool os::can_execute_large_page_memory() { bool os::can_execute_large_page_memory() {
return UseHugeTLBFS; return UseTransparentHugePages || UseHugeTLBFS;
} }
// Reserve memory at an arbitrary address, only if that area is // Reserve memory at an arbitrary address, only if that area is
@ -4563,21 +4767,23 @@ jint os::init_2(void)
UseNUMA = false; UseNUMA = false;
} }
} }
// With SHM large pages we cannot uncommit a page, so there's not way // With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way
// we can make the adaptive lgrp chunk resizing work. If the user specified // we can make the adaptive lgrp chunk resizing work. If the user specified
// both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and // both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and
// disable adaptive resizing. // disable adaptive resizing.
if (UseNUMA && UseLargePages && UseSHM) { if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
if (!FLAG_IS_DEFAULT(UseNUMA)) { if (FLAG_IS_DEFAULT(UseNUMA)) {
if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) { UseNUMA = false;
} else {
if (FLAG_IS_DEFAULT(UseLargePages) &&
FLAG_IS_DEFAULT(UseSHM) &&
FLAG_IS_DEFAULT(UseHugeTLBFS)) {
UseLargePages = false; UseLargePages = false;
} else { } else {
warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing"); warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing");
UseAdaptiveSizePolicy = false; UseAdaptiveSizePolicy = false;
UseAdaptiveNUMAChunkSizing = false; UseAdaptiveNUMAChunkSizing = false;
} }
} else {
UseNUMA = false;
} }
} }
if (!UseNUMA && ForceNUMA) { if (!UseNUMA && ForceNUMA) {
@ -5848,3 +6054,149 @@ void MemNotifyThread::start() {
} }
#endif // JAVASE_EMBEDDED #endif // JAVASE_EMBEDDED
/////////////// Unit tests ///////////////
#ifndef PRODUCT
#define test_log(...) \
do {\
if (VerboseInternalVMTests) { \
tty->print_cr(__VA_ARGS__); \
tty->flush(); \
}\
} while (false)
class TestReserveMemorySpecial : AllStatic {
public:
static void small_page_write(void* addr, size_t size) {
size_t page_size = os::vm_page_size();
char* end = (char*)addr + size;
for (char* p = (char*)addr; p < end; p += page_size) {
*p = 1;
}
}
static void test_reserve_memory_special_huge_tlbfs_only(size_t size) {
if (!UseHugeTLBFS) {
return;
}
test_log("test_reserve_memory_special_huge_tlbfs_only(" SIZE_FORMAT ")", size);
char* addr = os::Linux::reserve_memory_special_huge_tlbfs_only(size, NULL, false);
if (addr != NULL) {
small_page_write(addr, size);
os::Linux::release_memory_special_huge_tlbfs(addr, size);
}
}
static void test_reserve_memory_special_huge_tlbfs_only() {
if (!UseHugeTLBFS) {
return;
}
size_t lp = os::large_page_size();
for (size_t size = lp; size <= lp * 10; size += lp) {
test_reserve_memory_special_huge_tlbfs_only(size);
}
}
static void test_reserve_memory_special_huge_tlbfs_mixed(size_t size, size_t alignment) {
if (!UseHugeTLBFS) {
return;
}
test_log("test_reserve_memory_special_huge_tlbfs_mixed(" SIZE_FORMAT ", " SIZE_FORMAT ")",
size, alignment);
assert(size >= os::large_page_size(), "Incorrect input to test");
char* addr = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false);
if (addr != NULL) {
small_page_write(addr, size);
os::Linux::release_memory_special_huge_tlbfs(addr, size);
}
}
static void test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(size_t size) {
size_t lp = os::large_page_size();
size_t ag = os::vm_allocation_granularity();
for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) {
test_reserve_memory_special_huge_tlbfs_mixed(size, alignment);
}
}
static void test_reserve_memory_special_huge_tlbfs_mixed() {
size_t lp = os::large_page_size();
size_t ag = os::vm_allocation_granularity();
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + ag);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + lp / 2);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + ag);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 - ag);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + lp / 2);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10 + lp / 2);
}
static void test_reserve_memory_special_huge_tlbfs() {
if (!UseHugeTLBFS) {
return;
}
test_reserve_memory_special_huge_tlbfs_only();
test_reserve_memory_special_huge_tlbfs_mixed();
}
static void test_reserve_memory_special_shm(size_t size, size_t alignment) {
if (!UseSHM) {
return;
}
test_log("test_reserve_memory_special_shm(" SIZE_FORMAT ", " SIZE_FORMAT ")", size, alignment);
char* addr = os::Linux::reserve_memory_special_shm(size, alignment, NULL, false);
if (addr != NULL) {
assert(is_ptr_aligned(addr, alignment), "Check");
assert(is_ptr_aligned(addr, os::large_page_size()), "Check");
small_page_write(addr, size);
os::Linux::release_memory_special_shm(addr, size);
}
}
static void test_reserve_memory_special_shm() {
size_t lp = os::large_page_size();
size_t ag = os::vm_allocation_granularity();
for (size_t size = ag; size < lp * 3; size += ag) {
for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) {
test_reserve_memory_special_shm(size, alignment);
}
}
}
static void test() {
test_reserve_memory_special_huge_tlbfs();
test_reserve_memory_special_shm();
}
};
void TestReserveMemorySpecial_test() {
TestReserveMemorySpecial::test();
}
#endif

View File

@ -32,6 +32,7 @@ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *);
class Linux { class Linux {
friend class os; friend class os;
friend class TestReserveMemorySpecial;
// For signal-chaining // For signal-chaining
#define MAXSIGNUM 32 #define MAXSIGNUM 32
@ -92,8 +93,21 @@ class Linux {
static void rebuild_cpu_to_node_map(); static void rebuild_cpu_to_node_map();
static GrowableArray<int>* cpu_to_node() { return _cpu_to_node; } static GrowableArray<int>* cpu_to_node() { return _cpu_to_node; }
static size_t find_large_page_size();
static size_t setup_large_page_size();
static bool setup_large_page_type(size_t page_size);
static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size);
static bool hugetlbfs_sanity_check(bool warn, size_t page_size); static bool hugetlbfs_sanity_check(bool warn, size_t page_size);
static char* reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec);
static char* reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec);
static char* reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec);
static char* reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec);
static bool release_memory_special_shm(char* base, size_t bytes);
static bool release_memory_special_huge_tlbfs(char* base, size_t bytes);
static void print_full_memory_info(outputStream* st); static void print_full_memory_info(outputStream* st);
static void print_distro_info(outputStream* st); static void print_distro_info(outputStream* st);
static void print_libversion_info(outputStream* st); static void print_libversion_info(outputStream* st);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2012, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -260,6 +260,55 @@ FILE* os::open(int fd, const char* mode) {
return ::fdopen(fd, mode); return ::fdopen(fd, mode);
} }
void* os::get_default_process_handle() {
return (void*)::dlopen(NULL, RTLD_LAZY);
}
// Builds a platform dependent Agent_OnLoad_<lib_name> function name
// which is used to find statically linked in agents.
// Parameters:
// sym_name: Symbol in library we are looking for
// lib_name: Name of library to look in, NULL for shared libs.
// is_absolute_path == true if lib_name is absolute path to agent
// such as "/a/b/libL.so"
// == false if only the base name of the library is passed in
// such as "L"
char* os::build_agent_function_name(const char *sym_name, const char *lib_name,
bool is_absolute_path) {
char *agent_entry_name;
size_t len;
size_t name_len;
size_t prefix_len = strlen(JNI_LIB_PREFIX);
size_t suffix_len = strlen(JNI_LIB_SUFFIX);
const char *start;
if (lib_name != NULL) {
len = name_len = strlen(lib_name);
if (is_absolute_path) {
// Need to strip path, prefix and suffix
if ((start = strrchr(lib_name, *os::file_separator())) != NULL) {
lib_name = ++start;
}
if (len <= (prefix_len + suffix_len)) {
return NULL;
}
lib_name += prefix_len;
name_len = strlen(lib_name) - suffix_len;
}
}
len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2;
agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread);
if (agent_entry_name == NULL) {
return NULL;
}
strcpy(agent_entry_name, sym_name);
if (lib_name != NULL) {
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
}
return agent_entry_name;
}
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
} }

View File

@ -3385,7 +3385,7 @@ bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
return true; return true;
} }
char* os::reserve_memory_special(size_t size, char* addr, bool exec) { char* os::reserve_memory_special(size_t size, size_t alignment, char* addr, bool exec) {
fatal("os::reserve_memory_special should not be called on Solaris."); fatal("os::reserve_memory_special should not be called on Solaris.");
return NULL; return NULL;
} }
@ -6601,3 +6601,9 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
return strlen(buffer); return strlen(buffer);
} }
#ifndef PRODUCT
void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif

View File

@ -3156,7 +3156,12 @@ bool os::can_execute_large_page_memory() {
return true; return true;
} }
char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { char* os::reserve_memory_special(size_t bytes, size_t alignment, char* addr, bool exec) {
assert(UseLargePages, "only for large pages");
if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) {
return NULL; // Fallback to small pages.
}
const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
@ -5394,6 +5399,75 @@ inline BOOL os::Advapi32Dll::AdvapiAvailable() {
return true; return true;
} }
void* os::get_default_process_handle() {
return (void*)GetModuleHandle(NULL);
}
// Builds a platform dependent Agent_OnLoad_<lib_name> function name
// which is used to find statically linked in agents.
// Additionally for windows, takes into account __stdcall names.
// Parameters:
// sym_name: Symbol in library we are looking for
// lib_name: Name of library to look in, NULL for shared libs.
// is_absolute_path == true if lib_name is absolute path to agent
// such as "C:/a/b/L.dll"
// == false if only the base name of the library is passed in
// such as "L"
char* os::build_agent_function_name(const char *sym_name, const char *lib_name,
bool is_absolute_path) {
char *agent_entry_name;
size_t len;
size_t name_len;
size_t prefix_len = strlen(JNI_LIB_PREFIX);
size_t suffix_len = strlen(JNI_LIB_SUFFIX);
const char *start;
if (lib_name != NULL) {
len = name_len = strlen(lib_name);
if (is_absolute_path) {
// Need to strip path, prefix and suffix
if ((start = strrchr(lib_name, *os::file_separator())) != NULL) {
lib_name = ++start;
} else {
// Need to check for C:
if ((start = strchr(lib_name, ':')) != NULL) {
lib_name = ++start;
}
}
if (len <= (prefix_len + suffix_len)) {
return NULL;
}
lib_name += prefix_len;
name_len = strlen(lib_name) - suffix_len;
}
}
len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2;
agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread);
if (agent_entry_name == NULL) {
return NULL;
}
if (lib_name != NULL) {
const char *p = strrchr(sym_name, '@');
if (p != NULL && p != sym_name) {
// sym_name == _Agent_OnLoad@XX
strncpy(agent_entry_name, sym_name, (p - sym_name));
agent_entry_name[(p-sym_name)] = '\0';
// agent_entry_name == _Agent_OnLoad
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
strcat(agent_entry_name, p);
// agent_entry_name == _Agent_OnLoad_lib_name@XX
} else {
strcpy(agent_entry_name, sym_name);
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
}
} else {
strcpy(agent_entry_name, sym_name);
}
return agent_entry_name;
}
#else #else
// Kernel32 API // Kernel32 API
typedef BOOL (WINAPI* SwitchToThread_Fn)(void); typedef BOOL (WINAPI* SwitchToThread_Fn)(void);
@ -5638,3 +5712,9 @@ BOOL os::Advapi32Dll::AdvapiAvailable() {
} }
#endif #endif
#ifndef PRODUCT
void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif

View File

@ -3460,7 +3460,9 @@ void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) {
void ConcurrentMarkSweepGeneration::shrink(size_t bytes) { void ConcurrentMarkSweepGeneration::shrink(size_t bytes) {
assert_locked_or_safepoint(Heap_lock); assert_locked_or_safepoint(Heap_lock);
size_t size = ReservedSpace::page_align_size_down(bytes); size_t size = ReservedSpace::page_align_size_down(bytes);
if (size > 0) { // Only shrink if a compaction was done so that all the free space
// in the generation is in a contiguous block at the end.
if (size > 0 && did_compact()) {
shrink_by(size); shrink_by(size);
} }
} }
@ -8696,9 +8698,10 @@ void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) {
assert(inFreeRange(), "Should only be called if currently in a free range."); assert(inFreeRange(), "Should only be called if currently in a free range.");
HeapWord* const eob = ((HeapWord*)fc) + chunk_size; HeapWord* const eob = ((HeapWord*)fc) + chunk_size;
assert(_sp->used_region().contains(eob - 1), assert(_sp->used_region().contains(eob - 1),
err_msg("eob = " PTR_FORMAT " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT
" out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")"
" when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")",
_limit, _sp->bottom(), _sp->end(), fc, chunk_size)); eob, eob-1, _limit, _sp->bottom(), _sp->end(), fc, chunk_size));
if (eob >= _limit) { if (eob >= _limit) {
assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit"); assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit");
if (CMSTraceSweeper) { if (CMSTraceSweeper) {

View File

@ -981,7 +981,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
if (should_try_gc) { if (should_try_gc) {
bool succeeded; bool succeeded;
result = do_collection_pause(word_size, gc_count_before, &succeeded); result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_inc_collection_pause);
if (result != NULL) { if (result != NULL) {
assert(succeeded, "only way to get back a non-NULL result"); assert(succeeded, "only way to get back a non-NULL result");
return result; return result;
@ -1106,7 +1107,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
// enough space for the allocation to succeed after the pause. // enough space for the allocation to succeed after the pause.
bool succeeded; bool succeeded;
result = do_collection_pause(word_size, gc_count_before, &succeeded); result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_humongous_allocation);
if (result != NULL) { if (result != NULL) {
assert(succeeded, "only way to get back a non-NULL result"); assert(succeeded, "only way to get back a non-NULL result");
return result; return result;
@ -2006,10 +2008,12 @@ jint G1CollectedHeap::initialize() {
size_t init_byte_size = collector_policy()->initial_heap_byte_size(); size_t init_byte_size = collector_policy()->initial_heap_byte_size();
size_t max_byte_size = collector_policy()->max_heap_byte_size(); size_t max_byte_size = collector_policy()->max_heap_byte_size();
size_t heap_alignment = collector_policy()->max_alignment();
// Ensure that the sizes are properly aligned. // Ensure that the sizes are properly aligned.
Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap");
Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap");
Universe::check_alignment(max_byte_size, heap_alignment, "g1 heap");
_cg1r = new ConcurrentG1Refine(this); _cg1r = new ConcurrentG1Refine(this);
@ -2026,12 +2030,8 @@ jint G1CollectedHeap::initialize() {
// If this happens then we could end up using a non-optimal // If this happens then we could end up using a non-optimal
// compressed oops mode. // compressed oops mode.
// Since max_byte_size is aligned to the size of a heap region (checked
// above).
Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap");
ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size, ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size,
HeapRegion::GrainBytes); heap_alignment);
// It is important to do this in a way such that concurrent readers can't // It is important to do this in a way such that concurrent readers can't
// temporarily think something is in the heap. (I've actually seen this // temporarily think something is in the heap. (I've actually seen this
@ -3700,14 +3700,15 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) {
HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
unsigned int gc_count_before, unsigned int gc_count_before,
bool* succeeded) { bool* succeeded,
GCCause::Cause gc_cause) {
assert_heap_not_locked_and_not_at_safepoint(); assert_heap_not_locked_and_not_at_safepoint();
g1_policy()->record_stop_world_start(); g1_policy()->record_stop_world_start();
VM_G1IncCollectionPause op(gc_count_before, VM_G1IncCollectionPause op(gc_count_before,
word_size, word_size,
false, /* should_initiate_conc_mark */ false, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms(), g1_policy()->max_pause_time_ms(),
GCCause::_g1_inc_collection_pause); gc_cause);
VMThread::execute(&op); VMThread::execute(&op);
HeapWord* result = op.result(); HeapWord* result = op.result();

View File

@ -776,9 +776,10 @@ protected:
// it has to be read while holding the Heap_lock. Currently, both // it has to be read while holding the Heap_lock. Currently, both
// methods that call do_collection_pause() release the Heap_lock // methods that call do_collection_pause() release the Heap_lock
// before the call, so it's easy to read gc_count_before just before. // before the call, so it's easy to read gc_count_before just before.
HeapWord* do_collection_pause(size_t word_size, HeapWord* do_collection_pause(size_t word_size,
unsigned int gc_count_before, unsigned int gc_count_before,
bool* succeeded); bool* succeeded,
GCCause::Cause gc_cause);
// The guts of the incremental collection pause, executed by the vm // The guts of the incremental collection pause, executed by the vm
// thread. It returns false if it is unable to do the collection due // thread. It returns false if it is unable to do the collection due

View File

@ -313,7 +313,8 @@ G1CollectorPolicy::G1CollectorPolicy() :
void G1CollectorPolicy::initialize_flags() { void G1CollectorPolicy::initialize_flags() {
set_min_alignment(HeapRegion::GrainBytes); set_min_alignment(HeapRegion::GrainBytes);
size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name()); size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name());
set_max_alignment(MAX2(card_table_alignment, min_alignment())); size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size();
set_max_alignment(MAX3(card_table_alignment, min_alignment(), page_size));
if (SurvivorRatio < 1) { if (SurvivorRatio < 1) {
vm_exit_during_initialization("Invalid survivor ratio specified"); vm_exit_during_initialization("Invalid survivor ratio specified");
} }

View File

@ -70,9 +70,6 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause(
guarantee(target_pause_time_ms > 0.0, guarantee(target_pause_time_ms > 0.0,
err_msg("target_pause_time_ms = %1.6lf should be positive", err_msg("target_pause_time_ms = %1.6lf should be positive",
target_pause_time_ms)); target_pause_time_ms));
guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause,
"we can only request an allocation if the GC cause is for "
"an incremental GC pause");
_gc_cause = gc_cause; _gc_cause = gc_cause;
} }

View File

@ -666,7 +666,7 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC {
NEW_RESOURCE_ARRAY_RETURN_NULL(type, 1) NEW_RESOURCE_ARRAY_RETURN_NULL(type, 1)
#define NEW_C_HEAP_ARRAY3(type, size, memflags, pc, allocfail)\ #define NEW_C_HEAP_ARRAY3(type, size, memflags, pc, allocfail)\
(type*) AllocateHeap(size * sizeof(type), memflags, pc, allocfail) (type*) AllocateHeap((size) * sizeof(type), memflags, pc, allocfail)
#define NEW_C_HEAP_ARRAY2(type, size, memflags, pc)\ #define NEW_C_HEAP_ARRAY2(type, size, memflags, pc)\
(type*) (AllocateHeap((size) * sizeof(type), memflags, pc)) (type*) (AllocateHeap((size) * sizeof(type), memflags, pc))
@ -675,16 +675,16 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC {
(type*) (AllocateHeap((size) * sizeof(type), memflags)) (type*) (AllocateHeap((size) * sizeof(type), memflags))
#define NEW_C_HEAP_ARRAY2_RETURN_NULL(type, size, memflags, pc)\ #define NEW_C_HEAP_ARRAY2_RETURN_NULL(type, size, memflags, pc)\
NEW_C_HEAP_ARRAY3(type, size, memflags, pc, AllocFailStrategy::RETURN_NULL) NEW_C_HEAP_ARRAY3(type, (size), memflags, pc, AllocFailStrategy::RETURN_NULL)
#define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, memflags)\ #define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, memflags)\
NEW_C_HEAP_ARRAY3(type, size, memflags, (address)0, AllocFailStrategy::RETURN_NULL) NEW_C_HEAP_ARRAY3(type, (size), memflags, (address)0, AllocFailStrategy::RETURN_NULL)
#define REALLOC_C_HEAP_ARRAY(type, old, size, memflags)\ #define REALLOC_C_HEAP_ARRAY(type, old, size, memflags)\
(type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags)) (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), memflags))
#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(type, old, size, memflags)\ #define REALLOC_C_HEAP_ARRAY_RETURN_NULL(type, old, size, memflags)\
(type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags, AllocFailStrategy::RETURN_NULL)) (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), memflags, AllocFailStrategy::RETURN_NULL))
#define FREE_C_HEAP_ARRAY(type, old, memflags) \ #define FREE_C_HEAP_ARRAY(type, old, memflags) \
FreeHeap((char*)(old), memflags) FreeHeap((char*)(old), memflags)

View File

@ -193,6 +193,8 @@ size_t GenCollectorPolicy::compute_max_alignment() {
alignment = lcm(os::large_page_size(), alignment); alignment = lcm(os::large_page_size(), alignment);
} }
assert(alignment >= min_alignment(), "Must be");
return alignment; return alignment;
} }

View File

@ -95,13 +95,13 @@ jint GenCollectedHeap::initialize() {
guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize"); guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize");
// The heap must be at least as aligned as generations. // The heap must be at least as aligned as generations.
size_t alignment = Generation::GenGrain; size_t gen_alignment = Generation::GenGrain;
_gen_specs = gen_policy()->generations(); _gen_specs = gen_policy()->generations();
// Make sure the sizes are all aligned. // Make sure the sizes are all aligned.
for (i = 0; i < _n_gens; i++) { for (i = 0; i < _n_gens; i++) {
_gen_specs[i]->align(alignment); _gen_specs[i]->align(gen_alignment);
} }
// Allocate space for the heap. // Allocate space for the heap.
@ -109,9 +109,11 @@ jint GenCollectedHeap::initialize() {
char* heap_address; char* heap_address;
size_t total_reserved = 0; size_t total_reserved = 0;
int n_covered_regions = 0; int n_covered_regions = 0;
ReservedSpace heap_rs(0); ReservedSpace heap_rs;
heap_address = allocate(alignment, &total_reserved, size_t heap_alignment = collector_policy()->max_alignment();
heap_address = allocate(heap_alignment, &total_reserved,
&n_covered_regions, &heap_rs); &n_covered_regions, &heap_rs);
if (!heap_rs.is_reserved()) { if (!heap_rs.is_reserved()) {
@ -168,6 +170,8 @@ char* GenCollectedHeap::allocate(size_t alignment,
const size_t pageSize = UseLargePages ? const size_t pageSize = UseLargePages ?
os::large_page_size() : os::vm_page_size(); os::large_page_size() : os::vm_page_size();
assert(alignment % pageSize == 0, "Must be");
for (int i = 0; i < _n_gens; i++) { for (int i = 0; i < _n_gens; i++) {
total_reserved += _gen_specs[i]->max_size(); total_reserved += _gen_specs[i]->max_size();
if (total_reserved < _gen_specs[i]->max_size()) { if (total_reserved < _gen_specs[i]->max_size()) {
@ -175,24 +179,17 @@ char* GenCollectedHeap::allocate(size_t alignment,
} }
n_covered_regions += _gen_specs[i]->n_covered_regions(); n_covered_regions += _gen_specs[i]->n_covered_regions();
} }
assert(total_reserved % pageSize == 0, assert(total_reserved % alignment == 0,
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize=" err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment="
SIZE_FORMAT, total_reserved, pageSize)); SIZE_FORMAT, total_reserved, alignment));
// Needed until the cardtable is fixed to have the right number // Needed until the cardtable is fixed to have the right number
// of covered regions. // of covered regions.
n_covered_regions += 2; n_covered_regions += 2;
if (UseLargePages) { *_total_reserved = total_reserved;
assert(total_reserved != 0, "total_reserved cannot be 0"); *_n_covered_regions = n_covered_regions;
total_reserved = round_to(total_reserved, os::large_page_size());
if (total_reserved < os::large_page_size()) {
vm_exit_during_initialization(overflow_msg);
}
}
*_total_reserved = total_reserved;
*_n_covered_regions = n_covered_regions;
*heap_rs = Universe::reserve_heap(total_reserved, alignment); *heap_rs = Universe::reserve_heap(total_reserved, alignment);
return heap_rs->base(); return heap_rs->base();
} }

View File

@ -345,7 +345,7 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
}; };
// byte_size is the size of the associated virtualspace. // byte_size is the size of the associated virtualspace.
VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) { VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(), _container_count(0) {
// align up to vm allocation granularity // align up to vm allocation granularity
byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); byte_size = align_size_up(byte_size, os::vm_allocation_granularity());

View File

@ -681,17 +681,23 @@ static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1);
// 32Gb // 32Gb
// OopEncodingHeapMax == NarrowOopHeapMax << LogMinObjAlignmentInBytes; // OopEncodingHeapMax == NarrowOopHeapMax << LogMinObjAlignmentInBytes;
char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {
assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");
assert(is_size_aligned((size_t)NarrowOopHeapMax, alignment), "Must be");
assert(is_size_aligned(heap_size, alignment), "Must be");
uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);
size_t base = 0; size_t base = 0;
#ifdef _LP64 #ifdef _LP64
if (UseCompressedOops) { if (UseCompressedOops) {
assert(mode == UnscaledNarrowOop || assert(mode == UnscaledNarrowOop ||
mode == ZeroBasedNarrowOop || mode == ZeroBasedNarrowOop ||
mode == HeapBasedNarrowOop, "mode is invalid"); mode == HeapBasedNarrowOop, "mode is invalid");
const size_t total_size = heap_size + HeapBaseMinAddress; const size_t total_size = heap_size + heap_base_min_address_aligned;
// Return specified base for the first request. // Return specified base for the first request.
if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
base = HeapBaseMinAddress; base = heap_base_min_address_aligned;
// If the total size is small enough to allow UnscaledNarrowOop then // If the total size is small enough to allow UnscaledNarrowOop then
// just use UnscaledNarrowOop. // just use UnscaledNarrowOop.
@ -742,6 +748,8 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
} }
} }
#endif #endif
assert(is_ptr_aligned((char*)base, alignment), "Must be");
return (char*)base; // also return NULL (don't care) for 32-bit VM return (char*)base; // also return NULL (don't care) for 32-bit VM
} }
@ -867,27 +875,33 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
size_t total_reserved = align_size_up(heap_size, alignment); size_t total_reserved = align_size_up(heap_size, alignment);
assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),
"heap size is too big for compressed oops"); "heap size is too big for compressed oops");
char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop);
ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size());
assert(!UseLargePages
|| UseParallelOldGC
|| use_large_pages, "Wrong alignment to use large pages");
char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop);
ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);
if (UseCompressedOops) { if (UseCompressedOops) {
if (addr != NULL && !total_rs.is_reserved()) { if (addr != NULL && !total_rs.is_reserved()) {
// Failed to reserve at specified address - the requested memory // Failed to reserve at specified address - the requested memory
// region is taken already, for example, by 'java' launcher. // region is taken already, for example, by 'java' launcher.
// Try again to reserver heap higher. // Try again to reserver heap higher.
addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);
ReservedHeapSpace total_rs0(total_reserved, alignment, ReservedHeapSpace total_rs0(total_reserved, alignment,
UseLargePages, addr); use_large_pages, addr);
if (addr != NULL && !total_rs0.is_reserved()) { if (addr != NULL && !total_rs0.is_reserved()) {
// Failed to reserve at specified address again - give up. // Failed to reserve at specified address again - give up.
addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop);
assert(addr == NULL, ""); assert(addr == NULL, "");
ReservedHeapSpace total_rs1(total_reserved, alignment, ReservedHeapSpace total_rs1(total_reserved, alignment,
UseLargePages, addr); use_large_pages, addr);
total_rs = total_rs1; total_rs = total_rs1;
} else { } else {
total_rs = total_rs0; total_rs = total_rs0;

View File

@ -346,7 +346,7 @@ class Universe: AllStatic {
}; };
static NARROW_OOP_MODE narrow_oop_mode(); static NARROW_OOP_MODE narrow_oop_mode();
static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode); static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode);
static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); static char* preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode);
static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode); static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode);
static address narrow_oop_base() { return _narrow_oop._base; } static address narrow_oop_base() { return _narrow_oop._base; }
static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); } static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); }

View File

@ -3234,19 +3234,22 @@ JNI_QUICK_ENTRY(const jchar*, jni_GetStringChars(
HOTSPOT_JNI_GETSTRINGCHARS_ENTRY( HOTSPOT_JNI_GETSTRINGCHARS_ENTRY(
env, string, (uintptr_t *) isCopy); env, string, (uintptr_t *) isCopy);
#endif /* USDT2 */ #endif /* USDT2 */
//%note jni_5
if (isCopy != NULL) {
*isCopy = JNI_TRUE;
}
oop s = JNIHandles::resolve_non_null(string); oop s = JNIHandles::resolve_non_null(string);
int s_len = java_lang_String::length(s); int s_len = java_lang_String::length(s);
typeArrayOop s_value = java_lang_String::value(s); typeArrayOop s_value = java_lang_String::value(s);
int s_offset = java_lang_String::offset(s); int s_offset = java_lang_String::offset(s);
jchar* buf = NEW_C_HEAP_ARRAY(jchar, s_len + 1, mtInternal); // add one for zero termination jchar* buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination
if (s_len > 0) { /* JNI Specification states return NULL on OOM */
memcpy(buf, s_value->char_at_addr(s_offset), sizeof(jchar)*s_len); if (buf != NULL) {
if (s_len > 0) {
memcpy(buf, s_value->char_at_addr(s_offset), sizeof(jchar)*s_len);
}
buf[s_len] = 0;
//%note jni_5
if (isCopy != NULL) {
*isCopy = JNI_TRUE;
}
} }
buf[s_len] = 0;
#ifndef USDT2 #ifndef USDT2
DTRACE_PROBE1(hotspot_jni, GetStringChars__return, buf); DTRACE_PROBE1(hotspot_jni, GetStringChars__return, buf);
#else /* USDT2 */ #else /* USDT2 */
@ -3335,9 +3338,14 @@ JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboole
#endif /* USDT2 */ #endif /* USDT2 */
oop java_string = JNIHandles::resolve_non_null(string); oop java_string = JNIHandles::resolve_non_null(string);
size_t length = java_lang_String::utf8_length(java_string); size_t length = java_lang_String::utf8_length(java_string);
char* result = AllocateHeap(length + 1, mtInternal); /* JNI Specification states return NULL on OOM */
java_lang_String::as_utf8_string(java_string, result, (int) length + 1); char* result = AllocateHeap(length + 1, mtInternal, 0, AllocFailStrategy::RETURN_NULL);
if (isCopy != NULL) *isCopy = JNI_TRUE; if (result != NULL) {
java_lang_String::as_utf8_string(java_string, result, (int) length + 1);
if (isCopy != NULL) {
*isCopy = JNI_TRUE;
}
}
#ifndef USDT2 #ifndef USDT2
DTRACE_PROBE1(hotspot_jni, GetStringUTFChars__return, result); DTRACE_PROBE1(hotspot_jni, GetStringUTFChars__return, result);
#else /* USDT2 */ #else /* USDT2 */
@ -3591,11 +3599,16 @@ JNI_QUICK_ENTRY(ElementType*, \
* Avoid asserts in typeArrayOop. */ \ * Avoid asserts in typeArrayOop. */ \
result = (ElementType*)get_bad_address(); \ result = (ElementType*)get_bad_address(); \
} else { \ } else { \
result = NEW_C_HEAP_ARRAY(ElementType, len, mtInternal); \ /* JNI Specification states return NULL on OOM */ \
/* copy the array to the c chunk */ \ result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len); \ if (result != NULL) { \
/* copy the array to the c chunk */ \
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len); \
if (isCopy) { \
*isCopy = JNI_TRUE; \
} \
} \
} \ } \
if (isCopy) *isCopy = JNI_TRUE; \
DTRACE_PROBE1(hotspot_jni, Get##Result##ArrayElements__return, result);\ DTRACE_PROBE1(hotspot_jni, Get##Result##ArrayElements__return, result);\
return result; \ return result; \
JNI_END JNI_END
@ -3628,11 +3641,16 @@ JNI_QUICK_ENTRY(ElementType*, \
* Avoid asserts in typeArrayOop. */ \ * Avoid asserts in typeArrayOop. */ \
result = (ElementType*)get_bad_address(); \ result = (ElementType*)get_bad_address(); \
} else { \ } else { \
result = NEW_C_HEAP_ARRAY(ElementType, len, mtInternal); \ /* JNI Specification states return NULL on OOM */ \
/* copy the array to the c chunk */ \ result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len); \ if (result != NULL) { \
/* copy the array to the c chunk */ \
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len); \
if (isCopy) { \
*isCopy = JNI_TRUE; \
} \
} \
} \ } \
if (isCopy) *isCopy = JNI_TRUE; \
ReturnProbe; \ ReturnProbe; \
return result; \ return result; \
JNI_END JNI_END
@ -5027,9 +5045,15 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) {
tty->print_cr("Running test: " #unit_test_function_call); \ tty->print_cr("Running test: " #unit_test_function_call); \
unit_test_function_call unit_test_function_call
// Forward declaration
void TestReservedSpace_test();
void TestReserveMemorySpecial_test();
void execute_internal_vm_tests() { void execute_internal_vm_tests() {
if (ExecuteInternalVMTests) { if (ExecuteInternalVMTests) {
tty->print_cr("Running internal VM tests"); tty->print_cr("Running internal VM tests");
run_unit_test(TestReservedSpace_test());
run_unit_test(TestReserveMemorySpecial_test());
run_unit_test(GlobalDefinitions::test_globals()); run_unit_test(GlobalDefinitions::test_globals());
run_unit_test(GCTimerAllTest::all()); run_unit_test(GCTimerAllTest::all());
run_unit_test(arrayOopDesc::test_max_array_length()); run_unit_test(arrayOopDesc::test_max_array_length());

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="jvmti.xsl"?> <?xml-stylesheet type="text/xsl" href="jvmti.xsl"?>
<!-- <!--
Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
@ -358,7 +358,7 @@
<specification label="JVM(TM) Tool Interface" <specification label="JVM(TM) Tool Interface"
majorversion="1" majorversion="1"
minorversion="2" minorversion="2"
microversion="2"> microversion="3">
<title subtitle="Version"> <title subtitle="Version">
<tm>JVM</tm> Tool Interface <tm>JVM</tm> Tool Interface
</title> </title>
@ -431,12 +431,46 @@
On the <tm>Solaris</tm> Operating Environment, an agent library is a shared On the <tm>Solaris</tm> Operating Environment, an agent library is a shared
object (<code>.so</code> file). object (<code>.so</code> file).
<p/> <p/>
An agent may be started at VM startup by specifying the agent library An agent may be started at VM startup by specifying the agent library
name using a <internallink id="starting">command line option</internallink>. name using a <internallink id="starting">command line option</internallink>.
Some implementations may support a mechanism to <internallink id="onattach"> Some implementations may support a mechanism to <internallink id="onattach">
start agents</internallink> in the live <functionlink id="GetPhase">phase</functionlink>. start agents</internallink> in the live <functionlink id="GetPhase">phase</functionlink>.
The details of how this is initiated are implementation specific. The details of how this is initiated are implementation specific.
</intro> </intro>
<intro id="entry point" label="Statically Linked Agents (since version 1.2.3)">
A native JVMTI Agent may be <i>statically linked</i> with the VM.
The manner in which the library and VM image are combined is
implementation-dependent.
An agent L whose image has been combined with the VM is defined as
<i>statically linked</i> if and only if the agent exports a function
called Agent_OnLoad_L.
<p/>
If a <i>statically linked</i> agent L exports a function called
Agent_OnLoad_L and a function called Agent_OnLoad, the Agent_OnLoad
function will be ignored.
If an agent L is <i>statically linked</i>, an Agent_OnLoad_L
function will be invoked with the same arguments and expected return
value as specified for the Agent_OnLoad function.
An agent L that is <i>statically linked</i> will prohibit an agent of
the same name from being loaded dynamically.
<p/>
The VM will invoke the Agent_OnUnload_L function of the agent, if such
a function is exported, at the same point during startup as it would
have called the dynamic entry point Agent_OnUnLoad.
If a <i>statically linked</i> agent L exports a function called
Agent_OnUnLoad_L and a function called Agent_OnUnLoad, the Agent_OnUnLoad
function will be ignored.
<p/>
If an agent L is <i>statically linked</i>, an Agent_OnAttach_L function
will be invoked with the same arguments and expected return value as
specified for the Agent_OnAttach function.
If a <i>statically linked</i> agent L exports a function called
Agent_OnAttach_L and a function called Agent_OnAttach, the Agent_OnAttach
function will be ignored.
</intro>
<intro id="starting" label="Agent Command Line Options"> <intro id="starting" label="Agent Command Line Options">
The term "command-line option" is used below to The term "command-line option" is used below to
@ -455,7 +489,7 @@
<dd> <dd>
The name following <code>-agentlib:</code> is the name of the The name following <code>-agentlib:</code> is the name of the
library to load. Lookup of the library, both its full name and location, library to load. Lookup of the library, both its full name and location,
proceeds in a platform-specific manner. proceeds in a platform-specific manner.
Typically, the <i>&lt;agent-lib-name&gt;</i> is expanded to an Typically, the <i>&lt;agent-lib-name&gt;</i> is expanded to an
operating system specific file name. operating system specific file name.
The <i>&lt;options&gt;</i> will be passed to the agent on start-up. The <i>&lt;options&gt;</i> will be passed to the agent on start-up.
@ -463,7 +497,11 @@
<code>-agentlib:foo=opt1,opt2</code> is specified, the VM will attempt to <code>-agentlib:foo=opt1,opt2</code> is specified, the VM will attempt to
load the shared library <code>foo.dll</code> from the system <code>PATH</code> load the shared library <code>foo.dll</code> from the system <code>PATH</code>
under <tm>Windows</tm> or <code>libfoo.so</code> from the under <tm>Windows</tm> or <code>libfoo.so</code> from the
<code>LD_LIBRARY_PATH</code> under the <tm>Solaris</tm> operating environment. <code>LD_LIBRARY_PATH</code> under the <tm>Solaris</tm> operating
environment.
If the agent library is statically linked into the executable
then no actual loading takes place.
<p/>
</dd> </dd>
<dt><code>-agentpath:</code><i>&lt;path-to-agent&gt;</i><code>=</code><i>&lt;options&gt;</i></dt> <dt><code>-agentpath:</code><i>&lt;path-to-agent&gt;</i><code>=</code><i>&lt;options&gt;</i></dt>
<dd> <dd>
@ -473,11 +511,20 @@
The <i>&lt;options&gt;</i> will be passed to the agent on start-up. The <i>&lt;options&gt;</i> will be passed to the agent on start-up.
For example, if the option For example, if the option
<code>-agentpath:c:\myLibs\foo.dll=opt1,opt2</code> is specified, the VM will attempt to <code>-agentpath:c:\myLibs\foo.dll=opt1,opt2</code> is specified, the VM will attempt to
load the shared library <code>c:\myLibs\foo.dll</code>. load the shared library <code>c:\myLibs\foo.dll</code>. If the agent
library is statically linked into the executable
then no actual loading takes place.
<p/>
</dd> </dd>
</dl> </dl>
The start-up routine <internallink id="onload"><code>Agent_OnLoad</code></internallink> For a dynamic shared library agent, the start-up routine
in the library will be invoked. <internallink id="onload"><code>Agent_OnLoad</code></internallink>
in the library will be invoked. If the agent library is statically linked
into the executable then the system will attempt to invoke the
<code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> entry point where
&lt;agent-lib-name&gt; is the basename of the
agent. In the above example <code>-agentpath:c:\myLibs\foo.dll=opt1,opt2</code>,
the system will attempt to find and call the <code>Agent_OnLoad_foo</code> start-up routine.
<p/> <p/>
Libraries loaded with <code>-agentlib:</code> or <code>-agentpath:</code> Libraries loaded with <code>-agentlib:</code> or <code>-agentpath:</code>
will be searched for JNI native method implementations to facilitate the will be searched for JNI native method implementations to facilitate the
@ -502,11 +549,13 @@
If the agent is started in the <code>OnLoad</code> If the agent is started in the <code>OnLoad</code>
<functionlink id="GetPhase">phase</functionlink> the function <functionlink id="GetPhase">phase</functionlink> the function
<internallink id="onload"><code>Agent_OnLoad</code></internallink> <internallink id="onload"><code>Agent_OnLoad</code></internallink>
will be invoked. or <internallink id="onload"><code>Agent_OnLoad_L</code></internallink>
for statically linked agents will be invoked.
If the agent is started in the live If the agent is started in the live
<functionlink id="GetPhase">phase</functionlink> the function <functionlink id="GetPhase">phase</functionlink> the function
<internallink id="onattach"><code>Agent_OnAttach</code></internallink> <internallink id="onattach"><code>Agent_OnAttach</code></internallink>
will be invoked. or <internallink id="onattach"><code>Agent_OnAttach_L</code></internallink>
for statically linked agents will be invoked.
Exactly one call to a start-up function is made per agent. Exactly one call to a start-up function is made per agent.
</intro> </intro>
@ -516,6 +565,11 @@
<example> <example>
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example> Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
Or for a statically linked agent named 'L':
<example>
JNIEXPORT jint JNICALL
Agent_OnLoad_L(JavaVM *vm, char *options, void *reserved)</example>
The VM will start the agent by calling this function. The VM will start the agent by calling this function.
It will be called early enough in VM initialization that: It will be called early enough in VM initialization that:
<ul> <ul>
@ -531,7 +585,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
<li>no objects have been created</li> <li>no objects have been created</li>
</ul> </ul>
<p/> <p/>
The VM will call the <code>Agent_OnLoad</code> function with The VM will call the <code>Agent_OnLoad</code> or
<code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> function with
<i>&lt;options&gt;</i> as the second argument - <i>&lt;options&gt;</i> as the second argument -
that is, using the command-line option examples, that is, using the command-line option examples,
<code>"opt1,opt2"</code> will be passed to the <code>char *options</code> <code>"opt1,opt2"</code> will be passed to the <code>char *options</code>
@ -540,7 +595,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
<internallink id="mUTF">modified UTF-8</internallink> string. <internallink id="mUTF">modified UTF-8</internallink> string.
If <i>=&lt;options&gt;</i> is not specified, If <i>=&lt;options&gt;</i> is not specified,
a zero length string is passed to <code>options</code>. a zero length string is passed to <code>options</code>.
The lifespan of the <code>options</code> string is the <code>Agent_OnLoad</code> The lifespan of the <code>options</code> string is the
<code>Agent_OnLoad</code> or <code>Agent_OnLoad_&lt;agent-lib-name&gt;</code>
call. If needed beyond this time the string or parts of the string must call. If needed beyond this time the string or parts of the string must
be copied. be copied.
The period between when <code>Agent_OnLoad</code> is called and when it The period between when <code>Agent_OnLoad</code> is called and when it
@ -570,7 +626,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
their functionality. their functionality.
</rationale> </rationale>
<p/> <p/>
The return value from <code>Agent_OnLoad</code> is used to indicate an error. The return value from <code>Agent_OnLoad</code> or
<code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> is used to indicate an error.
Any value other than zero indicates an error and causes termination of the VM. Any value other than zero indicates an error and causes termination of the VM.
</intro> </intro>
@ -587,6 +644,11 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
<example> <example>
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example> Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
Or for a statically linked agent named 'L':
<example>
JNIEXPORT jint JNICALL
Agent_OnAttach_L(JavaVM* vm, char *options, void *reserved)</example>
<p/> <p/>
The VM will start the agent by calling this function. The VM will start the agent by calling this function.
It will be called in the context of a thread It will be called in the context of a thread
@ -596,13 +658,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
</internallink> string. </internallink> string.
If startup options were not provided, a zero length string is passed to If startup options were not provided, a zero length string is passed to
<code>options</code>. The lifespan of the <code>options</code> string is the <code>options</code>. The lifespan of the <code>options</code> string is the
<code>Agent_OnAttach</code> call. If needed beyond this time the string or parts of <code>Agent_OnAttach</code> or <code>Agent_OnAttach_&lt;agent-lib-name&gt;</code> call.
the string must be copied. If needed beyond this time the string or parts of the string must be copied.
<p/> <p/>
Note that some <internallink id="capability">capabilities</internallink> Note that some <internallink id="capability">capabilities</internallink>
may not be available in the live phase. may not be available in the live phase.
<p/> <p/>
The <code>Agent_OnAttach</code> function initializes the agent and returns a value The <code>Agent_OnAttach</code> or <code>Agent_OnAttach_&lt;agent-lib-name
&gt;</code> function initializes the agent and returns a value
to the VM to indicate if an error occurred. Any value other than zero indicates an error. to the VM to indicate if an error occurred. Any value other than zero indicates an error.
An error does not cause the VM to terminate. Instead the VM ignores the error, or takes An error does not cause the VM to terminate. Instead the VM ignores the error, or takes
some implementation specific action -- for example it might print an error to standard error, some implementation specific action -- for example it might print an error to standard error,
@ -615,8 +678,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
<example> <example>
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm)</example> Agent_OnUnload(JavaVM *vm)</example>
Or for a statically linked agent named 'L':
<example>
JNIEXPORT void JNICALL
Agent_OnUnload_L(JavaVM *vm)</example>
This function will be called by the VM when the library is about to be unloaded. This function will be called by the VM when the library is about to be unloaded.
The library will be unloaded and this function will be called if some platform specific The library will be unloaded (unless it is statically linked into the
executable) and this function will be called if some platform specific
mechanism causes the unload (an unload mechanism is not specified in this document) mechanism causes the unload (an unload mechanism is not specified in this document)
or the library is (in effect) unloaded by the termination of the VM whether through or the library is (in effect) unloaded by the termination of the VM whether through
normal termination or VM failure, including start-up failure. normal termination or VM failure, including start-up failure.
@ -625,8 +694,9 @@ Agent_OnUnload(JavaVM *vm)</example>
<eventlink id="VMDeath">VM Death event</eventlink>: for the VM Death event <eventlink id="VMDeath">VM Death event</eventlink>: for the VM Death event
to be sent, the VM must have run at least to the point of initialization and a valid to be sent, the VM must have run at least to the point of initialization and a valid
<jvmti/> environment must exist which has set a callback for VMDeath <jvmti/> environment must exist which has set a callback for VMDeath
and enabled the event and enabled the event.
None of these are required for <code>Agent_OnUnload</code> and this function None of these are required for <code>Agent_OnUnload</code> or
<code>Agent_OnUnload_&lt;agent-lib-name&gt;</code> and this function
is also called if the library is unloaded for other reasons. is also called if the library is unloaded for other reasons.
In the case that a VM Death event is sent, it will be sent before this In the case that a VM Death event is sent, it will be sent before this
function is called (assuming this function is called due to VM termination). function is called (assuming this function is called due to VM termination).
@ -10701,10 +10771,14 @@ myInit() {
<constants id="jvmtiPhase" label="Phases of execution" kind="enum"> <constants id="jvmtiPhase" label="Phases of execution" kind="enum">
<constant id="JVMTI_PHASE_ONLOAD" num="1"> <constant id="JVMTI_PHASE_ONLOAD" num="1">
<code>OnLoad</code> phase: while in the <code>OnLoad</code> phase: while in the
<internallink id="onload"><code>Agent_OnLoad</code></internallink> function. <internallink id="onload"><code>Agent_OnLoad</code></internallink>
or, for statically linked agents, the <internallink id="onload">
<code>Agent_OnLoad_&lt;agent-lib-name&gt;
</code></internallink> function.
</constant> </constant>
<constant id="JVMTI_PHASE_PRIMORDIAL" num="2"> <constant id="JVMTI_PHASE_PRIMORDIAL" num="2">
Primordial phase: between return from <code>Agent_OnLoad</code> and the Primordial phase: between return from <code>Agent_OnLoad</code>
or <code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> and the
<code>VMStart</code> event. <code>VMStart</code> event.
</constant> </constant>
<constant id="JVMTI_PHASE_START" num="6"> <constant id="JVMTI_PHASE_START" num="6">
@ -14261,6 +14335,9 @@ typedef void (JNICALL *jvmtiEventVMInit)
<change date="11 October 2012" version="1.2.2"> <change date="11 October 2012" version="1.2.2">
Fixed the "HTTP" and "Missing Anchor" errors reported by the LinkCheck tool. Fixed the "HTTP" and "Missing Anchor" errors reported by the LinkCheck tool.
</change> </change>
<change date="19 June 2013" version="1.2.3">
Added support for statically linked agents.
</change>
</changehistory> </changehistory>
</specification> </specification>

View File

@ -2191,6 +2191,8 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
char buffer[JVM_MAXPATHLEN]; char buffer[JVM_MAXPATHLEN];
void* library = NULL; void* library = NULL;
jint result = JNI_ERR; jint result = JNI_ERR;
const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS;
size_t num_symbol_entries = ARRAY_SIZE(on_attach_symbols);
// get agent name and options // get agent name and options
const char* agent = op->arg(0); const char* agent = op->arg(0);
@ -2200,43 +2202,48 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
// The abs paramter should be "true" or "false" // The abs paramter should be "true" or "false"
bool is_absolute_path = (absParam != NULL) && (strcmp(absParam,"true")==0); bool is_absolute_path = (absParam != NULL) && (strcmp(absParam,"true")==0);
// Initially marked as invalid. It will be set to valid if we can find the agent
AgentLibrary *agent_lib = new AgentLibrary(agent, options, is_absolute_path, NULL);
// If the path is absolute we attempt to load the library. Otherwise we try to // Check for statically linked in agent. If not found then if the path is
// load it from the standard dll directory. // absolute we attempt to load the library. Otherwise we try to load it
// from the standard dll directory.
if (is_absolute_path) { if (!os::find_builtin_agent(agent_lib, on_attach_symbols, num_symbol_entries)) {
library = os::dll_load(agent, ebuf, sizeof ebuf); if (is_absolute_path) {
} else { library = os::dll_load(agent, ebuf, sizeof ebuf);
// Try to load the agent from the standard dll directory } else {
if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), // Try to load the agent from the standard dll directory
agent)) { if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
library = os::dll_load(buffer, ebuf, sizeof ebuf); agent)) {
}
if (library == NULL) {
// not found - try local path
char ns[1] = {0};
if (os::dll_build_name(buffer, sizeof(buffer), ns, agent)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf); library = os::dll_load(buffer, ebuf, sizeof ebuf);
} }
if (library == NULL) {
// not found - try local path
char ns[1] = {0};
if (os::dll_build_name(buffer, sizeof(buffer), ns, agent)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
}
}
if (library != NULL) {
agent_lib->set_os_lib(library);
agent_lib->set_valid();
} }
} }
// If the library was loaded then we attempt to invoke the Agent_OnAttach // If the library was loaded then we attempt to invoke the Agent_OnAttach
// function // function
if (library != NULL) { if (agent_lib->valid()) {
// Lookup the Agent_OnAttach function // Lookup the Agent_OnAttach function
OnAttachEntry_t on_attach_entry = NULL; OnAttachEntry_t on_attach_entry = NULL;
const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS; on_attach_entry = CAST_TO_FN_PTR(OnAttachEntry_t,
for (uint symbol_index = 0; symbol_index < ARRAY_SIZE(on_attach_symbols); symbol_index++) { os::find_agent_function(agent_lib, false, on_attach_symbols, num_symbol_entries));
on_attach_entry =
CAST_TO_FN_PTR(OnAttachEntry_t, os::dll_lookup(library, on_attach_symbols[symbol_index]));
if (on_attach_entry != NULL) break;
}
if (on_attach_entry == NULL) { if (on_attach_entry == NULL) {
// Agent_OnAttach missing - unload library // Agent_OnAttach missing - unload library
os::dll_unload(library); if (!agent_lib->is_static_lib()) {
os::dll_unload(library);
}
delete agent_lib;
} else { } else {
// Invoke the Agent_OnAttach function // Invoke the Agent_OnAttach function
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
@ -2256,7 +2263,9 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
// If OnAttach returns JNI_OK then we add it to the list of // If OnAttach returns JNI_OK then we add it to the list of
// agent libraries so that we can call Agent_OnUnload later. // agent libraries so that we can call Agent_OnUnload later.
if (result == JNI_OK) { if (result == JNI_OK) {
Arguments::add_loaded_agent(agent, (char*)options, is_absolute_path, library); Arguments::add_loaded_agent(agent_lib);
} else {
delete agent_lib;
} }
// Agent_OnAttach executed so completion status is JNI_OK // Agent_OnAttach executed so completion status is JNI_OK

View File

@ -1554,18 +1554,22 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class,
return false; return false;
} }
// rewrite sourc file name index: // rewrite source file name index:
u2 source_file_name_idx = scratch_class->source_file_name_index(); u2 source_file_name_idx = scratch_class->source_file_name_index();
if (source_file_name_idx != 0) { if (source_file_name_idx != 0) {
u2 new_source_file_name_idx = find_new_index(source_file_name_idx); u2 new_source_file_name_idx = find_new_index(source_file_name_idx);
scratch_class->set_source_file_name_index(new_source_file_name_idx); if (new_source_file_name_idx != 0) {
scratch_class->set_source_file_name_index(new_source_file_name_idx);
}
} }
// rewrite class generic signature index: // rewrite class generic signature index:
u2 generic_signature_index = scratch_class->generic_signature_index(); u2 generic_signature_index = scratch_class->generic_signature_index();
if (generic_signature_index != 0) { if (generic_signature_index != 0) {
u2 new_generic_signature_index = find_new_index(generic_signature_index); u2 new_generic_signature_index = find_new_index(generic_signature_index);
scratch_class->set_generic_signature_index(new_generic_signature_index); if (new_generic_signature_index != 0) {
scratch_class->set_generic_signature_index(new_generic_signature_index);
}
} }
return true; return true;
@ -1737,7 +1741,10 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method,
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
const u2 cp_index = elem[i].name_cp_index; const u2 cp_index = elem[i].name_cp_index;
elem[i].name_cp_index = find_new_index(cp_index); const u2 new_cp_index = find_new_index(cp_index);
if (new_cp_index != 0) {
elem[i].name_cp_index = new_cp_index;
}
} }
} }
} // end rewrite_cp_refs_in_method() } // end rewrite_cp_refs_in_method()

View File

@ -128,7 +128,7 @@ WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
WB_END WB_END
#endif // INCLUDE_ALL_GCS #endif // INCLUDE_ALL_GCS
#ifdef INCLUDE_NMT #if INCLUDE_NMT
// Alloc memory using the test memory type so that we can use that to see if // Alloc memory using the test memory type so that we can use that to see if
// NMT picks it up correctly // NMT picks it up correctly
WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size)) WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size))
@ -181,6 +181,10 @@ WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env))
return MemTracker::wbtest_wait_for_data_merge(); return MemTracker::wbtest_wait_for_data_merge();
WB_END WB_END
WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env))
return MemTracker::tracking_level() == MemTracker::NMT_detail;
WB_END
#endif // INCLUDE_NMT #endif // INCLUDE_NMT
static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) {
@ -439,7 +443,7 @@ static JNINativeMethod methods[] = {
{CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions },
{CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize },
#endif // INCLUDE_ALL_GCS #endif // INCLUDE_ALL_GCS
#ifdef INCLUDE_NMT #if INCLUDE_NMT
{CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc }, {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
{CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree }, {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree },
{CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory }, {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory },
@ -447,6 +451,7 @@ static JNINativeMethod methods[] = {
{CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory }, {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory },
{CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory }, {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory },
{CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge}, {CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge},
{CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported},
#endif // INCLUDE_NMT #endif // INCLUDE_NMT
{CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll },
{CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I", {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I",

View File

@ -118,11 +118,21 @@ class SystemProperty: public CHeapObj<mtInternal> {
// For use by -agentlib, -agentpath and -Xrun // For use by -agentlib, -agentpath and -Xrun
class AgentLibrary : public CHeapObj<mtInternal> { class AgentLibrary : public CHeapObj<mtInternal> {
friend class AgentLibraryList; friend class AgentLibraryList;
public:
// Is this library valid or not. Don't rely on os_lib == NULL as statically
// linked lib could have handle of RTLD_DEFAULT which == 0 on some platforms
enum AgentState {
agent_invalid = 0,
agent_valid = 1
};
private: private:
char* _name; char* _name;
char* _options; char* _options;
void* _os_lib; void* _os_lib;
bool _is_absolute_path; bool _is_absolute_path;
bool _is_static_lib;
AgentState _state;
AgentLibrary* _next; AgentLibrary* _next;
public: public:
@ -133,6 +143,11 @@ class AgentLibrary : public CHeapObj<mtInternal> {
void* os_lib() const { return _os_lib; } void* os_lib() const { return _os_lib; }
void set_os_lib(void* os_lib) { _os_lib = os_lib; } void set_os_lib(void* os_lib) { _os_lib = os_lib; }
AgentLibrary* next() const { return _next; } AgentLibrary* next() const { return _next; }
bool is_static_lib() const { return _is_static_lib; }
void set_static_lib(bool static_lib) { _is_static_lib = static_lib; }
bool valid() { return (_state == agent_valid); }
void set_valid() { _state = agent_valid; }
void set_invalid() { _state = agent_invalid; }
// Constructor // Constructor
AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) { AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) {
@ -147,6 +162,8 @@ class AgentLibrary : public CHeapObj<mtInternal> {
_is_absolute_path = is_absolute_path; _is_absolute_path = is_absolute_path;
_os_lib = os_lib; _os_lib = os_lib;
_next = NULL; _next = NULL;
_state = agent_invalid;
_is_static_lib = false;
} }
}; };
@ -276,6 +293,8 @@ class Arguments : AllStatic {
{ _agentList.add(new AgentLibrary(name, options, absolute_path, NULL)); } { _agentList.add(new AgentLibrary(name, options, absolute_path, NULL)); }
// Late-binding agents not started via arguments // Late-binding agents not started via arguments
static void add_loaded_agent(AgentLibrary *agentLib)
{ _agentList.add(agentLib); }
static void add_loaded_agent(const char* name, char* options, bool absolute_path, void* os_lib) static void add_loaded_agent(const char* name, char* options, bool absolute_path, void* os_lib)
{ _agentList.add(new AgentLibrary(name, options, absolute_path, os_lib)); } { _agentList.add(new AgentLibrary(name, options, absolute_path, os_lib)); }

View File

@ -1933,6 +1933,9 @@ class CommandLineFlags {
notproduct(bool, ExecuteInternalVMTests, false, \ notproduct(bool, ExecuteInternalVMTests, false, \
"Enable execution of internal VM tests.") \ "Enable execution of internal VM tests.") \
\ \
notproduct(bool, VerboseInternalVMTests, false, \
"Turn on logging for internal VM tests.") \
\
product_pd(bool, UseTLAB, "Use thread-local object allocation") \ product_pd(bool, UseTLAB, "Use thread-local object allocation") \
\ \
product_pd(bool, ResizeTLAB, \ product_pd(bool, ResizeTLAB, \

View File

@ -124,13 +124,15 @@ Monitor* GCTaskManager_lock = NULL;
Mutex* Management_lock = NULL; Mutex* Management_lock = NULL;
Monitor* Service_lock = NULL; Monitor* Service_lock = NULL;
Mutex* Stacktrace_lock = NULL; Monitor* PeriodicTask_lock = NULL;
Monitor* JfrQuery_lock = NULL; #ifdef INCLUDE_TRACE
Mutex* JfrStacktrace_lock = NULL;
Monitor* JfrMsg_lock = NULL; Monitor* JfrMsg_lock = NULL;
Mutex* JfrBuffer_lock = NULL; Mutex* JfrBuffer_lock = NULL;
Mutex* JfrStream_lock = NULL; Mutex* JfrStream_lock = NULL;
Monitor* PeriodicTask_lock = NULL; Mutex* JfrThreadGroups_lock = NULL;
#endif
#define MAX_NUM_MUTEX 128 #define MAX_NUM_MUTEX 128
static Monitor * _mutex_array[MAX_NUM_MUTEX]; static Monitor * _mutex_array[MAX_NUM_MUTEX];
@ -206,7 +208,6 @@ void mutex_init() {
def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching. def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching.
def(ObjAllocPost_lock , Monitor, special, false); def(ObjAllocPost_lock , Monitor, special, false);
def(Service_lock , Monitor, special, true ); // used for service thread operations def(Service_lock , Monitor, special, true ); // used for service thread operations
def(Stacktrace_lock , Mutex, special, true ); // used for JFR stacktrace database
def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs.
def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread
@ -272,11 +273,16 @@ void mutex_init() {
def(Debug3_lock , Mutex , nonleaf+4, true ); def(Debug3_lock , Mutex , nonleaf+4, true );
def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread
def(CompileThread_lock , Monitor, nonleaf+5, false ); def(CompileThread_lock , Monitor, nonleaf+5, false );
def(PeriodicTask_lock , Monitor, nonleaf+5, true);
#ifdef INCLUDE_TRACE
def(JfrMsg_lock , Monitor, leaf, true); def(JfrMsg_lock , Monitor, leaf, true);
def(JfrBuffer_lock , Mutex, nonleaf+1, true); def(JfrBuffer_lock , Mutex, nonleaf+1, true);
def(JfrThreadGroups_lock , Mutex, nonleaf+1, true);
def(JfrStream_lock , Mutex, nonleaf+2, true); def(JfrStream_lock , Mutex, nonleaf+2, true);
def(PeriodicTask_lock , Monitor, nonleaf+5, true); def(JfrStacktrace_lock , Mutex, special, true );
#endif
} }
GCMutexLocker::GCMutexLocker(Monitor * mutex) { GCMutexLocker::GCMutexLocker(Monitor * mutex) {

View File

@ -137,13 +137,15 @@ extern Mutex* HotCardCache_lock; // protects the hot card cache
extern Mutex* Management_lock; // a lock used to serialize JVM management extern Mutex* Management_lock; // a lock used to serialize JVM management
extern Monitor* Service_lock; // a lock used for service thread operation extern Monitor* Service_lock; // a lock used for service thread operation
extern Mutex* Stacktrace_lock; // used to guard access to the stacktrace table extern Monitor* PeriodicTask_lock; // protects the periodic task structure
extern Monitor* JfrQuery_lock; // protects JFR use #ifdef INCLUDE_TRACE
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
extern Monitor* JfrMsg_lock; // protects JFR messaging extern Monitor* JfrMsg_lock; // protects JFR messaging
extern Mutex* JfrBuffer_lock; // protects JFR buffer operations extern Mutex* JfrBuffer_lock; // protects JFR buffer operations
extern Mutex* JfrStream_lock; // protects JFR stream access extern Mutex* JfrStream_lock; // protects JFR stream access
extern Monitor* PeriodicTask_lock; // protects the periodic task structure extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups
#endif
// A MutexLocker provides mutual exclusion with respect to a given mutex // A MutexLocker provides mutual exclusion with respect to a given mutex
// for the scope which contains the locker. The lock is an OS lock, not // for the scope which contains the locker. The lock is an OS lock, not

View File

@ -443,6 +443,67 @@ void* os::native_java_library() {
return _native_java_library; return _native_java_library;
} }
/*
* Support for finding Agent_On(Un)Load/Attach<_lib_name> if it exists.
* If check_lib == true then we are looking for an
* Agent_OnLoad_lib_name or Agent_OnAttach_lib_name function to determine if
* this library is statically linked into the image.
* If check_lib == false then we will look for the appropriate symbol in the
* executable if agent_lib->is_static_lib() == true or in the shared library
* referenced by 'handle'.
*/
void* os::find_agent_function(AgentLibrary *agent_lib, bool check_lib,
const char *syms[], size_t syms_len) {
const char *lib_name;
void *handle = agent_lib->os_lib();
void *entryName = NULL;
char *agent_function_name;
size_t i;
// If checking then use the agent name otherwise test is_static_lib() to
// see how to process this lookup
lib_name = ((check_lib || agent_lib->is_static_lib()) ? agent_lib->name() : NULL);
for (i = 0; i < syms_len; i++) {
agent_function_name = build_agent_function_name(syms[i], lib_name, agent_lib->is_absolute_path());
if (agent_function_name == NULL) {
break;
}
entryName = dll_lookup(handle, agent_function_name);
FREE_C_HEAP_ARRAY(char, agent_function_name, mtThread);
if (entryName != NULL) {
break;
}
}
return entryName;
}
// See if the passed in agent is statically linked into the VM image.
bool os::find_builtin_agent(AgentLibrary *agent_lib, const char *syms[],
size_t syms_len) {
void *ret;
void *proc_handle;
void *save_handle;
if (agent_lib->name() == NULL) {
return false;
}
proc_handle = get_default_process_handle();
// Check for Agent_OnLoad/Attach_lib_name function
save_handle = agent_lib->os_lib();
// We want to look in this process' symbol table.
agent_lib->set_os_lib(proc_handle);
ret = find_agent_function(agent_lib, true, syms, syms_len);
agent_lib->set_os_lib(save_handle);
if (ret != NULL) {
// Found an entry point like Agent_OnLoad_lib_name so we have a static agent
agent_lib->set_os_lib(proc_handle);
agent_lib->set_valid();
agent_lib->set_static_lib(true);
return true;
}
return false;
}
// --------------------- heap allocation utilities --------------------- // --------------------- heap allocation utilities ---------------------
char *os::strdup(const char *str, MEMFLAGS flags) { char *os::strdup(const char *str, MEMFLAGS flags) {

View File

@ -46,6 +46,8 @@
# include <setjmp.h> # include <setjmp.h>
#endif #endif
class AgentLibrary;
// os defines the interface to operating system; this includes traditional // os defines the interface to operating system; this includes traditional
// OS services (time, I/O) as well as other functionality with system- // OS services (time, I/O) as well as other functionality with system-
// dependent code. // dependent code.
@ -328,8 +330,8 @@ class os: AllStatic {
static char* non_memory_address_word(); static char* non_memory_address_word();
// reserve, commit and pin the entire memory region // reserve, commit and pin the entire memory region
static char* reserve_memory_special(size_t size, char* addr = NULL, static char* reserve_memory_special(size_t size, size_t alignment,
bool executable = false); char* addr, bool executable);
static bool release_memory_special(char* addr, size_t bytes); static bool release_memory_special(char* addr, size_t bytes);
static void large_page_init(); static void large_page_init();
static size_t large_page_size(); static size_t large_page_size();
@ -537,6 +539,17 @@ class os: AllStatic {
// Unload library // Unload library
static void dll_unload(void *lib); static void dll_unload(void *lib);
// Return the handle of this process
static void* get_default_process_handle();
// Check for static linked agent library
static bool find_builtin_agent(AgentLibrary *agent_lib, const char *syms[],
size_t syms_len);
// Find agent entry point
static void *find_agent_function(AgentLibrary *agent_lib, bool check_lib,
const char *syms[], size_t syms_len);
// Print out system information; they are called by fatal error handler. // Print out system information; they are called by fatal error handler.
// Output format may be different on different platforms. // Output format may be different on different platforms.
static void print_os_info(outputStream* st); static void print_os_info(outputStream* st);
@ -806,6 +819,11 @@ class os: AllStatic {
// ResumeThread call) // ResumeThread call)
static void pause(); static void pause();
// Builds a platform dependent Agent_OnLoad_<libname> function name
// which is used to find statically linked in agents.
static char* build_agent_function_name(const char *sym, const char *cname,
bool is_absolute_path);
class SuspendedThreadTaskContext { class SuspendedThreadTaskContext {
public: public:
SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {} SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {}

View File

@ -3696,15 +3696,18 @@ extern "C" {
// num_symbol_entries must be passed-in since only the caller knows the number of symbols in the array. // num_symbol_entries must be passed-in since only the caller knows the number of symbols in the array.
static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_symbols[], size_t num_symbol_entries) { static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_symbols[], size_t num_symbol_entries) {
OnLoadEntry_t on_load_entry = NULL; OnLoadEntry_t on_load_entry = NULL;
void *library = agent->os_lib(); // check if we have looked it up before void *library = NULL;
if (library == NULL) { if (!agent->valid()) {
char buffer[JVM_MAXPATHLEN]; char buffer[JVM_MAXPATHLEN];
char ebuf[1024]; char ebuf[1024];
const char *name = agent->name(); const char *name = agent->name();
const char *msg = "Could not find agent library "; const char *msg = "Could not find agent library ";
if (agent->is_absolute_path()) { // First check to see if agent is statcally linked into executable
if (os::find_builtin_agent(agent, on_load_symbols, num_symbol_entries)) {
library = agent->os_lib();
} else if (agent->is_absolute_path()) {
library = os::dll_load(name, ebuf, sizeof ebuf); library = os::dll_load(name, ebuf, sizeof ebuf);
if (library == NULL) { if (library == NULL) {
const char *sub_msg = " in absolute path, with error: "; const char *sub_msg = " in absolute path, with error: ";
@ -3738,13 +3741,15 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym
} }
} }
agent->set_os_lib(library); agent->set_os_lib(library);
agent->set_valid();
} }
// Find the OnLoad function. // Find the OnLoad function.
for (size_t symbol_index = 0; symbol_index < num_symbol_entries; symbol_index++) { on_load_entry =
on_load_entry = CAST_TO_FN_PTR(OnLoadEntry_t, os::dll_lookup(library, on_load_symbols[symbol_index])); CAST_TO_FN_PTR(OnLoadEntry_t, os::find_agent_function(agent,
if (on_load_entry != NULL) break; false,
} on_load_symbols,
num_symbol_entries));
return on_load_entry; return on_load_entry;
} }
@ -3819,22 +3824,23 @@ extern "C" {
void Threads::shutdown_vm_agents() { void Threads::shutdown_vm_agents() {
// Send any Agent_OnUnload notifications // Send any Agent_OnUnload notifications
const char *on_unload_symbols[] = AGENT_ONUNLOAD_SYMBOLS; const char *on_unload_symbols[] = AGENT_ONUNLOAD_SYMBOLS;
size_t num_symbol_entries = ARRAY_SIZE(on_unload_symbols);
extern struct JavaVM_ main_vm; extern struct JavaVM_ main_vm;
for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) { for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
// Find the Agent_OnUnload function. // Find the Agent_OnUnload function.
for (uint symbol_index = 0; symbol_index < ARRAY_SIZE(on_unload_symbols); symbol_index++) { Agent_OnUnload_t unload_entry = CAST_TO_FN_PTR(Agent_OnUnload_t,
Agent_OnUnload_t unload_entry = CAST_TO_FN_PTR(Agent_OnUnload_t, os::find_agent_function(agent,
os::dll_lookup(agent->os_lib(), on_unload_symbols[symbol_index])); false,
on_unload_symbols,
num_symbol_entries));
// Invoke the Agent_OnUnload function // Invoke the Agent_OnUnload function
if (unload_entry != NULL) { if (unload_entry != NULL) {
JavaThread* thread = JavaThread::current(); JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread); ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread); HandleMark hm(thread);
(*unload_entry)(&main_vm); (*unload_entry)(&main_vm);
break;
}
} }
} }
} }

View File

@ -42,8 +42,19 @@
// ReservedSpace // ReservedSpace
// Dummy constructor
ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0),
_alignment(0), _special(false), _executable(false) {
}
ReservedSpace::ReservedSpace(size_t size) { ReservedSpace::ReservedSpace(size_t size) {
initialize(size, 0, false, NULL, 0, false); size_t page_size = os::page_size_for_region(size, size, 1);
bool large_pages = page_size != (size_t)os::vm_page_size();
// Don't force the alignment to be large page aligned,
// since that will waste memory.
size_t alignment = os::vm_allocation_granularity();
initialize(size, alignment, large_pages, NULL, 0, false);
} }
ReservedSpace::ReservedSpace(size_t size, size_t alignment, ReservedSpace::ReservedSpace(size_t size, size_t alignment,
@ -129,16 +140,18 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
if (special) { if (special) {
base = os::reserve_memory_special(size, requested_address, executable); base = os::reserve_memory_special(size, alignment, requested_address, executable);
if (base != NULL) { if (base != NULL) {
if (failed_to_reserve_as_requested(base, requested_address, size, true)) { if (failed_to_reserve_as_requested(base, requested_address, size, true)) {
// OS ignored requested address. Try different address. // OS ignored requested address. Try different address.
return; return;
} }
// Check alignment constraints // Check alignment constraints.
assert((uintptr_t) base % alignment == 0, assert((uintptr_t) base % alignment == 0,
"Large pages returned a non-aligned address"); err_msg("Large pages returned a non-aligned address, base: "
PTR_FORMAT " alignment: " PTR_FORMAT,
base, (void*)(uintptr_t)alignment));
_special = true; _special = true;
} else { } else {
// failed; try to reserve regular memory below // failed; try to reserve regular memory below
@ -715,4 +728,188 @@ void VirtualSpace::print() {
tty->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); tty->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary());
} }
/////////////// Unit tests ///////////////
#ifndef PRODUCT
#define test_log(...) \
do {\
if (VerboseInternalVMTests) { \
tty->print_cr(__VA_ARGS__); \
tty->flush(); \
}\
} while (false)
class TestReservedSpace : AllStatic {
public:
static void small_page_write(void* addr, size_t size) {
size_t page_size = os::vm_page_size();
char* end = (char*)addr + size;
for (char* p = (char*)addr; p < end; p += page_size) {
*p = 1;
}
}
static void release_memory_for_test(ReservedSpace rs) {
if (rs.special()) {
guarantee(os::release_memory_special(rs.base(), rs.size()), "Shouldn't fail");
} else {
guarantee(os::release_memory(rs.base(), rs.size()), "Shouldn't fail");
}
}
static void test_reserved_space1(size_t size, size_t alignment) {
test_log("test_reserved_space1(%p)", (void*) (uintptr_t) size);
assert(is_size_aligned(size, alignment), "Incorrect input parameters");
ReservedSpace rs(size, // size
alignment, // alignment
UseLargePages, // large
NULL, // requested_address
0); // noacces_prefix
test_log(" rs.special() == %d", rs.special());
assert(rs.base() != NULL, "Must be");
assert(rs.size() == size, "Must be");
assert(is_ptr_aligned(rs.base(), alignment), "aligned sizes should always give aligned addresses");
assert(is_size_aligned(rs.size(), alignment), "aligned sizes should always give aligned addresses");
if (rs.special()) {
small_page_write(rs.base(), size);
}
release_memory_for_test(rs);
}
static void test_reserved_space2(size_t size) {
test_log("test_reserved_space2(%p)", (void*)(uintptr_t)size);
assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned");
ReservedSpace rs(size);
test_log(" rs.special() == %d", rs.special());
assert(rs.base() != NULL, "Must be");
assert(rs.size() == size, "Must be");
if (rs.special()) {
small_page_write(rs.base(), size);
}
release_memory_for_test(rs);
}
static void test_reserved_space3(size_t size, size_t alignment, bool maybe_large) {
test_log("test_reserved_space3(%p, %p, %d)",
(void*)(uintptr_t)size, (void*)(uintptr_t)alignment, maybe_large);
assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned");
assert(is_size_aligned(size, alignment), "Must be at least aligned against alignment");
bool large = maybe_large && UseLargePages && size >= os::large_page_size();
ReservedSpace rs(size, alignment, large, false);
test_log(" rs.special() == %d", rs.special());
assert(rs.base() != NULL, "Must be");
assert(rs.size() == size, "Must be");
if (rs.special()) {
small_page_write(rs.base(), size);
}
release_memory_for_test(rs);
}
static void test_reserved_space1() {
size_t size = 2 * 1024 * 1024;
size_t ag = os::vm_allocation_granularity();
test_reserved_space1(size, ag);
test_reserved_space1(size * 2, ag);
test_reserved_space1(size * 10, ag);
}
static void test_reserved_space2() {
size_t size = 2 * 1024 * 1024;
size_t ag = os::vm_allocation_granularity();
test_reserved_space2(size * 1);
test_reserved_space2(size * 2);
test_reserved_space2(size * 10);
test_reserved_space2(ag);
test_reserved_space2(size - ag);
test_reserved_space2(size);
test_reserved_space2(size + ag);
test_reserved_space2(size * 2);
test_reserved_space2(size * 2 - ag);
test_reserved_space2(size * 2 + ag);
test_reserved_space2(size * 3);
test_reserved_space2(size * 3 - ag);
test_reserved_space2(size * 3 + ag);
test_reserved_space2(size * 10);
test_reserved_space2(size * 10 + size / 2);
}
static void test_reserved_space3() {
size_t ag = os::vm_allocation_granularity();
test_reserved_space3(ag, ag , false);
test_reserved_space3(ag * 2, ag , false);
test_reserved_space3(ag * 3, ag , false);
test_reserved_space3(ag * 2, ag * 2, false);
test_reserved_space3(ag * 4, ag * 2, false);
test_reserved_space3(ag * 8, ag * 2, false);
test_reserved_space3(ag * 4, ag * 4, false);
test_reserved_space3(ag * 8, ag * 4, false);
test_reserved_space3(ag * 16, ag * 4, false);
if (UseLargePages) {
size_t lp = os::large_page_size();
// Without large pages
test_reserved_space3(lp, ag * 4, false);
test_reserved_space3(lp * 2, ag * 4, false);
test_reserved_space3(lp * 4, ag * 4, false);
test_reserved_space3(lp, lp , false);
test_reserved_space3(lp * 2, lp , false);
test_reserved_space3(lp * 3, lp , false);
test_reserved_space3(lp * 2, lp * 2, false);
test_reserved_space3(lp * 4, lp * 2, false);
test_reserved_space3(lp * 8, lp * 2, false);
// With large pages
test_reserved_space3(lp, ag * 4 , true);
test_reserved_space3(lp * 2, ag * 4, true);
test_reserved_space3(lp * 4, ag * 4, true);
test_reserved_space3(lp, lp , true);
test_reserved_space3(lp * 2, lp , true);
test_reserved_space3(lp * 3, lp , true);
test_reserved_space3(lp * 2, lp * 2, true);
test_reserved_space3(lp * 4, lp * 2, true);
test_reserved_space3(lp * 8, lp * 2, true);
}
}
static void test_reserved_space() {
test_reserved_space1();
test_reserved_space2();
test_reserved_space3();
}
};
void TestReservedSpace_test() {
TestReservedSpace::test_reserved_space();
}
#endif // PRODUCT
#endif #endif

View File

@ -53,6 +53,7 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC {
public: public:
// Constructor // Constructor
ReservedSpace();
ReservedSpace(size_t size); ReservedSpace(size_t size);
ReservedSpace(size_t size, size_t alignment, bool large, ReservedSpace(size_t size, size_t alignment, bool large,
char* requested_address = NULL, char* requested_address = NULL,

View File

@ -876,8 +876,6 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap))
total_used += u.used(); total_used += u.used();
total_committed += u.committed(); total_committed += u.committed();
// if any one of the memory pool has undefined init_size or max_size,
// set it to -1
if (u.init_size() == (size_t)-1) { if (u.init_size() == (size_t)-1) {
has_undefined_init_size = true; has_undefined_init_size = true;
} }
@ -894,6 +892,15 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap))
} }
} }
// if any one of the memory pool has undefined init_size or max_size,
// set it to -1
if (has_undefined_init_size) {
total_init = (size_t)-1;
}
if (has_undefined_max_size) {
total_max = (size_t)-1;
}
MemoryUsage usage((heap ? InitialHeapSize : total_init), MemoryUsage usage((heap ? InitialHeapSize : total_init),
total_used, total_used,
total_committed, total_committed,

View File

@ -87,6 +87,8 @@ class MemTracker : AllStatic {
MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
static inline void record_virtual_memory_commit(address addr, size_t size, static inline void record_virtual_memory_commit(address addr, size_t size,
address pc = 0, Thread* thread = NULL) { } address pc = 0, Thread* thread = NULL) { }
static inline void record_virtual_memory_release(address addr, size_t size,
Thread* thread = NULL) { }
static inline void record_virtual_memory_type(address base, MEMFLAGS flags, static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
Thread* thread = NULL) { } Thread* thread = NULL) { }
static inline Tracker get_realloc_tracker() { return _tkr; } static inline Tracker get_realloc_tracker() { return _tkr; }
@ -372,6 +374,13 @@ class MemTracker : AllStatic {
tkr.record(addr, size, flags, pc); tkr.record(addr, size, flags, pc);
} }
static inline void record_virtual_memory_release(address addr, size_t size,
Thread* thread = NULL) {
if (is_on()) {
Tracker tkr(Tracker::Release, thread);
tkr.record(addr, size);
}
}
// record memory type on virtual memory base address // record memory type on virtual memory base address
static inline void record_virtual_memory_type(address base, MEMFLAGS flags, static inline void record_virtual_memory_type(address base, MEMFLAGS flags,

View File

@ -402,6 +402,14 @@ const jlong CompressedKlassPointersBase = NOT_LP64(0) LP64_ONLY(CONST64(0x800000
#define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1)) #define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))
inline bool is_size_aligned(size_t size, size_t alignment) {
return align_size_up_(size, alignment) == size;
}
inline bool is_ptr_aligned(void* ptr, size_t alignment) {
return align_size_up_((intptr_t)ptr, (intptr_t)alignment) == (intptr_t)ptr;
}
inline intptr_t align_size_up(intptr_t size, intptr_t alignment) { inline intptr_t align_size_up(intptr_t size, intptr_t alignment) {
return align_size_up_(size, alignment); return align_size_up_(size, alignment);
} }
@ -414,6 +422,14 @@ inline intptr_t align_size_down(intptr_t size, intptr_t alignment) {
#define is_size_aligned_(size, alignment) ((size) == (align_size_up_(size, alignment))) #define is_size_aligned_(size, alignment) ((size) == (align_size_up_(size, alignment)))
inline void* align_ptr_up(void* ptr, size_t alignment) {
return (void*)align_size_up((intptr_t)ptr, (intptr_t)alignment);
}
inline void* align_ptr_down(void* ptr, size_t alignment) {
return (void*)align_size_down((intptr_t)ptr, (intptr_t)alignment);
}
// Align objects by rounding up their size, in HeapWord units. // Align objects by rounding up their size, in HeapWord units.
#define align_object_size_(size) align_size_up_(size, MinObjAlignment) #define align_object_size_(size) align_size_up_(size, MinObjAlignment)

View File

@ -25,7 +25,8 @@
# This file identifies the root of the test-suite hierarchy. # This file identifies the root of the test-suite hierarchy.
# It also contains test-suite configuration information. # It also contains test-suite configuration information.
# DO NOT EDIT without first contacting hotspot-regtest@sun.com
# The list of keywords supported in this test suite # The list of keywords supported in this test suite
keys=cte_test jcmd nmt regression gc keys=cte_test jcmd nmt regression gc
groups=TEST.groups [closed/TEST.groups]

192
hotspot/test/TEST.groups Normal file
View File

@ -0,0 +1,192 @@
#
# 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.
#
# Profile-based Test Group Definitions
#
# These groups define the tests that cover the different possible runtimes:
# - compact1, compact2, compact3, full JRE, JDK
#
# In addition they support testing of the minimal VM on compact1 and compact2.
# Essentially this defines groups based around the specified API's and VM
# services available in the runtime.
#
# The groups are defined hierarchically in two forms:
# - The need_xxx groups list all the tests that have a dependency on
# a specific profile. This is either because it tests a feature in
# that profile, or the test infrastructure uses a feature in that
# profile.
# - The primary groups are defined in terms of the other primary groups
# combined with the needs_xxx groups (including and excluding them as
# appropriate). For example the jre can run all tests from compact3, plus
# those from needs_jre, but excluding those from need_jdk.
#
# The bottom group defines all the actual tests to be considered, simply
# by listing the top-level test directories.
#
# To use a group simply list it on the jtreg command line eg:
# jtreg :jdk
# runs all tests. While
# jtreg :compact2
# runs those tests that only require compact1 and compact2 API's.
#
# Full JDK can run all tests
#
jdk = \
:jre \
:needs_jdk
# Tests that require a full JDK to execute. Either they test a feature
# only in the JDK or they use tools that are only in the JDK. The latter
# can be resolved in some cases by using tools from the compile-jdk.
#
needs_jdk = \
gc/TestG1ZeroPGCTJcmdThreadPrint.java \
gc/metaspace/ClassMetaspaceSizeInJmapHeap.java \
gc/metaspace/TestMetaspacePerfCounters.java \
runtime/6819213/TestBootNativeLibraryPath.java \
runtime/6878713/Test6878713.sh \
runtime/6925573/SortMethodsTest.java \
runtime/7107135/Test7107135.sh \
runtime/7158988/FieldMonitor.java \
runtime/7194254/Test7194254.java \
runtime/jsig/Test8017498.sh \
runtime/Metaspace/FragmentMetaspace.java \
runtime/NMT/BaselineWithParameter.java \
runtime/NMT/JcmdScale.java \
runtime/NMT/JcmdWithNMTDisabled.java \
runtime/NMT/MallocTestType.java \
runtime/NMT/ReleaseCommittedMemory.java \
runtime/NMT/ShutdownTwice.java \
runtime/NMT/SummaryAfterShutdown.java \
runtime/NMT/SummarySanityCheck.java \
runtime/NMT/ThreadedMallocTestType.java \
runtime/NMT/ThreadedVirtualAllocTestType.java \
runtime/NMT/VirtualAllocTestType.java \
runtime/RedefineObject/TestRedefineObject.java \
serviceability/attach/AttachWithStalePidFile.java
# JRE adds further tests to compact3
#
jre = \
:compact3 \
:needs_jre \
-:needs_jdk
# Tests that require the full JRE
#
needs_jre = \
compiler/6852078/Test6852078.java \
compiler/7047069/Test7047069.java \
runtime/6294277/SourceDebugExtension.java
# Compact 3 adds further tests to compact2
#
compact3 = \
:compact2 \
:needs_compact3 \
-:needs_jre \
-:needs_jdk
# Tests that require compact3 API's
#
needs_compact3 = \
compiler/whitebox/DeoptimizeMethodTest.java \
compiler/whitebox/SetForceInlineMethodTest.java \
compiler/whitebox/SetDontInlineMethodTest.java \
compiler/whitebox/DeoptimizeAllTest.java \
compiler/whitebox/MakeMethodNotCompilableTest.java \
compiler/whitebox/ClearMethodStateTest.java \
compiler/whitebox/EnqueueMethodForCompilationTest.java \
compiler/whitebox/IsMethodCompilableTest.java \
gc/6581734/Test6581734.java \
gc/7072527/TestFullGCCount.java \
gc/7168848/HumongousAlloc.java \
gc/arguments/TestG1HeapRegionSize.java \
gc/metaspace/TestMetaspaceMemoryPool.java \
runtime/InternalApi/ThreadCpuTimesDeadlock.java \
serviceability/threads/TestFalseDeadLock.java
# Compact 2 adds full VM tests
compact2 = \
:compact2_minimal \
:compact1 \
:needs_full_vm_compact2 \
-:needs_compact3 \
-:needs_jre \
-:needs_jdk
# Tests that require compact2 API's and a full VM
#
needs_full_vm_compact2 =
# Compact 1 adds full VM tests
#
compact1 = \
:compact1_minimal \
:needs_full_vm_compact1 \
-:needs_compact2 \
-:needs_full_vm_compact2 \
-:needs_compact3 \
-:needs_jre \
-:needs_jdk
# Tests that require compact1 API's and a full VM
#
needs_full_vm_compact1 = \
runtime/NMT \
gc/g1/TestRegionAlignment.java \
gc/g1/TestShrinkToOneRegion.java \
gc/metaspace/G1AddMetaspaceDependency.java \
runtime/6929067/Test6929067.sh
# Minimal VM on Compact 2 adds in some compact2 tests
#
compact2_minimal = \
:compact1_minimal \
:needs_compact2 \
-:needs_full_vm_compact2 \
-:needs_compact3 \
-:needs_jre \
-:needs_jdk
# Tests that require compact2 API's
#
needs_compact2 = \
compiler/6589834/Test_ia32.java
# All tests that run on the most minimal configuration: Minimal VM on Compact 1
compact1_minimal = \
serviceability/ \
compiler/ \
testlibrary/ \
sanity/ \
runtime/ \
gc/ \
-:needs_full_vm_compact1 \
-:needs_full_vm_compact2 \
-:needs_compact2 \
-:needs_compact3 \
-:needs_jre \
-:needs_jdk

View File

@ -0,0 +1,56 @@
/*
* 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 8004051
* @bug 8005722
* @summary assert(_oprs_len[mode] < maxNumberOfOperands) failed: array overflow
*
* @run main/othervm -Xcomp -client Test8004051
*/
public class Test8004051 {
public static void main(String[] argv) {
Object o = new Object();
fillPrimRect(1.1f, 1.2f, 1.3f, 1.4f,
o, o,
1.5f, 1.6f, 1.7f, 1.8f,
2.0f, 2.1f, 2.2f, 2.3f,
2.4f, 2.5f, 2.6f, 2.7f,
100, 101);
System.out.println("Test passed, test did not assert");
}
static boolean fillPrimRect(float x, float y, float w, float h,
Object rectTex, Object wrapTex,
float bx, float by, float bw, float bh,
float f1, float f2, float f3, float f4,
float f5, float f6, float f7, float f8,
int i1, int i2 ) {
System.out.println(x + " " + y + " " + w + " " + h + " " +
bx + " " + by + " " + bw + " " + bh);
return true;
}
}

View File

@ -1,126 +0,0 @@
#
# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test Xchecksig.sh
# @bug 7051189
# @summary Need to suppress info message if -xcheck:jni used with libjsig.so
# @run shell Xchecksig.sh
#
if [ "${TESTSRC}" = "" ]
then
TESTSRC=${PWD}
echo "TESTSRC not set. Using "${TESTSRC}" as default"
fi
echo "TESTSRC=${TESTSRC}"
## Adding common setup Variables for running shell tests.
. ${TESTSRC}/../../test_env.sh
OS=`uname -s`
case "$OS" in
Windows_* | CYGWIN_* )
printf "Not testing libjsig.so on Windows. PASSED.\n "
exit 0
;;
esac
JAVA=${TESTJAVA}${FS}bin${FS}java
# LD_PRELOAD arch needs to match the binary we run, so run the java
# 64-bit binary directly if we are testing 64-bit (bin/ARCH/java).
# Check if TESTVMOPS contains -d64, but cannot use
# java ${TESTVMOPS} to run "java -d64" with LD_PRELOAD.
if [ ${OS} -eq "SunOS" ]
then
printf "SunOS test TESTVMOPTS = ${TESTVMOPTS}"
printf ${TESTVMOPTS} | grep d64 > /dev/null
if [ $? -eq 0 ]
then
printf "SunOS 64-bit test\n"
BIT_FLAG=-d64
fi
fi
ARCH=`uname -p`
case $ARCH in
i386)
if [ X${BIT_FLAG} != "X" ]
then
ARCH=amd64
JAVA=${TESTJAVA}${FS}bin${FS}${ARCH}${FS}java
fi
;;
sparc)
if [ X${BIT_FLAG} != "X" ]
then
ARCH=sparcv9
JAVA=${TESTJAVA}${FS}bin${FS}${ARCH}${FS}java
fi
;;
* )
printf "Not testing architecture $ARCH, skipping test.\n"
exit 0
;;
esac
LIBJSIG=${COMPILEJAVA}${FS}jre${FS}lib${FS}${ARCH}${FS}libjsig.so
# If libjsig and binary do not match, skip test.
A=`file ${LIBJSIG} | awk '{ print $3 }'`
B=`file ${JAVA} | awk '{ print $3 }'`
if [ $A -ne $B ]
then
printf "Mismatching binary and library to preload, skipping test.\n"
exit 0
fi
if [ ! -f ${LIBJSIG} ]
then
printf "Skipping test: libjsig missing for given architecture: ${LIBJSIG}\n"
exit 0
fi
# Use java -version to test, java version info appears on stderr,
# the libjsig message we are removing appears on stdout.
# grep returns zero meaning found, non-zero means not found:
LD_PRELOAD=${LIBJSIG} ${JAVA} ${TESTVMOPTS} -Xcheck:jni -version 2>&1 | grep "libjsig is activated"
if [ $? -eq 0 ]; then
printf "Failed: -Xcheck:jni prints message when libjsig.so is loaded.\n"
exit 1
fi
LD_PRELOAD=${LIBJSIG} ${JAVA} ${TESTVMOPTS} -Xcheck:jni -verbose:jni -version 2>&1 | grep "libjsig is activated"
if [ $? != 0 ]; then
printf "Failed: -Xcheck:jni does not print message when libjsig.so is loaded and -verbose:jni is set.\n"
exit 1
fi
printf "PASSED\n"
exit 0

View File

@ -45,6 +45,13 @@ public class ThreadedVirtualAllocTestType {
String pid = Integer.toString(ProcessTools.getProcessId()); String pid = Integer.toString(ProcessTools.getProcessId());
ProcessBuilder pb = new ProcessBuilder(); ProcessBuilder pb = new ProcessBuilder();
boolean has_nmt_detail = wb.NMTIsDetailSupported();
if (has_nmt_detail) {
System.out.println("NMT detail support detected.");
} else {
System.out.println("NMT detail support not detected.");
}
Thread reserveThread = new Thread() { Thread reserveThread = new Thread() {
public void run() { public void run() {
addr = wb.NMTReserveMemory(reserveSize); addr = wb.NMTReserveMemory(reserveSize);
@ -58,7 +65,9 @@ public class ThreadedVirtualAllocTestType {
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
output = new OutputAnalyzer(pb.start()); output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=512KB, committed=0KB)"); output.shouldContain("Test (reserved=512KB, committed=0KB)");
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 512KB for Test"); if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 512KB for Test");
}
Thread commitThread = new Thread() { Thread commitThread = new Thread() {
public void run() { public void run() {
@ -72,7 +81,9 @@ public class ThreadedVirtualAllocTestType {
output = new OutputAnalyzer(pb.start()); output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=512KB, committed=128KB)"); output.shouldContain("Test (reserved=512KB, committed=128KB)");
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB");
}
Thread uncommitThread = new Thread() { Thread uncommitThread = new Thread() {
public void run() { public void run() {

View File

@ -46,13 +46,22 @@ public class VirtualAllocTestType {
String pid = Integer.toString(ProcessTools.getProcessId()); String pid = Integer.toString(ProcessTools.getProcessId());
ProcessBuilder pb = new ProcessBuilder(); ProcessBuilder pb = new ProcessBuilder();
boolean has_nmt_detail = wb.NMTIsDetailSupported();
if (has_nmt_detail) {
System.out.println("NMT detail support detected.");
} else {
System.out.println("NMT detail support not detected.");
}
addr = wb.NMTReserveMemory(reserveSize); addr = wb.NMTReserveMemory(reserveSize);
mergeData(); mergeData();
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
output = new OutputAnalyzer(pb.start()); output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=256KB, committed=0KB)"); output.shouldContain("Test (reserved=256KB, committed=0KB)");
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 256KB for Test"); if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 256KB for Test");
}
wb.NMTCommitMemory(addr, commitSize); wb.NMTCommitMemory(addr, commitSize);
@ -60,7 +69,9 @@ public class VirtualAllocTestType {
output = new OutputAnalyzer(pb.start()); output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=256KB, committed=128KB)"); output.shouldContain("Test (reserved=256KB, committed=128KB)");
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB");
}
wb.NMTUncommitMemory(addr, commitSize); wb.NMTUncommitMemory(addr, commitSize);
@ -71,7 +82,6 @@ public class VirtualAllocTestType {
output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed"); output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed");
wb.NMTReleaseMemory(addr, reserveSize); wb.NMTReleaseMemory(addr, reserveSize);
mergeData(); mergeData();
output = new OutputAnalyzer(pb.start()); output = new OutputAnalyzer(pb.start());

View File

@ -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.
*
* 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 7051189 8023393
* @summary Need to suppress info message if -Xcheck:jni is used with libjsig.so
* @library /testlibrary
* @run main XCheckJSig
*/
import java.util.*;
import com.oracle.java.testlibrary.*;
public class XCheckJSig {
public static void main(String args[]) throws Throwable {
System.out.println("Regression test for bugs 7051189 and 8023393");
if (!Platform.isSolaris() && !Platform.isLinux() && !Platform.isOSX()) {
System.out.println("Test only applicable on Solaris, Linux, and Mac OSX, skipping");
return;
}
String jdk_path = System.getProperty("test.jdk");
String os_arch = Platform.getOsArch();
String libjsig;
String env_var;
if (Platform.isOSX()) {
libjsig = jdk_path + "/jre/lib/server/libjsig.dylib";
env_var = "DYLD_INSERT_LIBRARIES";
} else {
libjsig = jdk_path + "/jre/lib/" + os_arch + "/libjsig.so";
env_var = "LD_PRELOAD";
}
String java_program;
if (Platform.isSolaris()) {
// On Solaris, need to call the 64-bit Java directly in order for
// LD_PRELOAD to work because libjsig.so is 64-bit.
java_program = jdk_path + "/jre/bin/" + os_arch + "/java";
} else {
java_program = JDKToolFinder.getJDKTool("java");
}
// If this test fails, these might be useful to know.
System.out.println("libjsig: " + libjsig);
System.out.println("osArch: " + os_arch);
System.out.println("java_program: " + java_program);
ProcessBuilder pb = new ProcessBuilder(java_program, "-Xcheck:jni", "-version");
Map<String, String> env = pb.environment();
env.put(env_var, libjsig);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldNotContain("libjsig is activated");
output.shouldHaveExitValue(0);
pb = new ProcessBuilder(java_program, "-Xcheck:jni", "-verbose:jni", "-version");
env = pb.environment();
env.put(env_var, libjsig);
output = new OutputAnalyzer(pb.start());
output.shouldContain("libjsig is activated");
output.shouldHaveExitValue(0);
}
}

View File

@ -90,6 +90,7 @@ public class WhiteBox {
public native void NMTUncommitMemory(long addr, long size); public native void NMTUncommitMemory(long addr, long size);
public native void NMTReleaseMemory(long addr, long size); public native void NMTReleaseMemory(long addr, long size);
public native boolean NMTWaitForDataMerge(); public native boolean NMTWaitForDataMerge();
public native boolean NMTIsDetailSupported();
// Compiler // Compiler
public native void deoptimizeAll(); public native void deoptimizeAll();

View File

@ -226,3 +226,4 @@ c4908732fef5235f1b98cafe0ce507771ef7892c jdk8-b98
8ed8e2b4b90e0ac9aa5b3efef51cd576a9db96a9 jdk8-b102 8ed8e2b4b90e0ac9aa5b3efef51cd576a9db96a9 jdk8-b102
e0f6039c0290b7381042a6fec3100a69a5a67e37 jdk8-b103 e0f6039c0290b7381042a6fec3100a69a5a67e37 jdk8-b103
f1d8d15bfcb5ada858a942f8a31f6598f23214d1 jdk8-b104 f1d8d15bfcb5ada858a942f8a31f6598f23214d1 jdk8-b104
1fe211ae3d2b8cc2dfc4f58d9a6eb96418679672 jdk8-b105

View File

@ -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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -43,8 +43,6 @@ FILES_java = \
com/sun/security/auth/UserPrincipal.java \ com/sun/security/auth/UserPrincipal.java \
com/sun/security/auth/LdapPrincipal.java \ com/sun/security/auth/LdapPrincipal.java \
com/sun/security/auth/PolicyFile.java \ com/sun/security/auth/PolicyFile.java \
com/sun/security/auth/SubjectCodeSource.java \
com/sun/security/auth/PolicyParser.java \
com/sun/security/auth/PrincipalComparator.java \ com/sun/security/auth/PrincipalComparator.java \
com/sun/security/auth/callback/TextCallbackHandler.java \ com/sun/security/auth/callback/TextCallbackHandler.java \
com/sun/security/auth/callback/DialogCallbackHandler.java com/sun/security/auth/callback/DialogCallbackHandler.java

View File

@ -65,10 +65,6 @@ PROFILE_2_JARS := \
$(if $(PROFILE_2_JRE_JAR_FILES), $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_2_JRE_JAR_FILES))) \ $(if $(PROFILE_2_JRE_JAR_FILES), $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_2_JRE_JAR_FILES))) \
$(PROFILE_1_JARS) $(PROFILE_1_JARS)
ifneq ($(ENABLE_JFR), true)
PROFILE_3_JRE_JAR_FILES := $(filter-out jfr.jar, $(PROFILE_3_JRE_JAR_FILES))
endif
PROFILE_3_JARS := \ PROFILE_3_JARS := \
$(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_3_JRE_JAR_FILES)) \ $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_3_JRE_JAR_FILES)) \
$(PROFILE_2_JARS) $(PROFILE_2_JARS)
@ -77,6 +73,10 @@ ifdef OPENJDK
FULL_JRE_JAR_FILES := $(filter-out alt-rt.jar, $(FULL_JRE_JAR_FILES)) FULL_JRE_JAR_FILES := $(filter-out alt-rt.jar, $(FULL_JRE_JAR_FILES))
endif endif
ifneq ($(ENABLE_JFR), true)
FULL_JRE_JAR_FILES := $(filter-out jfr.jar, $(FULL_JRE_JAR_FILES))
endif
FULL_JRE_JARS := \ FULL_JRE_JARS := \
$(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(FULL_JRE_JAR_FILES)) \ $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(FULL_JRE_JAR_FILES)) \
$(PROFILE_3_JARS) $(PROFILE_3_JARS)

View File

@ -87,6 +87,7 @@ class KQueueArrayWrapper {
private int incomingInterruptFD; private int incomingInterruptFD;
static { static {
IOUtil.load();
initStructSizes(); initStructSizes();
String datamodel = java.security.AccessController.doPrivileged( String datamodel = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.arch.data.model") new sun.security.action.GetPropertyAction("sun.arch.data.model")

View File

@ -246,9 +246,4 @@ class KQueueSelectorImpl
} }
return this; return this;
} }
static {
Util.load();
}
} }

View File

@ -28,6 +28,12 @@
#include "util.h" #include "util.h"
#include "SDE.h" #include "SDE.h"
#ifdef __APPLE__
/* use setjmp/longjmp versions that do not save/restore the signal mask */
#define setjmp _setjmp
#define longjmp _longjmp
#endif
/** /**
* This SourceDebugExtension code does not * This SourceDebugExtension code does not
* allow concurrent translation - due to caching method. * allow concurrent translation - due to caching method.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -59,7 +59,7 @@ import java.io.IOException;
* {@link java.lang.instrument} for a detailed description on how these agents * {@link java.lang.instrument} for a detailed description on how these agents
* are loaded and started). The {@link #loadAgentLibrary loadAgentLibrary} and * are loaded and started). The {@link #loadAgentLibrary loadAgentLibrary} and
* {@link #loadAgentPath loadAgentPath} methods are used to load agents that * {@link #loadAgentPath loadAgentPath} methods are used to load agents that
* are deployed in a dynamic library and make use of the <a * are deployed either in a dynamic library or statically linked into the VM and make use of the <a
* href="../../../../../../../../technotes/guides/jvmti/index.html">JVM Tools * href="../../../../../../../../technotes/guides/jvmti/index.html">JVM Tools
* Interface</a>. </p> * Interface</a>. </p>
* *
@ -298,25 +298,29 @@ public abstract class VirtualMachine {
* <p> A <a href="../../../../../../../../technotes/guides/jvmti/index.html">JVM * <p> A <a href="../../../../../../../../technotes/guides/jvmti/index.html">JVM
* TI</a> client is called an <i>agent</i>. It is developed in a native language. * TI</a> client is called an <i>agent</i>. It is developed in a native language.
* A JVM TI agent is deployed in a platform specific manner but it is typically the * A JVM TI agent is deployed in a platform specific manner but it is typically the
* platform equivalent of a dynamic library. This method causes the given agent * platform equivalent of a dynamic library. Alternatively, it may be statically linked into the VM.
* library to be loaded into the target VM (if not already loaded). * This method causes the given agent library to be loaded into the target
* VM (if not already loaded or if not statically linked into the VM).
* It then causes the target VM to invoke the <code>Agent_OnAttach</code> function * It then causes the target VM to invoke the <code>Agent_OnAttach</code> function
* or, for a statically linked agent named 'L', the <code>Agent_OnAttach_L</code> function
* as specified in the * as specified in the
* <a href="../../../../../../../../technotes/guides/jvmti/index.html"> JVM Tools * <a href="../../../../../../../../technotes/guides/jvmti/index.html"> JVM Tools
* Interface</a> specification. Note that the <code>Agent_OnAttach</code> * Interface</a> specification. Note that the <code>Agent_OnAttach[_L]</code>
* function is invoked even if the agent library was loaded prior to invoking * function is invoked even if the agent library was loaded prior to invoking
* this method. * this method.
* *
* <p> The agent library provided is the name of the agent library. It is interpreted * <p> The agent library provided is the name of the agent library. It is interpreted
* in the target virtual machine in an implementation-dependent manner. Typically an * in the target virtual machine in an implementation-dependent manner. Typically an
* implementation will expand the library name into an operating system specific file * implementation will expand the library name into an operating system specific file
* name. For example, on UNIX systems, the name <tt>foo</tt> might be expanded to * name. For example, on UNIX systems, the name <tt>L</tt> might be expanded to
* <tt>libfoo.so</tt>, and located using the search path specified by the * <tt>libL.so</tt>, and located using the search path specified by the
* <tt>LD_LIBRARY_PATH</tt> environment variable.</p> * <tt>LD_LIBRARY_PATH</tt> environment variable. If the agent named 'L' is
* statically linked into the VM then the VM must export a function named
* <code>Agent_OnAttach_L</code>.</p>
* *
* <p> If the <code>Agent_OnAttach</code> function in the agent library returns * <p> If the <code>Agent_OnAttach[_L]</code> function in the agent library returns
* an error then an {@link com.sun.tools.attach.AgentInitializationException} is * an error then an {@link com.sun.tools.attach.AgentInitializationException} is
* thrown. The return value from the <code>Agent_OnAttach</code> can then be * thrown. The return value from the <code>Agent_OnAttach[_L]</code> can then be
* obtained by invoking the {@link * obtained by invoking the {@link
* com.sun.tools.attach.AgentInitializationException#returnValue() returnValue} * com.sun.tools.attach.AgentInitializationException#returnValue() returnValue}
* method on the exception. </p> * method on the exception. </p>
@ -325,15 +329,16 @@ public abstract class VirtualMachine {
* The name of the agent library. * The name of the agent library.
* *
* @param options * @param options
* The options to provide to the <code>Agent_OnAttach</code> * The options to provide to the <code>Agent_OnAttach[_L]</code>
* function (can be <code>null</code>). * function (can be <code>null</code>).
* *
* @throws AgentLoadException * @throws AgentLoadException
* If the agent library does not exist, or cannot be loaded for * If the agent library does not exist, the agent library is not
* another reason. * statically linked with the VM, or the agent library cannot be
* loaded for another reason.
* *
* @throws AgentInitializationException * @throws AgentInitializationException
* If the <code>Agent_OnAttach</code> function returns an error * If the <code>Agent_OnAttach[_L]</code> function returns an error.
* *
* @throws IOException * @throws IOException
* If an I/O error occurs * If an I/O error occurs
@ -359,11 +364,12 @@ public abstract class VirtualMachine {
* The name of the agent library. * The name of the agent library.
* *
* @throws AgentLoadException * @throws AgentLoadException
* If the agent library does not exist, or cannot be loaded for * If the agent library does not exist, the agent library is not
* another reason. * statically linked with the VM, or the agent library cannot be
* loaded for another reason.
* *
* @throws AgentInitializationException * @throws AgentInitializationException
* If the <code>Agent_OnAttach</code> function returns an error * If the <code>Agent_OnAttach[_L]</code> function returns an error.
* *
* @throws IOException * @throws IOException
* If an I/O error occurs * If an I/O error occurs
@ -383,12 +389,23 @@ public abstract class VirtualMachine {
* <p> A <a href="../../../../../../../../technotes/guides/jvmti/index.html">JVM * <p> A <a href="../../../../../../../../technotes/guides/jvmti/index.html">JVM
* TI</a> client is called an <i>agent</i>. It is developed in a native language. * TI</a> client is called an <i>agent</i>. It is developed in a native language.
* A JVM TI agent is deployed in a platform specific manner but it is typically the * A JVM TI agent is deployed in a platform specific manner but it is typically the
* platform equivalent of a dynamic library. This method causes the given agent * platform equivalent of a dynamic library. Alternatively, the native
* library to be loaded into the target VM (if not already loaded). * library specified by the agentPath parameter may be statically
* It then causes the target VM to invoke the <code>Agent_OnAttach</code> function * linked with the VM. The parsing of the agentPath parameter into
* as specified in the * a statically linked library name is done in a platform
* specific manner in the VM. For example, in UNIX, an agentPath parameter
* of <code>/a/b/libL.so</code> would name a library 'L'.
*
* See the JVM TI Specification for more details.
*
* This method causes the given agent library to be loaded into the target
* VM (if not already loaded or if not statically linked into the VM).
* It then causes the target VM to invoke the <code>Agent_OnAttach</code>
* function or, for a statically linked agent named 'L', the
* <code>Agent_OnAttach_L</code> function as specified in the
* <a href="../../../../../../../../technotes/guides/jvmti/index.html"> JVM Tools * <a href="../../../../../../../../technotes/guides/jvmti/index.html"> JVM Tools
* Interface</a> specification. Note that the <code>Agent_OnAttach</code> * Interface</a> specification.
* Note that the <code>Agent_OnAttach[_L]</code>
* function is invoked even if the agent library was loaded prior to invoking * function is invoked even if the agent library was loaded prior to invoking
* this method. * this method.
* *
@ -396,9 +413,9 @@ public abstract class VirtualMachine {
* agent library. Unlike {@link #loadAgentLibrary loadAgentLibrary}, the library name * agent library. Unlike {@link #loadAgentLibrary loadAgentLibrary}, the library name
* is not expanded in the target virtual machine. </p> * is not expanded in the target virtual machine. </p>
* *
* <p> If the <code>Agent_OnAttach</code> function in the agent library returns * <p> If the <code>Agent_OnAttach[_L]</code> function in the agent library returns
* an error then an {@link com.sun.tools.attach.AgentInitializationException} is * an error then an {@link com.sun.tools.attach.AgentInitializationException} is
* thrown. The return value from the <code>Agent_OnAttach</code> can then be * thrown. The return value from the <code>Agent_OnAttach[_L]</code> can then be
* obtained by invoking the {@link * obtained by invoking the {@link
* com.sun.tools.attach.AgentInitializationException#returnValue() returnValue} * com.sun.tools.attach.AgentInitializationException#returnValue() returnValue}
* method on the exception. </p> * method on the exception. </p>
@ -407,15 +424,16 @@ public abstract class VirtualMachine {
* The full path of the agent library. * The full path of the agent library.
* *
* @param options * @param options
* The options to provide to the <code>Agent_OnAttach</code> * The options to provide to the <code>Agent_OnAttach[_L]</code>
* function (can be <code>null</code>). * function (can be <code>null</code>).
* *
* @throws AgentLoadException * @throws AgentLoadException
* If the agent library does not exist, or cannot be loaded for * If the agent library does not exist, the agent library is not
* another reason. * statically linked with the VM, or the agent library cannot be
* loaded for another reason.
* *
* @throws AgentInitializationException * @throws AgentInitializationException
* If the <code>Agent_OnAttach</code> function returns an error * If the <code>Agent_OnAttach[_L]</code> function returns an error.
* *
* @throws IOException * @throws IOException
* If an I/O error occurs * If an I/O error occurs
@ -441,11 +459,12 @@ public abstract class VirtualMachine {
* The full path to the agent library. * The full path to the agent library.
* *
* @throws AgentLoadException * @throws AgentLoadException
* If the agent library does not exist, or cannot be loaded for * If the agent library does not exist, the agent library is not
* another reason. * statically linked with the VM, or the agent library cannot be
* loaded for another reason.
* *
* @throws AgentInitializationException * @throws AgentInitializationException
* If the <code>Agent_OnAttach</code> function returns an error * If the <code>Agent_OnAttach[_L]</code> function returns an error.
* *
* @throws IOException * @throws IOException
* If an I/O error occurs * If an I/O error occurs

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -50,7 +50,15 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
public public
class BufferedInputStream extends FilterInputStream { class BufferedInputStream extends FilterInputStream {
private static int defaultBufferSize = 8192; private static int DEFAULT_BUFFER_SIZE = 8192;
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
/** /**
* The internal buffer array where the data is stored. When necessary, * The internal buffer array where the data is stored. When necessary,
@ -172,7 +180,7 @@ class BufferedInputStream extends FilterInputStream {
* @param in the underlying input stream. * @param in the underlying input stream.
*/ */
public BufferedInputStream(InputStream in) { public BufferedInputStream(InputStream in) {
this(in, defaultBufferSize); this(in, DEFAULT_BUFFER_SIZE);
} }
/** /**
@ -215,8 +223,11 @@ class BufferedInputStream extends FilterInputStream {
} else if (buffer.length >= marklimit) { } else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */ markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */ pos = 0; /* drop buffer contents */
} else if (buffer.length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */ } else { /* grow buffer */
int nsz = pos * 2; int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit) if (nsz > marklimit)
nsz = marklimit; nsz = marklimit;
byte nbuf[] = new byte[nsz]; byte nbuf[] = new byte[nsz];

View File

@ -1307,7 +1307,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* specified substring, starting at the specified index. The integer * specified substring, starting at the specified index. The integer
* returned is the smallest value {@code k} for which: * returned is the smallest value {@code k} for which:
* <blockquote><pre> * <blockquote><pre>
* k >= Math.min(fromIndex, str.length()) && * k >= Math.min(fromIndex, this.length()) &&
* this.toString().startsWith(str, k) * this.toString().startsWith(str, k)
* </pre></blockquote> * </pre></blockquote>
* If no such value of <i>k</i> exists, then -1 is returned. * If no such value of <i>k</i> exists, then -1 is returned.
@ -1346,7 +1346,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* specified substring. The integer returned is the largest value <i>k</i> * specified substring. The integer returned is the largest value <i>k</i>
* such that: * such that:
* <blockquote><pre> * <blockquote><pre>
* k <= Math.min(fromIndex, str.length()) && * k <= Math.min(fromIndex, this.length()) &&
* this.toString().startsWith(str, k) * this.toString().startsWith(str, k)
* </pre></blockquote> * </pre></blockquote>
* If no such value of <i>k</i> exists, then -1 is returned. * If no such value of <i>k</i> exists, then -1 is returned.

View File

@ -3338,8 +3338,16 @@ public final class Class<T> implements java.io.Serializable,
* @since 1.8 * @since 1.8
*/ */
public AnnotatedType getAnnotatedSuperclass() { public AnnotatedType getAnnotatedSuperclass() {
return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this); if (this == Object.class ||
} isInterface() ||
isArray() ||
isPrimitive() ||
this == Void.TYPE) {
return null;
}
return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this);
}
/** /**
* Returns an array of AnnotatedType objects that represent the use of types to * Returns an array of AnnotatedType objects that represent the use of types to

View File

@ -698,11 +698,8 @@ public final class Math {
return 0; return 0;
} }
private static Random randomNumberGenerator; private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
private static synchronized Random initRNG() {
Random rnd = randomNumberGenerator;
return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
} }
/** /**
@ -729,9 +726,7 @@ public final class Math {
* @see Random#nextDouble() * @see Random#nextDouble()
*/ */
public static double random() { public static double random() {
Random rnd = randomNumberGenerator; return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
if (rnd == null) rnd = initRNG();
return rnd.nextDouble();
} }
/** /**

View File

@ -29,7 +29,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.AccessControlException;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -1033,9 +1032,9 @@ public final class ProcessBuilder
// Can not disclose the fail reason for read-protected files. // Can not disclose the fail reason for read-protected files.
try { try {
security.checkRead(prog); security.checkRead(prog);
} catch (AccessControlException ace) { } catch (SecurityException se) {
exceptionInfo = ""; exceptionInfo = "";
cause = ace; cause = se;
} }
} }
// It's much easier for us to create a high-quality error // It's much easier for us to create a high-quality error

View File

@ -678,11 +678,8 @@ public final class StrictMath {
return Math.round(a); return Math.round(a);
} }
private static Random randomNumberGenerator; private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
private static synchronized Random initRNG() {
Random rnd = randomNumberGenerator;
return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
} }
/** /**
@ -709,9 +706,7 @@ public final class StrictMath {
* @see Random#nextDouble() * @see Random#nextDouble()
*/ */
public static double random() { public static double random() {
Random rnd = randomNumberGenerator; return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
if (rnd == null) rnd = initRNG();
return rnd.nextDouble();
} }
/** /**

View File

@ -2659,28 +2659,32 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (ys == 0) if (ys == 0)
return 1; return 1;
int sdiff = this.scale - val.scale; long sdiff = (long)this.scale - val.scale;
if (sdiff != 0) { if (sdiff != 0) {
// Avoid matching scales if the (adjusted) exponents differ // Avoid matching scales if the (adjusted) exponents differ
int xae = this.precision() - this.scale; // [-1] long xae = (long)this.precision() - this.scale; // [-1]
int yae = val.precision() - val.scale; // [-1] long yae = (long)val.precision() - val.scale; // [-1]
if (xae < yae) if (xae < yae)
return -1; return -1;
if (xae > yae) if (xae > yae)
return 1; return 1;
BigInteger rb = null; BigInteger rb = null;
if (sdiff < 0) { if (sdiff < 0) {
if ( (xs == INFLATED || // The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
(xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) && if ( sdiff > Integer.MIN_VALUE &&
(xs == INFLATED ||
(xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
ys == INFLATED) { ys == INFLATED) {
rb = bigMultiplyPowerTen(-sdiff); rb = bigMultiplyPowerTen((int)-sdiff);
return rb.compareMagnitude(val.intVal); return rb.compareMagnitude(val.intVal);
} }
} else { // sdiff > 0 } else { // sdiff > 0
if ( (ys == INFLATED || // The cases sdiff > Integer.MAX_VALUE intentionally fall through.
(ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) && if ( sdiff <= Integer.MAX_VALUE &&
(ys == INFLATED ||
(ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
xs == INFLATED) { xs == INFLATED) {
rb = val.bigMultiplyPowerTen(sdiff); rb = val.bigMultiplyPowerTen((int)sdiff);
return this.intVal.compareMagnitude(rb); return this.intVal.compareMagnitude(rb);
} }
} }
@ -4545,7 +4549,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if(cmp > 0) { // satisfy constraint (b) if(cmp > 0) { // satisfy constraint (b)
yscale -= 1; // [that is, divisor *= 10] yscale -= 1; // [that is, divisor *= 10]
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) { if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
// assert newScale >= xscale // assert newScale >= xscale
int raise = checkScaleNonZero((long) mcp + yscale - xscale); int raise = checkScaleNonZero((long) mcp + yscale - xscale);
long scaledXs; long scaledXs;
@ -4626,7 +4630,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// return BigDecimal object whose scale will be set to 'scl'. // return BigDecimal object whose scale will be set to 'scl'.
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
BigDecimal quotient; BigDecimal quotient;
if (checkScaleNonZero((long) mcp + yscale) > xscale) { if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale); int raise = checkScaleNonZero((long) mcp + yscale - xscale);
long scaledXs; long scaledXs;
if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) { if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
@ -4673,7 +4677,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// return BigDecimal object whose scale will be set to 'scl'. // return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient; BigDecimal quotient;
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) { if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale); int raise = checkScaleNonZero((long) mcp + yscale - xscale);
BigInteger rb = bigMultiplyPowerTen(xs,raise); BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
@ -4714,7 +4718,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// return BigDecimal object whose scale will be set to 'scl'. // return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient; BigDecimal quotient;
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) { if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale); int raise = checkScaleNonZero((long) mcp + yscale - xscale);
BigInteger rb = bigMultiplyPowerTen(xs,raise); BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
@ -4745,7 +4749,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// return BigDecimal object whose scale will be set to 'scl'. // return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient; BigDecimal quotient;
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) { if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale); int raise = checkScaleNonZero((long) mcp + yscale - xscale);
BigInteger rb = bigMultiplyPowerTen(xs,raise); BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));

View File

@ -2109,7 +2109,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
// This is a quick way to approximate the size of the result, // This is a quick way to approximate the size of the result,
// similar to doing log2[n] * exponent. This will give an upper bound // similar to doing log2[n] * exponent. This will give an upper bound
// of how big the result can be, and which algorithm to use. // of how big the result can be, and which algorithm to use.
int scaleFactor = remainingBits * exponent; long scaleFactor = (long)remainingBits * exponent;
// Use slightly different algorithms for small and large operands. // Use slightly different algorithms for small and large operands.
// See if the result will safely fit into a long. (Largest 2^63-1) // See if the result will safely fit into a long. (Largest 2^63-1)

View File

@ -50,13 +50,13 @@ import java.net.*;
* @implNote * @implNote
* <p>You can use the {@code RMISocketFactory} class to create a server socket that * <p>You can use the {@code RMISocketFactory} class to create a server socket that
* is bound to a specific address, restricting the origin of requests. For example, * is bound to a specific address, restricting the origin of requests. For example,
* the following code implements a socket factory that binds server sockets to the * the following code implements a socket factory that binds server sockets to an IPv4
* loopback address. This restricts RMI to processing requests only from the local host. * loopback address. This restricts RMI to processing requests only from the local host.
* *
* <pre>{@code * <pre>{@code
* class LoopbackSocketFactory extends RMISocketFactory { * class LoopbackSocketFactory extends RMISocketFactory {
* public ServerSocket createServerSocket(int port) throws IOException { * public ServerSocket createServerSocket(int port) throws IOException {
* return new ServerSocket(port, 5, InetAddress.getLoopbackAddress()); * return new ServerSocket(port, 5, InetAddress.getByName("127.0.0.1"));
* } * }
* *
* public Socket createSocket(String host, int port) throws IOException { * public Socket createSocket(String host, int port) throws IOException {
@ -72,8 +72,8 @@ import java.net.*;
* }</pre> * }</pre>
* *
* Set the {@code java.rmi.server.hostname} system property * Set the {@code java.rmi.server.hostname} system property
* to a host name (typically {@code localhost}) that resolves to the loopback * to {@code 127.0.0.1} to ensure that the generated stubs connect to the right
* interface to ensure that the generated stubs use the right network interface. * network interface.
* *
* @author Ann Wollrath * @author Ann Wollrath
* @author Peter Jones * @author Peter Jones

View File

@ -27,7 +27,6 @@ package java.util;
import java.io.Serializable; import java.io.Serializable;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InvalidObjectException;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@ -35,6 +34,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
@ -1148,7 +1148,16 @@ public class Collections {
public Spliterator<E> spliterator() { public Spliterator<E> spliterator() {
return (Spliterator<E>)c.spliterator(); return (Spliterator<E>)c.spliterator();
} }
@SuppressWarnings("unchecked")
@Override
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> parallelStream() {
return (Stream<E>)c.parallelStream();
}
} }
/** /**
@ -2009,8 +2018,8 @@ public class Collections {
* through the returned collection.<p> * through the returned collection.<p>
* *
* It is imperative that the user manually synchronize on the returned * It is imperative that the user manually synchronize on the returned
* collection when traversing it via {@link Iterator} or * collection when traversing it via {@link Iterator}, {@link Spliterator}
* {@link Spliterator}: * or {@link Stream}:
* <pre> * <pre>
* Collection c = Collections.synchronizedCollection(myCollection); * Collection c = Collections.synchronizedCollection(myCollection);
* ... * ...
@ -2120,6 +2129,14 @@ public class Collections {
public Spliterator<E> spliterator() { public Spliterator<E> spliterator() {
return c.spliterator(); // Must be manually synched by user! return c.spliterator(); // Must be manually synched by user!
} }
@Override
public Stream<E> stream() {
return c.stream(); // Must be manually synched by user!
}
@Override
public Stream<E> parallelStream() {
return c.parallelStream(); // Must be manually synched by user!
}
private void writeObject(ObjectOutputStream s) throws IOException { private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();} synchronized (mutex) {s.defaultWriteObject();}
} }
@ -3172,6 +3189,10 @@ public class Collections {
} }
@Override @Override
public Spliterator<E> spliterator() {return c.spliterator();} public Spliterator<E> spliterator() {return c.spliterator();}
@Override
public Stream<E> stream() {return c.stream();}
@Override
public Stream<E> parallelStream() {return c.parallelStream();}
} }
/** /**
@ -5096,6 +5117,22 @@ public class Collections {
") > toIndex(" + toIndex + ")"); ") > toIndex(" + toIndex + ")");
return new CopiesList<>(toIndex - fromIndex, element); return new CopiesList<>(toIndex - fromIndex, element);
} }
// Override default methods in Collection
@Override
public Stream<E> stream() {
return IntStream.range(0, n).mapToObj(i -> element);
}
@Override
public Stream<E> parallelStream() {
return IntStream.range(0, n).parallel().mapToObj(i -> element);
}
@Override
public Spliterator<E> spliterator() {
return stream().spliterator();
}
} }
/** /**
@ -5503,6 +5540,10 @@ public class Collections {
@Override @Override
public Spliterator<E> spliterator() {return s.spliterator();} public Spliterator<E> spliterator() {return s.spliterator();}
@Override
public Stream<E> stream() {return s.stream();}
@Override
public Stream<E> parallelStream() {return s.parallelStream();}
private static final long serialVersionUID = 2454657854757543876L; private static final long serialVersionUID = 2454657854757543876L;
@ -5568,10 +5609,14 @@ public class Collections {
@Override @Override
public void forEach(Consumer<? super E> action) {q.forEach(action);} public void forEach(Consumer<? super E> action) {q.forEach(action);}
@Override @Override
public Spliterator<E> spliterator() {return q.spliterator();}
@Override
public boolean removeIf(Predicate<? super E> filter) { public boolean removeIf(Predicate<? super E> filter) {
return q.removeIf(filter); return q.removeIf(filter);
} }
@Override
public Spliterator<E> spliterator() {return q.spliterator();}
@Override
public Stream<E> stream() {return q.stream();}
@Override
public Stream<E> parallelStream() {return q.parallelStream();}
} }
} }

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright 2009 Google Inc. All Rights Reserved. * Copyright 2009 Google Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -146,7 +147,7 @@ class ComparableTimSort {
*/ */
int stackLen = (len < 120 ? 5 : int stackLen = (len < 120 ? 5 :
len < 1542 ? 10 : len < 1542 ? 10 :
len < 119151 ? 19 : 40); len < 119151 ? 24 : 40);
runBase = new int[stackLen]; runBase = new int[stackLen];
runLen = new int[stackLen]; runLen = new int[stackLen];
} }

View File

@ -199,7 +199,7 @@ public interface Comparator<T> {
* composed using following code, * composed using following code,
* *
* <pre>{@code * <pre>{@code
* Comparator<String> cmp = Comparator.comparing(String::length) * Comparator<String> cmp = Comparator.comparingInt(String::length)
* .thenComparing(String.CASE_INSENSITIVE_ORDER); * .thenComparing(String.CASE_INSENSITIVE_ORDER);
* }</pre> * }</pre>
* *
@ -270,18 +270,18 @@ public interface Comparator<T> {
* extracts a {@code int} sort key. * extracts a {@code int} sort key.
* *
* @implSpec This default implementation behaves as if {@code * @implSpec This default implementation behaves as if {@code
* thenComparing(comparing(keyExtractor))}. * thenComparing(comparingInt(keyExtractor))}.
* *
* @param keyExtractor the function used to extract the integer sort key * @param keyExtractor the function used to extract the integer sort key
* @return a lexicographic-order comparator composed of this and then the * @return a lexicographic-order comparator composed of this and then the
* {@code int} sort key * {@code int} sort key
* @throws NullPointerException if the argument is null. * @throws NullPointerException if the argument is null.
* @see #comparing(ToIntFunction) * @see #comparingInt(ToIntFunction)
* @see #thenComparing(Comparator) * @see #thenComparing(Comparator)
* @since 1.8 * @since 1.8
*/ */
default Comparator<T> thenComparing(ToIntFunction<? super T> keyExtractor) { default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
return thenComparing(comparing(keyExtractor)); return thenComparing(comparingInt(keyExtractor));
} }
/** /**
@ -289,18 +289,18 @@ public interface Comparator<T> {
* extracts a {@code long} sort key. * extracts a {@code long} sort key.
* *
* @implSpec This default implementation behaves as if {@code * @implSpec This default implementation behaves as if {@code
* thenComparing(comparing(keyExtractor))}. * thenComparing(comparingLong(keyExtractor))}.
* *
* @param keyExtractor the function used to extract the long sort key * @param keyExtractor the function used to extract the long sort key
* @return a lexicographic-order comparator composed of this and then the * @return a lexicographic-order comparator composed of this and then the
* {@code long} sort key * {@code long} sort key
* @throws NullPointerException if the argument is null. * @throws NullPointerException if the argument is null.
* @see #comparing(ToLongFunction) * @see #comparingLong(ToLongFunction)
* @see #thenComparing(Comparator) * @see #thenComparing(Comparator)
* @since 1.8 * @since 1.8
*/ */
default Comparator<T> thenComparing(ToLongFunction<? super T> keyExtractor) { default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
return thenComparing(comparing(keyExtractor)); return thenComparing(comparingLong(keyExtractor));
} }
/** /**
@ -308,18 +308,18 @@ public interface Comparator<T> {
* extracts a {@code double} sort key. * extracts a {@code double} sort key.
* *
* @implSpec This default implementation behaves as if {@code * @implSpec This default implementation behaves as if {@code
* thenComparing(comparing(keyExtractor))}. * thenComparing(comparingDouble(keyExtractor))}.
* *
* @param keyExtractor the function used to extract the double sort key * @param keyExtractor the function used to extract the double sort key
* @return a lexicographic-order comparator composed of this and then the * @return a lexicographic-order comparator composed of this and then the
* {@code double} sort key * {@code double} sort key
* @throws NullPointerException if the argument is null. * @throws NullPointerException if the argument is null.
* @see #comparing(ToDoubleFunction) * @see #comparingDouble(ToDoubleFunction)
* @see #thenComparing(Comparator) * @see #thenComparing(Comparator)
* @since 1.8 * @since 1.8
*/ */
default Comparator<T> thenComparing(ToDoubleFunction<? super T> keyExtractor) { default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
return thenComparing(comparing(keyExtractor)); return thenComparing(comparingDouble(keyExtractor));
} }
/** /**
@ -484,7 +484,7 @@ public interface Comparator<T> {
* @throws NullPointerException if the argument is null * @throws NullPointerException if the argument is null
* @since 1.8 * @since 1.8
*/ */
public static <T> Comparator<T> comparing(ToIntFunction<? super T> keyExtractor) { public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) return (Comparator<T> & Serializable)
(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
@ -505,7 +505,7 @@ public interface Comparator<T> {
* @throws NullPointerException if the argument is null * @throws NullPointerException if the argument is null
* @since 1.8 * @since 1.8
*/ */
public static <T> Comparator<T> comparing(ToLongFunction<? super T> keyExtractor) { public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) return (Comparator<T> & Serializable)
(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
@ -526,7 +526,7 @@ public interface Comparator<T> {
* @throws NullPointerException if the argument is null * @throws NullPointerException if the argument is null
* @since 1.8 * @since 1.8
*/ */
public static<T> Comparator<T> comparing(ToDoubleFunction<? super T> keyExtractor) { public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) return (Comparator<T> & Serializable)
(c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));

View File

@ -26,9 +26,13 @@
package java.util; package java.util;
import java.io.*; import java.io.*;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
import java.util.stream.DoubleStream; import java.util.stream.DoubleStream;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.LongStream; import java.util.stream.LongStream;
import java.util.stream.StreamSupport;
import sun.misc.Unsafe; import sun.misc.Unsafe;
@ -85,6 +89,13 @@ class Random implements java.io.Serializable {
private static final long addend = 0xBL; private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1; private static final long mask = (1L << 48) - 1;
private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
// IllegalArgumentException messages
static final String BadBound = "bound must be positive";
static final String BadRange = "bound must be greater than origin";
static final String BadSize = "size must be non-negative";
/** /**
* Creates a new random number generator. This constructor sets * Creates a new random number generator. This constructor sets
* the seed of the random number generator to a value very likely * the seed of the random number generator to a value very likely
@ -221,6 +232,82 @@ class Random implements java.io.Serializable {
bytes[i++] = (byte)rnd; bytes[i++] = (byte)rnd;
} }
/**
* The form of nextLong used by LongStream Spliterators. If
* origin is greater than bound, acts as unbounded form of
* nextLong, else as bounded form.
*
* @param origin the least value, unless greater than bound
* @param bound the upper bound (exclusive), must not equal origin
* @return a pseudorandom value
*/
final long internalNextLong(long origin, long bound) {
long r = nextLong();
if (origin < bound) {
long n = bound - origin, m = n - 1;
if ((n & m) == 0L) // power of two
r = (r & m) + origin;
else if (n > 0L) { // reject over-represented candidates
for (long u = r >>> 1; // ensure nonnegative
u + m - (r = u % n) < 0L; // rejection check
u = nextLong() >>> 1) // retry
;
r += origin;
}
else { // range not representable as long
while (r < origin || r >= bound)
r = nextLong();
}
}
return r;
}
/**
* The form of nextInt used by IntStream Spliterators.
* For the unbounded case: uses nextInt().
* For the bounded case with representable range: uses nextInt(int bound)
* For the bounded case with unrepresentable range: uses nextInt()
*
* @param origin the least value, unless greater than bound
* @param bound the upper bound (exclusive), must not equal origin
* @return a pseudorandom value
*/
final int internalNextInt(int origin, int bound) {
if (origin < bound) {
int n = bound - origin;
if (n > 0) {
return nextInt(n) + origin;
}
else { // range not representable as int
int r;
do {
r = nextInt();
} while (r < origin || r >= bound);
return r;
}
}
else {
return nextInt();
}
}
/**
* The form of nextDouble used by DoubleStream Spliterators.
*
* @param origin the least value, unless greater than bound
* @param bound the upper bound (exclusive), must not equal origin
* @return a pseudorandom value
*/
final double internalNextDouble(double origin, double bound) {
double r = nextDouble();
if (origin < bound) {
r = r * (bound - origin) + origin;
if (r >= bound) // correct for rounding
r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
}
return r;
}
/** /**
* Returns the next pseudorandom, uniformly distributed {@code int} * Returns the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence. The general * value from this random number generator's sequence. The general
@ -247,23 +334,23 @@ class Random implements java.io.Serializable {
* between 0 (inclusive) and the specified value (exclusive), drawn from * between 0 (inclusive) and the specified value (exclusive), drawn from
* this random number generator's sequence. The general contract of * this random number generator's sequence. The general contract of
* {@code nextInt} is that one {@code int} value in the specified range * {@code nextInt} is that one {@code int} value in the specified range
* is pseudorandomly generated and returned. All {@code n} possible * is pseudorandomly generated and returned. All {@code bound} possible
* {@code int} values are produced with (approximately) equal * {@code int} values are produced with (approximately) equal
* probability. The method {@code nextInt(int n)} is implemented by * probability. The method {@code nextInt(int bound)} is implemented by
* class {@code Random} as if by: * class {@code Random} as if by:
* <pre> {@code * <pre> {@code
* public int nextInt(int n) { * public int nextInt(int bound) {
* if (n <= 0) * if (bound <= 0)
* throw new IllegalArgumentException("n must be positive"); * throw new IllegalArgumentException("bound must be positive");
* *
* if ((n & -n) == n) // i.e., n is a power of 2 * if ((bound & -bound) == bound) // i.e., bound is a power of 2
* return (int)((n * (long)next(31)) >> 31); * return (int)((bound * (long)next(31)) >> 31);
* *
* int bits, val; * int bits, val;
* do { * do {
* bits = next(31); * bits = next(31);
* val = bits % n; * val = bits % bound;
* } while (bits - val + (n-1) < 0); * } while (bits - val + (bound-1) < 0);
* return val; * return val;
* }}</pre> * }}</pre>
* *
@ -289,28 +376,28 @@ class Random implements java.io.Serializable {
* greatly increases the length of the sequence of values returned by * greatly increases the length of the sequence of values returned by
* successive calls to this method if n is a small power of two. * successive calls to this method if n is a small power of two.
* *
* @param n the bound on the random number to be returned. Must be * @param bound the upper bound (exclusive). Must be positive.
* positive.
* @return the next pseudorandom, uniformly distributed {@code int} * @return the next pseudorandom, uniformly distributed {@code int}
* value between {@code 0} (inclusive) and {@code n} (exclusive) * value between zero (inclusive) and {@code bound} (exclusive)
* from this random number generator's sequence * from this random number generator's sequence
* @throws IllegalArgumentException if n is not positive * @throws IllegalArgumentException if bound is not positive
* @since 1.2 * @since 1.2
*/ */
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
public int nextInt(int n) { int r = next(31);
if (n <= 0) int m = bound - 1;
throw new IllegalArgumentException("n must be positive"); if ((bound & m) == 0) // i.e., bound is a power of 2
r = (int)((bound * (long)r) >> 31);
if ((n & -n) == n) // i.e., n is a power of 2 else {
return (int)((n * (long)next(31)) >> 31); for (int u = r;
u - (r = u % bound) + m < 0;
int bits, val; u = next(31))
do { ;
bits = next(31); }
val = bits % n; return r;
} while (bits - val + (n-1) < 0);
return val;
} }
/** /**
@ -442,8 +529,7 @@ class Random implements java.io.Serializable {
* @see Math#random * @see Math#random
*/ */
public double nextDouble() { public double nextDouble() {
return (((long)(next(26)) << 27) + next(27)) return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
/ (double)(1L << 53);
} }
private double nextNextGaussian; private double nextNextGaussian;
@ -513,57 +599,563 @@ class Random implements java.io.Serializable {
} }
} }
// stream methods, coded in a way intended to better isolate for
// maintenance purposes the small differences across forms.
/** /**
* Returns a stream of pseudorandom, uniformly distributed * Returns a stream producing the given {@code streamSize} number of
* {@code integer} values from this random number generator's * pseudorandom {@code int} values.
* sequence. Values are obtained as needed by calling
* {@link #nextInt()}.
* *
* @return an infinite stream of {@code integer} values * <p>A pseudorandom {@code int} value is generated as if it's the result of
* calling the method {@link #nextInt()}.
*
* @param streamSize the number of values to generate
* @return a stream of pseudorandom {@code int} values
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @since 1.8
*/
public IntStream ints(long streamSize) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, streamSize, Integer.MAX_VALUE, 0),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code int}
* values.
*
* <p>A pseudorandom {@code int} value is generated as if it's the result of
* calling the method {@link #nextInt()}.
*
* @implNote This method is implemented to be equivalent to {@code
* ints(Long.MAX_VALUE)}.
*
* @return a stream of pseudorandom {@code int} values
* @since 1.8 * @since 1.8
*/ */
public IntStream ints() { public IntStream ints() {
return IntStream.generate(this::nextInt); return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
false);
} }
/** /**
* Returns a stream of pseudorandom, uniformly distributed * Returns a stream producing the given {@code streamSize} number
* {@code long} values from this random number generator's * of pseudorandom {@code int} values, each conforming to the given
* sequence. Values are obtained as needed by calling * origin (inclusive) and bound (exclusive).
* {@link #nextLong()}.
* *
* @return an infinite stream of {@code long} values * <p>A pseudorandom {@code int} value is generated as if it's the result of
* calling the following method with the origin and bound:
* <pre> {@code
* int nextInt(int origin, int bound) {
* int n = bound - origin;
* if (n > 0) {
* return nextInt(n) + origin;
* }
* else { // range not representable as int
* int r;
* do {
* r = nextInt();
* } while (r < origin || r >= bound);
* return r;
* }
* }}</pre>
*
* @param streamSize the number of values to generate
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code int} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero, or {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public IntStream ints(long streamSize, int randomNumberOrigin,
int randomNumberBound) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* int} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* <p>A pseudorandom {@code int} value is generated as if it's the result of
* calling the following method with the origin and bound:
* <pre> {@code
* int nextInt(int origin, int bound) {
* int n = bound - origin;
* if (n > 0) {
* return nextInt(n) + origin;
* }
* else { // range not representable as int
* int r;
* do {
* r = nextInt();
* } while (r < origin || r >= bound);
* return r;
* }
* }}</pre>
*
* @implNote This method is implemented to be equivalent to {@code
* ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code int} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code long} values.
*
* <p>A pseudorandom {@code long} value is generated as if it's the result
* of calling the method {@link #nextLong()}.
*
* @param streamSize the number of values to generate
* @return a stream of pseudorandom {@code long} values
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @since 1.8
*/
public LongStream longs(long streamSize) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, streamSize, Long.MAX_VALUE, 0L),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code long}
* values.
*
* <p>A pseudorandom {@code long} value is generated as if it's the result
* of calling the method {@link #nextLong()}.
*
* @implNote This method is implemented to be equivalent to {@code
* longs(Long.MAX_VALUE)}.
*
* @return a stream of pseudorandom {@code long} values
* @since 1.8 * @since 1.8
*/ */
public LongStream longs() { public LongStream longs() {
return LongStream.generate(this::nextLong); return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
false);
} }
/** /**
* Returns a stream of pseudorandom, uniformly distributed * Returns a stream producing the given {@code streamSize} number of
* {@code double} values between {@code 0.0} and {@code 1.0} * pseudorandom {@code long}, each conforming to the given origin
* from this random number generator's sequence. Values are * (inclusive) and bound (exclusive).
* obtained as needed by calling {@link #nextDouble()}.
* *
* @return an infinite stream of {@code double} values * <p>A pseudorandom {@code long} value is generated as if it's the result
* of calling the following method with the origin and bound:
* <pre> {@code
* long nextLong(long origin, long bound) {
* long r = nextLong();
* long n = bound - origin, m = n - 1;
* if ((n & m) == 0L) // power of two
* r = (r & m) + origin;
* else if (n > 0L) { // reject over-represented candidates
* for (long u = r >>> 1; // ensure nonnegative
* u + m - (r = u % n) < 0L; // rejection check
* u = nextLong() >>> 1) // retry
* ;
* r += origin;
* }
* else { // range not representable as long
* while (r < origin || r >= bound)
* r = nextLong();
* }
* return r;
* }}</pre>
*
* @param streamSize the number of values to generate
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code long} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero, or {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public LongStream longs(long streamSize, long randomNumberOrigin,
long randomNumberBound) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* long} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* <p>A pseudorandom {@code long} value is generated as if it's the result
* of calling the following method with the origin and bound:
* <pre> {@code
* long nextLong(long origin, long bound) {
* long r = nextLong();
* long n = bound - origin, m = n - 1;
* if ((n & m) == 0L) // power of two
* r = (r & m) + origin;
* else if (n > 0L) { // reject over-represented candidates
* for (long u = r >>> 1; // ensure nonnegative
* u + m - (r = u % n) < 0L; // rejection check
* u = nextLong() >>> 1) // retry
* ;
* r += origin;
* }
* else { // range not representable as long
* while (r < origin || r >= bound)
* r = nextLong();
* }
* return r;
* }}</pre>
*
* @implNote This method is implemented to be equivalent to {@code
* longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code long} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code double} values, each between zero
* (inclusive) and one (exclusive).
*
* <p>A pseudorandom {@code double} value is generated as if it's the result
* of calling the method {@link #nextDouble()}}.
*
* @param streamSize the number of values to generate
* @return a stream of {@code double} values
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @since 1.8
*/
public DoubleStream doubles(long streamSize) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, streamSize, Double.MAX_VALUE, 0.0),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* double} values, each between zero (inclusive) and one
* (exclusive).
*
* <p>A pseudorandom {@code double} value is generated as if it's the result
* of calling the method {@link #nextDouble()}}.
*
* @implNote This method is implemented to be equivalent to {@code
* doubles(Long.MAX_VALUE)}.
*
* @return a stream of pseudorandom {@code double} values
* @since 1.8 * @since 1.8
*/ */
public DoubleStream doubles() { public DoubleStream doubles() {
return DoubleStream.generate(this::nextDouble); return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
false);
} }
/** /**
* Returns a stream of pseudorandom, Gaussian ("normally") * Returns a stream producing the given {@code streamSize} number of
* distributed {@code double} values with mean {@code 0.0} * pseudorandom {@code double} values, each conforming to the given origin
* and standard deviation {@code 1.0} from this random number * (inclusive) and bound (exclusive).
* generator's sequence. Values are obtained as needed by
* calling {@link #nextGaussian()}.
* *
* @return an infinite stream of {@code double} values * <p>A pseudorandom {@code double} value is generated as if it's the result
* of calling the following method with the origin and bound:
* <pre> {@code
* double nextDouble(double origin, double bound) {
* double r = nextDouble();
* r = r * (bound - origin) + origin;
* if (r >= bound) // correct for rounding
* r = Math.nextDown(bound);
* return r;
* }}</pre>
*
* @param streamSize the number of values to generate
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code double} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8 * @since 1.8
*/ */
public DoubleStream gaussians() { public DoubleStream doubles(long streamSize, double randomNumberOrigin,
return DoubleStream.generate(this::nextGaussian); double randomNumberBound) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
if (!(randomNumberOrigin < randomNumberBound))
throw new IllegalArgumentException(BadRange);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* double} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* <p>A pseudorandom {@code double} value is generated as if it's the result
* of calling the following method with the origin and bound:
* <pre> {@code
* double nextDouble(double origin, double bound) {
* double r = nextDouble();
* r = r * (bound - origin) + origin;
* if (r >= bound) // correct for rounding
* r = Math.nextDown(bound);
* return r;
* }}</pre>
*
* @implNote This method is implemented to be equivalent to {@code
* doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code double} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
if (!(randomNumberOrigin < randomNumberBound))
throw new IllegalArgumentException(BadRange);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Spliterator for int streams. We multiplex the four int
* versions into one class by treating a bound less than origin as
* unbounded, and also by treating "infinite" as equivalent to
* Long.MAX_VALUE. For splits, it uses the standard divide-by-two
* approach. The long and double versions of this class are
* identical except for types.
*/
static final class RandomIntsSpliterator implements Spliterator.OfInt {
final Random rng;
long index;
final long fence;
final int origin;
final int bound;
RandomIntsSpliterator(Random rng, long index, long fence,
int origin, int bound) {
this.rng = rng; this.index = index; this.fence = fence;
this.origin = origin; this.bound = bound;
}
public RandomIntsSpliterator trySplit() {
long i = index, m = (i + fence) >>> 1;
return (m <= i) ? null :
new RandomIntsSpliterator(rng, i, index = m, origin, bound);
}
public long estimateSize() {
return fence - index;
}
public int characteristics() {
return (Spliterator.SIZED | Spliterator.SUBSIZED |
Spliterator.NONNULL | Spliterator.IMMUTABLE);
}
public boolean tryAdvance(IntConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
consumer.accept(rng.internalNextInt(origin, bound));
index = i + 1;
return true;
}
return false;
}
public void forEachRemaining(IntConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
index = f;
Random r = rng;
int o = origin, b = bound;
do {
consumer.accept(r.internalNextInt(o, b));
} while (++i < f);
}
}
}
/**
* Spliterator for long streams.
*/
static final class RandomLongsSpliterator implements Spliterator.OfLong {
final Random rng;
long index;
final long fence;
final long origin;
final long bound;
RandomLongsSpliterator(Random rng, long index, long fence,
long origin, long bound) {
this.rng = rng; this.index = index; this.fence = fence;
this.origin = origin; this.bound = bound;
}
public RandomLongsSpliterator trySplit() {
long i = index, m = (i + fence) >>> 1;
return (m <= i) ? null :
new RandomLongsSpliterator(rng, i, index = m, origin, bound);
}
public long estimateSize() {
return fence - index;
}
public int characteristics() {
return (Spliterator.SIZED | Spliterator.SUBSIZED |
Spliterator.NONNULL | Spliterator.IMMUTABLE);
}
public boolean tryAdvance(LongConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
consumer.accept(rng.internalNextLong(origin, bound));
index = i + 1;
return true;
}
return false;
}
public void forEachRemaining(LongConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
index = f;
Random r = rng;
long o = origin, b = bound;
do {
consumer.accept(r.internalNextLong(o, b));
} while (++i < f);
}
}
}
/**
* Spliterator for double streams.
*/
static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
final Random rng;
long index;
final long fence;
final double origin;
final double bound;
RandomDoublesSpliterator(Random rng, long index, long fence,
double origin, double bound) {
this.rng = rng; this.index = index; this.fence = fence;
this.origin = origin; this.bound = bound;
}
public RandomDoublesSpliterator trySplit() {
long i = index, m = (i + fence) >>> 1;
return (m <= i) ? null :
new RandomDoublesSpliterator(rng, i, index = m, origin, bound);
}
public long estimateSize() {
return fence - index;
}
public int characteristics() {
return (Spliterator.SIZED | Spliterator.SUBSIZED |
Spliterator.NONNULL | Spliterator.IMMUTABLE);
}
public boolean tryAdvance(DoubleConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
consumer.accept(rng.internalNextDouble(origin, bound));
index = i + 1;
return true;
}
return false;
}
public void forEachRemaining(DoubleConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
index = f;
Random r = rng;
double o = origin, b = bound;
do {
consumer.accept(r.internalNextDouble(o, b));
} while (++i < f);
}
}
} }
/** /**

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright 2009 Google Inc. All Rights Reserved. * Copyright 2009 Google Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -176,7 +177,7 @@ class TimSort<T> {
*/ */
int stackLen = (len < 120 ? 5 : int stackLen = (len < 120 ? 5 :
len < 1542 ? 10 : len < 1542 ? 10 :
len < 119151 ? 19 : 40); len < 119151 ? 24 : 40);
runBase = new int[stackLen]; runBase = new int[stackLen];
runLen = new int[stackLen]; runLen = new int[stackLen];
} }

View File

@ -972,6 +972,27 @@ public class TreeMap<K,V>
return tailMap(fromKey, true); return tailMap(fromKey, true);
} }
@Override
public boolean replace(K key, V oldValue, V newValue) {
Entry<K,V> p = getEntry(key);
if (p!=null && Objects.equals(oldValue, p.value)) {
p.value = newValue;
return true;
}
return false;
}
@Override
public V replace(K key, V value) {
Entry<K,V> p = getEntry(key);
if (p!=null) {
V oldValue = p.value;
p.value = value;
return oldValue;
}
return null;
}
@Override @Override
public void forEach(BiConsumer<? super K, ? super V> action) { public void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action); Objects.requireNonNull(action);

View File

@ -37,11 +37,16 @@ package java.util.concurrent;
import java.io.ObjectStreamField; import java.io.ObjectStreamField;
import java.util.Random; import java.util.Random;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
import java.util.stream.DoubleStream; import java.util.stream.DoubleStream;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.LongStream; import java.util.stream.LongStream;
import java.util.stream.StreamSupport;
/** /**
* A random number generator isolated to the current thread. Like the * A random number generator isolated to the current thread. Like the
@ -64,6 +69,10 @@ import java.util.stream.LongStream;
* <p>This class also provides additional commonly used bounded random * <p>This class also provides additional commonly used bounded random
* generation methods. * generation methods.
* *
* <p>Instances of {@code ThreadLocalRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications.
*
* @since 1.7 * @since 1.7
* @author Doug Lea * @author Doug Lea
*/ */
@ -85,28 +94,26 @@ public class ThreadLocalRandom extends Random {
* application-level overhead and footprint of most concurrent * application-level overhead and footprint of most concurrent
* programs. * programs.
* *
* Even though this class subclasses java.util.Random, it uses the
* same basic algorithm as java.util.SplittableRandom. (See its
* internal documentation for explanations, which are not repeated
* here.) Because ThreadLocalRandoms are not splittable
* though, we use only a single 64bit gamma.
*
* Because this class is in a different package than class Thread, * Because this class is in a different package than class Thread,
* field access methods use Unsafe to bypass access control rules. * field access methods use Unsafe to bypass access control rules.
* The base functionality of Random methods is conveniently * To conform to the requirements of the Random superclass
* isolated in method next(bits), that just reads and writes the * constructor, the common static ThreadLocalRandom maintains an
* Thread field rather than its own field. However, to conform to * "initialized" field for the sake of rejecting user calls to
* the requirements of the Random superclass constructor, the * setSeed while still allowing a call from constructor. Note
* common static ThreadLocalRandom maintains an "initialized" * that serialization is completely unnecessary because there is
* field for the sake of rejecting user calls to setSeed while * only a static singleton. But we generate a serial form
* still allowing a call from constructor. Note that * containing "rnd" and "initialized" fields to ensure
* serialization is completely unnecessary because there is only a * compatibility across versions.
* static singleton. But we generate a serial form containing
* "rnd" and "initialized" fields to ensure compatibility across
* versions.
* *
* Per-thread initialization is similar to that in the no-arg * Implementations of non-core methods are mostly the same as in
* Random constructor, but we avoid correlation among not only * SplittableRandom, that were in part derived from a previous
* initial seeds of those created in different threads, but also * version of this class.
* those created using class Random itself; while at the same time
* not changing any statistical properties. So we use the same
* underlying multiplicative sequence, but start the sequence far
* away from the base version, and then merge (xor) current time
* and per-thread probe bits to generate initial values.
* *
* The nextLocalGaussian ThreadLocal supports the very rarely used * The nextLocalGaussian ThreadLocal supports the very rarely used
* nextGaussian method by providing a holder for the second of a * nextGaussian method by providing a holder for the second of a
@ -115,24 +122,51 @@ public class ThreadLocalRandom extends Random {
* but we provide identical statistical properties. * but we provide identical statistical properties.
*/ */
// same constants as Random, but must be redeclared because private
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
private static final int PROBE_INCREMENT = 0x61c88647;
/** Generates the basis for per-thread initial seed values */
private static final AtomicLong seedGenerator =
new AtomicLong(1269533684904616924L);
/** Generates per-thread initialization/probe field */ /** Generates per-thread initialization/probe field */
private static final AtomicInteger probeGenerator = private static final AtomicInteger probeGenerator =
new AtomicInteger(0xe80f8647); new AtomicInteger();
/**
* The next seed for default constructors.
*/
private static final AtomicLong seeder =
new AtomicLong(mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
/**
* The seed increment
*/
private static final long GAMMA = 0x9e3779b97f4a7c15L;
/**
* The increment for generating probe values
*/
private static final int PROBE_INCREMENT = 0x9e3779b9;
/**
* The increment of seeder per new instance
*/
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
// Constants from SplittableRandom
private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
private static final float FLOAT_UNIT = 1.0f / (1 << 24);
/** Rarely-used holder for the second of a pair of Gaussians */ /** Rarely-used holder for the second of a pair of Gaussians */
private static final ThreadLocal<Double> nextLocalGaussian = private static final ThreadLocal<Double> nextLocalGaussian =
new ThreadLocal<Double>(); new ThreadLocal<Double>();
private static long mix64(long z) {
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
return z ^ (z >>> 33);
}
private static int mix32(long z) {
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
}
/** /**
* Field used only during singleton initialization. * Field used only during singleton initialization.
* True when constructor completes. * True when constructor completes.
@ -155,16 +189,11 @@ public class ThreadLocalRandom extends Random {
* rely on (static) atomic generators to initialize the values. * rely on (static) atomic generators to initialize the values.
*/ */
static final void localInit() { static final void localInit() {
int p = probeGenerator.getAndAdd(PROBE_INCREMENT); int p = probeGenerator.addAndGet(PROBE_INCREMENT);
int probe = (p == 0) ? 1 : p; // skip 0 int probe = (p == 0) ? 1 : p; // skip 0
long current, next; long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
do { // same sequence as j.u.Random but different initial value
current = seedGenerator.get();
next = current * 181783497276652981L;
} while (!seedGenerator.compareAndSet(current, next));
long r = next ^ ((long)probe << 32) ^ System.nanoTime();
Thread t = Thread.currentThread(); Thread t = Thread.currentThread();
UNSAFE.putLong(t, SEED, r); UNSAFE.putLong(t, SEED, seed);
UNSAFE.putInt(t, PROBE, probe); UNSAFE.putInt(t, PROBE, probe);
} }
@ -191,124 +220,264 @@ public class ThreadLocalRandom extends Random {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
protected int next(int bits) { final long nextSeed() {
Thread t; long r; // read and update per-thread seed Thread t; long r; // read and update per-thread seed
UNSAFE.putLong UNSAFE.putLong(t = Thread.currentThread(), SEED,
(t = Thread.currentThread(), SEED, r = UNSAFE.getLong(t, SEED) + GAMMA);
r = (UNSAFE.getLong(t, SEED) * multiplier + addend) & mask); return r;
return (int) (r >>> (48-bits));
} }
/** // We must define this, but never use it.
* Returns a pseudorandom, uniformly distributed value between the protected int next(int bits) {
* given least value (inclusive) and bound (exclusive). return (int)(mix64(nextSeed()) >>> (64 - bits));
*
* @param least the least value returned
* @param bound the upper bound (exclusive)
* @throws IllegalArgumentException if least greater than or equal
* to bound
* @return the next value
*/
public int nextInt(int least, int bound) {
if (least >= bound)
throw new IllegalArgumentException();
return nextInt(bound - least) + least;
} }
// IllegalArgumentException messages
static final String BadBound = "bound must be positive";
static final String BadRange = "bound must be greater than origin";
static final String BadSize = "size must be non-negative";
/** /**
* Returns a pseudorandom, uniformly distributed value * The form of nextLong used by LongStream Spliterators. If
* between 0 (inclusive) and the specified value (exclusive). * origin is greater than bound, acts as unbounded form of
* nextLong, else as bounded form.
* *
* @param n the bound on the random number to be returned. Must be * @param origin the least value, unless greater than bound
* positive. * @param bound the upper bound (exclusive), must not equal origin
* @return the next value * @return a pseudorandom value
* @throws IllegalArgumentException if n is not positive
*/ */
public long nextLong(long n) { final long internalNextLong(long origin, long bound) {
if (n <= 0) long r = mix64(nextSeed());
throw new IllegalArgumentException("n must be positive"); if (origin < bound) {
// Divide n by two until small enough for nextInt. On each long n = bound - origin, m = n - 1;
// iteration (at most 31 of them but usually much less), if ((n & m) == 0L) // power of two
// randomly choose both whether to include high bit in result r = (r & m) + origin;
// (offset) and whether to continue with the lower vs upper else if (n > 0L) { // reject over-represented candidates
// half (which makes a difference only if odd). for (long u = r >>> 1; // ensure nonnegative
long offset = 0; u + m - (r = u % n) < 0L; // rejection check
while (n >= Integer.MAX_VALUE) { u = mix64(nextSeed()) >>> 1) // retry
int bits = next(2); ;
long half = n >>> 1; r += origin;
long nextn = ((bits & 2) == 0) ? half : n - half; }
if ((bits & 1) == 0) else { // range not representable as long
offset += n - nextn; while (r < origin || r >= bound)
n = nextn; r = mix64(nextSeed());
}
} }
return offset + nextInt((int) n); return r;
}
@Override
public IntStream ints() {
return IntStream.generate(() -> current().nextInt());
}
@Override
public LongStream longs() {
return LongStream.generate(() -> current().nextLong());
}
@Override
public DoubleStream doubles() {
return DoubleStream.generate(() -> current().nextDouble());
}
@Override
public DoubleStream gaussians() {
return DoubleStream.generate(() -> current().nextGaussian());
} }
/** /**
* Returns a pseudorandom, uniformly distributed value between the * The form of nextInt used by IntStream Spliterators.
* given least value (inclusive) and bound (exclusive). * Exactly the same as long version, except for types.
* *
* @param least the least value returned * @param origin the least value, unless greater than bound
* @param bound the upper bound (exclusive), must not equal origin
* @return a pseudorandom value
*/
final int internalNextInt(int origin, int bound) {
int r = mix32(nextSeed());
if (origin < bound) {
int n = bound - origin, m = n - 1;
if ((n & m) == 0)
r = (r & m) + origin;
else if (n > 0) {
for (int u = r >>> 1;
u + m - (r = u % n) < 0;
u = mix32(nextSeed()) >>> 1)
;
r += origin;
}
else {
while (r < origin || r >= bound)
r = mix32(nextSeed());
}
}
return r;
}
/**
* The form of nextDouble used by DoubleStream Spliterators.
*
* @param origin the least value, unless greater than bound
* @param bound the upper bound (exclusive), must not equal origin
* @return a pseudorandom value
*/
final double internalNextDouble(double origin, double bound) {
double r = (nextLong() >>> 11) * DOUBLE_UNIT;
if (origin < bound) {
r = r * (bound - origin) + origin;
if (r >= bound) // correct for rounding
r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
}
return r;
}
/**
* Returns a pseudorandom {@code int} value.
*
* @return a pseudorandom {@code int} value
*/
public int nextInt() {
return mix32(nextSeed());
}
/**
* Returns a pseudorandom {@code int} value between zero (inclusive)
* and the specified bound (exclusive).
*
* @param bound the upper bound (exclusive). Must be positive.
* @return a pseudorandom {@code int} value between zero
* (inclusive) and the bound (exclusive)
* @throws IllegalArgumentException if {@code bound} is not positive
*/
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
int r = mix32(nextSeed());
int m = bound - 1;
if ((bound & m) == 0) // power of two
r &= m;
else { // reject over-represented candidates
for (int u = r >>> 1;
u + m - (r = u % bound) < 0;
u = mix32(nextSeed()) >>> 1)
;
}
return r;
}
/**
* Returns a pseudorandom {@code int} value between the specified
* origin (inclusive) and the specified bound (exclusive).
*
* @param origin the least value returned
* @param bound the upper bound (exclusive) * @param bound the upper bound (exclusive)
* @return the next value * @return a pseudorandom {@code int} value between the origin
* @throws IllegalArgumentException if least greater than or equal * (inclusive) and the bound (exclusive)
* to bound * @throws IllegalArgumentException if {@code origin} is greater than
* or equal to {@code bound}
*/ */
public long nextLong(long least, long bound) { public int nextInt(int origin, int bound) {
if (least >= bound) if (origin >= bound)
throw new IllegalArgumentException(); throw new IllegalArgumentException(BadRange);
return nextLong(bound - least) + least; return internalNextInt(origin, bound);
} }
/** /**
* Returns a pseudorandom, uniformly distributed {@code double} value * Returns a pseudorandom {@code long} value.
* between 0 (inclusive) and the specified value (exclusive).
* *
* @param n the bound on the random number to be returned. Must be * @return a pseudorandom {@code long} value
* positive.
* @return the next value
* @throws IllegalArgumentException if n is not positive
*/ */
public double nextDouble(double n) { public long nextLong() {
if (n <= 0) return mix64(nextSeed());
throw new IllegalArgumentException("n must be positive");
return nextDouble() * n;
} }
/** /**
* Returns a pseudorandom, uniformly distributed value between the * Returns a pseudorandom {@code long} value between zero (inclusive)
* given least value (inclusive) and bound (exclusive). * and the specified bound (exclusive).
* *
* @param least the least value returned * @param bound the upper bound (exclusive). Must be positive.
* @return a pseudorandom {@code long} value between zero
* (inclusive) and the bound (exclusive)
* @throws IllegalArgumentException if {@code bound} is not positive
*/
public long nextLong(long bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
long r = mix64(nextSeed());
long m = bound - 1;
if ((bound & m) == 0L) // power of two
r &= m;
else { // reject over-represented candidates
for (long u = r >>> 1;
u + m - (r = u % bound) < 0L;
u = mix64(nextSeed()) >>> 1)
;
}
return r;
}
/**
* Returns a pseudorandom {@code long} value between the specified
* origin (inclusive) and the specified bound (exclusive).
*
* @param origin the least value returned
* @param bound the upper bound (exclusive) * @param bound the upper bound (exclusive)
* @return the next value * @return a pseudorandom {@code long} value between the origin
* @throws IllegalArgumentException if least greater than or equal * (inclusive) and the bound (exclusive)
* to bound * @throws IllegalArgumentException if {@code origin} is greater than
* or equal to {@code bound}
*/ */
public double nextDouble(double least, double bound) { public long nextLong(long origin, long bound) {
if (least >= bound) if (origin >= bound)
throw new IllegalArgumentException(); throw new IllegalArgumentException(BadRange);
return nextDouble() * (bound - least) + least; return internalNextLong(origin, bound);
}
/**
* Returns a pseudorandom {@code double} value between zero
* (inclusive) and one (exclusive).
*
* @return a pseudorandom {@code double} value between zero
* (inclusive) and one (exclusive)
*/
public double nextDouble() {
return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
}
/**
* Returns a pseudorandom {@code double} value between 0.0
* (inclusive) and the specified bound (exclusive).
*
* @param bound the upper bound (exclusive). Must be positive.
* @return a pseudorandom {@code double} value between zero
* (inclusive) and the bound (exclusive)
* @throws IllegalArgumentException if {@code bound} is not positive
*/
public double nextDouble(double bound) {
if (!(bound > 0.0))
throw new IllegalArgumentException(BadBound);
double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
return (result < bound) ? result : // correct for rounding
Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
}
/**
* Returns a pseudorandom {@code double} value between the specified
* origin (inclusive) and bound (exclusive).
*
* @param origin the least value returned
* @param bound the upper bound (exclusive)
* @return a pseudorandom {@code double} value between the origin
* (inclusive) and the bound (exclusive)
* @throws IllegalArgumentException if {@code origin} is greater than
* or equal to {@code bound}
*/
public double nextDouble(double origin, double bound) {
if (!(origin < bound))
throw new IllegalArgumentException(BadRange);
return internalNextDouble(origin, bound);
}
/**
* Returns a pseudorandom {@code boolean} value.
*
* @return a pseudorandom {@code boolean} value
*/
public boolean nextBoolean() {
return mix32(nextSeed()) < 0;
}
/**
* Returns a pseudorandom {@code float} value between zero
* (inclusive) and one (exclusive).
*
* @return a pseudorandom {@code float} value between zero
* (inclusive) and one (exclusive)
*/
public float nextFloat() {
return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT;
} }
public double nextGaussian() { public double nextGaussian() {
@ -329,6 +498,445 @@ public class ThreadLocalRandom extends Random {
return v1 * multiplier; return v1 * multiplier;
} }
// stream methods, coded in a way intended to better isolate for
// maintenance purposes the small differences across forms.
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code int} values.
*
* @param streamSize the number of values to generate
* @return a stream of pseudorandom {@code int} values
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @since 1.8
*/
public IntStream ints(long streamSize) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, streamSize, Integer.MAX_VALUE, 0),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code int}
* values.
*
* @implNote This method is implemented to be equivalent to {@code
* ints(Long.MAX_VALUE)}.
*
* @return a stream of pseudorandom {@code int} values
* @since 1.8
*/
public IntStream ints() {
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number
* of pseudorandom {@code int} values, each conforming to the given
* origin (inclusive) and bound (exclusive).
*
* @param streamSize the number of values to generate
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code int} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero, or {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public IntStream ints(long streamSize, int randomNumberOrigin,
int randomNumberBound) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, streamSize, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* int} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* @implNote This method is implemented to be equivalent to {@code
* ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code int} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code long} values.
*
* @param streamSize the number of values to generate
* @return a stream of pseudorandom {@code long} values
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @since 1.8
*/
public LongStream longs(long streamSize) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, streamSize, Long.MAX_VALUE, 0L),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code long}
* values.
*
* @implNote This method is implemented to be equivalent to {@code
* longs(Long.MAX_VALUE)}.
*
* @return a stream of pseudorandom {@code long} values
* @since 1.8
*/
public LongStream longs() {
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code long}, each conforming to the given origin
* (inclusive) and bound (exclusive).
*
* @param streamSize the number of values to generate
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code long} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero, or {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public LongStream longs(long streamSize, long randomNumberOrigin,
long randomNumberBound) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, streamSize, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* long} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* @implNote This method is implemented to be equivalent to {@code
* longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code long} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code double} values, each between zero
* (inclusive) and one (exclusive).
*
* @param streamSize the number of values to generate
* @return a stream of {@code double} values
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @since 1.8
*/
public DoubleStream doubles(long streamSize) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, streamSize, Double.MAX_VALUE, 0.0),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* double} values, each between zero (inclusive) and one
* (exclusive).
*
* @implNote This method is implemented to be equivalent to {@code
* doubles(Long.MAX_VALUE)}.
*
* @return a stream of pseudorandom {@code double} values
* @since 1.8
*/
public DoubleStream doubles() {
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
false);
}
/**
* Returns a stream producing the given {@code streamSize} number of
* pseudorandom {@code double} values, each conforming to the given origin
* (inclusive) and bound (exclusive).
*
* @param streamSize the number of values to generate
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code double} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code streamSize} is
* less than zero
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public DoubleStream doubles(long streamSize, double randomNumberOrigin,
double randomNumberBound) {
if (streamSize < 0L)
throw new IllegalArgumentException(BadSize);
if (!(randomNumberOrigin < randomNumberBound))
throw new IllegalArgumentException(BadRange);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, streamSize, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* double} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* @implNote This method is implemented to be equivalent to {@code
* doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code double} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
if (!(randomNumberOrigin < randomNumberBound))
throw new IllegalArgumentException(BadRange);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
/**
* Spliterator for int streams. We multiplex the four int
* versions into one class by treating a bound less than origin as
* unbounded, and also by treating "infinite" as equivalent to
* Long.MAX_VALUE. For splits, it uses the standard divide-by-two
* approach. The long and double versions of this class are
* identical except for types.
*/
static final class RandomIntsSpliterator implements Spliterator.OfInt {
long index;
final long fence;
final int origin;
final int bound;
RandomIntsSpliterator(long index, long fence,
int origin, int bound) {
this.index = index; this.fence = fence;
this.origin = origin; this.bound = bound;
}
public RandomIntsSpliterator trySplit() {
long i = index, m = (i + fence) >>> 1;
return (m <= i) ? null :
new RandomIntsSpliterator(i, index = m, origin, bound);
}
public long estimateSize() {
return fence - index;
}
public int characteristics() {
return (Spliterator.SIZED | Spliterator.SUBSIZED |
Spliterator.NONNULL | Spliterator.IMMUTABLE);
}
public boolean tryAdvance(IntConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
consumer.accept(ThreadLocalRandom.current().internalNextInt(origin, bound));
index = i + 1;
return true;
}
return false;
}
public void forEachRemaining(IntConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
index = f;
int o = origin, b = bound;
ThreadLocalRandom rng = ThreadLocalRandom.current();
do {
consumer.accept(rng.internalNextInt(o, b));
} while (++i < f);
}
}
}
/**
* Spliterator for long streams.
*/
static final class RandomLongsSpliterator implements Spliterator.OfLong {
long index;
final long fence;
final long origin;
final long bound;
RandomLongsSpliterator(long index, long fence,
long origin, long bound) {
this.index = index; this.fence = fence;
this.origin = origin; this.bound = bound;
}
public RandomLongsSpliterator trySplit() {
long i = index, m = (i + fence) >>> 1;
return (m <= i) ? null :
new RandomLongsSpliterator(i, index = m, origin, bound);
}
public long estimateSize() {
return fence - index;
}
public int characteristics() {
return (Spliterator.SIZED | Spliterator.SUBSIZED |
Spliterator.NONNULL | Spliterator.IMMUTABLE);
}
public boolean tryAdvance(LongConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
consumer.accept(ThreadLocalRandom.current().internalNextLong(origin, bound));
index = i + 1;
return true;
}
return false;
}
public void forEachRemaining(LongConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
index = f;
long o = origin, b = bound;
ThreadLocalRandom rng = ThreadLocalRandom.current();
do {
consumer.accept(rng.internalNextLong(o, b));
} while (++i < f);
}
}
}
/**
* Spliterator for double streams.
*/
static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
long index;
final long fence;
final double origin;
final double bound;
RandomDoublesSpliterator(long index, long fence,
double origin, double bound) {
this.index = index; this.fence = fence;
this.origin = origin; this.bound = bound;
}
public RandomDoublesSpliterator trySplit() {
long i = index, m = (i + fence) >>> 1;
return (m <= i) ? null :
new RandomDoublesSpliterator(i, index = m, origin, bound);
}
public long estimateSize() {
return fence - index;
}
public int characteristics() {
return (Spliterator.SIZED | Spliterator.SUBSIZED |
Spliterator.NONNULL | Spliterator.IMMUTABLE);
}
public boolean tryAdvance(DoubleConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
consumer.accept(ThreadLocalRandom.current().internalNextDouble(origin, bound));
index = i + 1;
return true;
}
return false;
}
public void forEachRemaining(DoubleConsumer consumer) {
if (consumer == null) throw new NullPointerException();
long i = index, f = fence;
if (i < f) {
index = f;
double o = origin, b = bound;
ThreadLocalRandom rng = ThreadLocalRandom.current();
do {
consumer.accept(rng.internalNextDouble(o, b));
} while (++i < f);
}
}
}
// Within-package utilities // Within-package utilities
/* /*
@ -401,23 +1009,26 @@ public class ThreadLocalRandom extends Random {
*/ */
private static final ObjectStreamField[] serialPersistentFields = { private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("rnd", long.class), new ObjectStreamField("rnd", long.class),
new ObjectStreamField("initialized", boolean.class) new ObjectStreamField("initialized", boolean.class),
}; };
/** /**
* Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it). * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it).
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
*/ */
private void writeObject(java.io.ObjectOutputStream out) private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException { throws java.io.IOException {
java.io.ObjectOutputStream.PutField fields = out.putFields(); java.io.ObjectOutputStream.PutField fields = s.putFields();
fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED)); fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED));
fields.put("initialized", true); fields.put("initialized", true);
out.writeFields(); s.writeFields();
} }
/** /**
* Returns the {@link #current() current} thread's {@code ThreadLocalRandom}. * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
* @return the {@link #current() current} thread's {@code ThreadLocalRandom}
*/ */
private Object readResolve() { private Object readResolve() {
return current(); return current();

View File

@ -226,7 +226,11 @@ public class StampedLock implements java.io.Serializable {
* incoming reader arrives while read lock is held but there is a * incoming reader arrives while read lock is held but there is a
* queued writer, this incoming reader is queued. (This rule is * queued writer, this incoming reader is queued. (This rule is
* responsible for some of the complexity of method acquireRead, * responsible for some of the complexity of method acquireRead,
* but without it, the lock becomes highly unfair.) * but without it, the lock becomes highly unfair.) Method release
* does not (and sometimes cannot) itself wake up cowaiters. This
* is done by the primary thread, but helped by any other threads
* with nothing better to do in methods acquireRead and
* acquireWrite.
* *
* These rules apply to threads actually queued. All tryLock forms * These rules apply to threads actually queued. All tryLock forms
* opportunistically try to acquire locks regardless of preference * opportunistically try to acquire locks regardless of preference
@ -267,11 +271,14 @@ public class StampedLock implements java.io.Serializable {
/** Number of processors, for spin control */ /** Number of processors, for spin control */
private static final int NCPU = Runtime.getRuntime().availableProcessors(); private static final int NCPU = Runtime.getRuntime().availableProcessors();
/** Maximum number of retries before blocking on acquisition */ /** Maximum number of retries before enqueuing on acquisition */
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0; private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
/** Maximum number of retries before blocking at head on acquisition */
private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
/** Maximum number of retries before re-blocking */ /** Maximum number of retries before re-blocking */
private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 0; private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
/** The period for yielding when waiting for overflow spinlock */ /** The period for yielding when waiting for overflow spinlock */
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1 private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
@ -415,8 +422,8 @@ public class StampedLock implements java.io.Serializable {
* @return a stamp that can be used to unlock or convert mode * @return a stamp that can be used to unlock or convert mode
*/ */
public long readLock() { public long readLock() {
long s, next; // bypass acquireRead on fully unlocked case only long s = state, next; // bypass acquireRead on common uncontended case
return ((((s = state) & ABITS) == 0L && return ((whead == wtail && (s & ABITS) < RFULL &&
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
next : acquireRead(false, 0L)); next : acquireRead(false, 0L));
} }
@ -1012,17 +1019,8 @@ public class StampedLock implements java.io.Serializable {
if (t.status <= 0) if (t.status <= 0)
q = t; q = t;
} }
if (q != null) { if (q != null && (w = q.thread) != null)
for (WNode r = q;;) { // release co-waiters too U.unpark(w);
if ((w = r.thread) != null) {
r.thread = null;
U.unpark(w);
}
if ((r = q.cowait) == null)
break;
U.compareAndSwapObject(q, WCOWAIT, r, r.cowait);
}
}
} }
} }
@ -1038,22 +1036,22 @@ public class StampedLock implements java.io.Serializable {
private long acquireWrite(boolean interruptible, long deadline) { private long acquireWrite(boolean interruptible, long deadline) {
WNode node = null, p; WNode node = null, p;
for (int spins = -1;;) { // spin while enqueuing for (int spins = -1;;) { // spin while enqueuing
long s, ns; long m, s, ns;
if (((s = state) & ABITS) == 0L) { if ((m = (s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
return ns; return ns;
} }
else if (spins < 0)
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) { else if (spins > 0) {
if (LockSupport.nextSecondarySeed() >= 0) if (LockSupport.nextSecondarySeed() >= 0)
--spins; --spins;
} }
else if ((p = wtail) == null) { // initialize queue else if ((p = wtail) == null) { // initialize queue
WNode h = new WNode(WMODE, null); WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, h)) if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = h; wtail = hd;
} }
else if (spins < 0)
spins = (p == whead) ? SPINS : 0;
else if (node == null) else if (node == null)
node = new WNode(WMODE, p); node = new WNode(WMODE, p);
else if (node.prev != p) else if (node.prev != p)
@ -1064,14 +1062,18 @@ public class StampedLock implements java.io.Serializable {
} }
} }
for (int spins = SPINS;;) { for (int spins = -1;;) {
WNode np, pp; int ps; long s, ns; Thread w; WNode h, np, pp; int ps;
while ((np = node.prev) != p && np != null) if ((h = whead) == p) {
(p = np).next = node; // stale if (spins < 0)
if (whead == p) { spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)
spins <<= 1;
for (int k = spins;;) { // spin at head for (int k = spins;;) { // spin at head
long s, ns;
if (((s = state) & ABITS) == 0L) { if (((s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) { if (U.compareAndSwapLong(this, STATE, s,
ns = s + WBIT)) {
whead = node; whead = node;
node.prev = null; node.prev = null;
return ns; return ns;
@ -1081,33 +1083,45 @@ public class StampedLock implements java.io.Serializable {
--k <= 0) --k <= 0)
break; break;
} }
if (spins < MAX_HEAD_SPINS)
spins <<= 1;
} }
if ((ps = p.status) == 0) else if (h != null) { // help release stale waiters
U.compareAndSwapInt(p, WSTATUS, 0, WAITING); WNode c; Thread w;
else if (ps == CANCELLED) { while ((c = h.cowait) != null) {
if ((pp = p.prev) != null) { if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
node.prev = pp; (w = c.thread) != null)
pp.next = node; U.unpark(w);
} }
} }
else { if (whead == h) {
long time; // 0 argument to park means no timeout if ((np = node.prev) != p) {
if (deadline == 0L) if (np != null)
time = 0L; (p = np).next = node; // stale
else if ((time = deadline - System.nanoTime()) <= 0L) }
return cancelWaiter(node, node, false); else if ((ps = p.status) == 0)
Thread wt = Thread.currentThread(); U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport.park else if (ps == CANCELLED) {
node.thread = wt; if ((pp = p.prev) != null) {
if (node.prev == p && p.status == WAITING && // recheck node.prev = pp;
(p != whead || (state & ABITS) != 0L)) pp.next = node;
U.park(false, time); }
node.thread = null; }
U.putObject(wt, PARKBLOCKER, null); else {
if (interruptible && Thread.interrupted()) long time; // 0 argument to park means no timeout
return cancelWaiter(node, node, true); if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
whead == h && node.prev == p)
U.park(false, time); // emulate LockSupport.park
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, node, true);
}
} }
} }
} }
@ -1122,138 +1136,159 @@ public class StampedLock implements java.io.Serializable {
* @return next state, or INTERRUPTED * @return next state, or INTERRUPTED
*/ */
private long acquireRead(boolean interruptible, long deadline) { private long acquireRead(boolean interruptible, long deadline) {
WNode node = null, group = null, p; WNode node = null, p;
for (int spins = -1;;) { for (int spins = -1;;) {
for (;;) { WNode h;
long s, m, ns; WNode h, q; Thread w; // anti-barging guard if ((h = whead) == (p = wtail)) {
if (group == null && (h = whead) != null && for (long m, s, ns;;) {
(q = h.next) != null && q.mode != RMODE) if ((m = (s = state) & ABITS) < RFULL ?
break; U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
if ((m = (s = state) & ABITS) < RFULL ? (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : return ns;
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { else if (m >= WBIT) {
if (group != null) { // help release others if (spins > 0) {
for (WNode r = group;;) { if (LockSupport.nextSecondarySeed() >= 0)
if ((w = r.thread) != null) { --spins;
r.thread = null; }
U.unpark(w); else {
if (spins == 0) {
WNode nh = whead, np = wtail;
if ((nh == h && np == p) || (h = nh) != (p = np))
break;
} }
if ((r = group.cowait) == null) spins = SPINS;
break;
U.compareAndSwapObject(group, WCOWAIT, r, r.cowait);
} }
} }
return ns;
} }
if (m >= WBIT)
break;
} }
if (spins > 0) { if (p == null) { // initialize queue
if (LockSupport.nextSecondarySeed() >= 0) WNode hd = new WNode(WMODE, null);
--spins; if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = hd;
} }
else if ((p = wtail) == null) {
WNode h = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, h))
wtail = h;
}
else if (spins < 0)
spins = (p == whead) ? SPINS : 0;
else if (node == null) else if (node == null)
node = new WNode(WMODE, p); node = new WNode(RMODE, p);
else if (node.prev != p) else if (h == p || p.mode != RMODE) {
node.prev = p; if (node.prev != p)
else if (p.mode == RMODE && p != whead) { node.prev = p;
WNode pp = p.prev; // become co-waiter with group p else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
if (pp != null && p == wtail && p.next = node;
U.compareAndSwapObject(p, WCOWAIT, break;
node.cowait = p.cowait, node)) { }
node.thread = Thread.currentThread(); }
for (long time;;) { else if (!U.compareAndSwapObject(p, WCOWAIT,
node.cowait = p.cowait, node))
node.cowait = null;
else {
for (;;) {
WNode pp, c; Thread w;
if ((h = whead) != null && (c = h.cowait) != null &&
U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null) // help release
U.unpark(w);
if (h == (pp = p.prev) || h == p || pp == null) {
long m, s, ns;
do {
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s,
ns = s + RUNIT) :
(m < WBIT &&
(ns = tryIncReaderOverflow(s)) != 0L))
return ns;
} while (m < WBIT);
}
if (whead == h && p.prev == pp) {
long time;
if (pp == null || h == p || p.status > 0) {
node = null; // throw away
break;
}
if (deadline == 0L) if (deadline == 0L)
time = 0L; time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L) else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, p, false); return cancelWaiter(node, p, false);
if (node.thread == null)
break;
if (p.prev != pp || p.status == CANCELLED ||
p == whead || p.prev != pp) {
node.thread = null;
break;
}
Thread wt = Thread.currentThread(); Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this); U.putObject(wt, PARKBLOCKER, this);
if (node.thread == null) // must recheck node.thread = wt;
break; if ((h != pp || (state & ABITS) == WBIT) &&
U.park(false, time); whead == h && p.prev == pp)
U.park(false, time);
node.thread = null;
U.putObject(wt, PARKBLOCKER, null); U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted()) if (interruptible && Thread.interrupted())
return cancelWaiter(node, p, true); return cancelWaiter(node, p, true);
} }
group = p;
} }
node = null; // throw away
}
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
p.next = node;
break;
} }
} }
for (int spins = SPINS;;) { for (int spins = -1;;) {
WNode np, pp, r; int ps; long m, s, ns; Thread w; WNode h, np, pp; int ps;
while ((np = node.prev) != p && np != null) if ((h = whead) == p) {
(p = np).next = node; if (spins < 0)
if (whead == p) { spins = HEAD_SPINS;
for (int k = spins;;) { else if (spins < MAX_HEAD_SPINS)
if ((m = (s = state) & ABITS) != WBIT) { spins <<= 1;
if (m < RFULL ? for (int k = spins;;) { // spin at head
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT): long m, s, ns;
(ns = tryIncReaderOverflow(s)) != 0L) { if ((m = (s = state) & ABITS) < RFULL ?
whead = node; U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
node.prev = null; (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
while ((r = node.cowait) != null) { WNode c; Thread w;
if (U.compareAndSwapObject(node, WCOWAIT, whead = node;
r, r.cowait) && node.prev = null;
(w = r.thread) != null) { while ((c = node.cowait) != null) {
r.thread = null; if (U.compareAndSwapObject(node, WCOWAIT,
U.unpark(w); // release co-waiter c, c.cowait) &&
} (w = c.thread) != null)
} U.unpark(w);
return ns;
} }
return ns;
} }
else if (LockSupport.nextSecondarySeed() >= 0 && else if (m >= WBIT &&
--k <= 0) LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
break; break;
} }
if (spins < MAX_HEAD_SPINS)
spins <<= 1;
} }
if ((ps = p.status) == 0) else if (h != null) {
U.compareAndSwapInt(p, WSTATUS, 0, WAITING); WNode c; Thread w;
else if (ps == CANCELLED) { while ((c = h.cowait) != null) {
if ((pp = p.prev) != null) { if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
node.prev = pp; (w = c.thread) != null)
pp.next = node; U.unpark(w);
} }
} }
else { if (whead == h) {
long time; if ((np = node.prev) != p) {
if (deadline == 0L) if (np != null)
time = 0L; (p = np).next = node; // stale
else if ((time = deadline - System.nanoTime()) <= 0L) }
return cancelWaiter(node, node, false); else if ((ps = p.status) == 0)
Thread wt = Thread.currentThread(); U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
U.putObject(wt, PARKBLOCKER, this); else if (ps == CANCELLED) {
node.thread = wt; if ((pp = p.prev) != null) {
if (node.prev == p && p.status == WAITING && node.prev = pp;
(p != whead || (state & ABITS) != WBIT)) pp.next = node;
U.park(false, time); }
node.thread = null; }
U.putObject(wt, PARKBLOCKER, null); else {
if (interruptible && Thread.interrupted()) long time;
return cancelWaiter(node, node, true); if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 &&
(p != h || (state & ABITS) == WBIT) &&
whead == h && node.prev == p)
U.park(false, time);
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, node, true);
}
} }
} }
} }
@ -1278,22 +1313,19 @@ public class StampedLock implements java.io.Serializable {
if (node != null && group != null) { if (node != null && group != null) {
Thread w; Thread w;
node.status = CANCELLED; node.status = CANCELLED;
node.thread = null;
// unsplice cancelled nodes from group // unsplice cancelled nodes from group
for (WNode p = group, q; (q = p.cowait) != null;) { for (WNode p = group, q; (q = p.cowait) != null;) {
if (q.status == CANCELLED) if (q.status == CANCELLED) {
U.compareAndSwapObject(p, WNEXT, q, q.next); U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
p = group; // restart
}
else else
p = q; p = q;
} }
if (group == node) { if (group == node) {
WNode r; // detach and wake up uncancelled co-waiters for (WNode r = group.cowait; r != null; r = r.cowait) {
while ((r = node.cowait) != null) { if ((w = r.thread) != null)
if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) && U.unpark(w); // wake up uncancelled co-waiters
(w = r.thread) != null) {
r.thread = null;
U.unpark(w);
}
} }
for (WNode pred = node.prev; pred != null; ) { // unsplice for (WNode pred = node.prev; pred != null; ) { // unsplice
WNode succ, pp; // find valid successor WNode succ, pp; // find valid successor

View File

@ -32,6 +32,7 @@ import java.security.*;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import sun.misc.JarIndex;
import sun.security.util.ManifestDigester; import sun.security.util.ManifestDigester;
import sun.security.util.ManifestEntryVerifier; import sun.security.util.ManifestEntryVerifier;
import sun.security.util.SignatureFileVerifier; import sun.security.util.SignatureFileVerifier;
@ -139,7 +140,8 @@ class JarVerifier {
return; return;
} }
if (uname.equals(JarFile.MANIFEST_NAME)) { if (uname.equals(JarFile.MANIFEST_NAME) ||
uname.equals(JarIndex.INDEX_NAME)) {
return; return;
} }

View File

@ -457,13 +457,15 @@ public class Logger {
* of the subsystem, such as java.net * of the subsystem, such as java.net
* or javax.swing * or javax.swing
* @param resourceBundleName name of ResourceBundle to be used for localizing * @param resourceBundleName name of ResourceBundle to be used for localizing
* messages for this logger. May be <CODE>null</CODE> if none of * messages for this logger. May be {@code null}
* the messages require localization. * if none of the messages require localization.
* @return a suitable Logger * @return a suitable Logger
* @throws MissingResourceException if the resourceBundleName is non-null and * @throws MissingResourceException if the resourceBundleName is non-null and
* no corresponding resource can be found. * no corresponding resource can be found.
* @throws IllegalArgumentException if the Logger already exists and uses * @throws IllegalArgumentException if the Logger already exists and uses
* a different resource bundle name. * a different resource bundle name; or if
* {@code resourceBundleName} is {@code null} but the named
* logger has a resource bundle set.
* @throws NullPointerException if the name is null. * @throws NullPointerException if the name is null.
*/ */
@ -1731,10 +1733,6 @@ public class Logger {
// Synchronized to prevent races in setting the fields. // Synchronized to prevent races in setting the fields.
private synchronized void setupResourceInfo(String name, private synchronized void setupResourceInfo(String name,
Class<?> callersClass) { Class<?> callersClass) {
if (name == null) {
return;
}
if (resourceBundleName != null) { if (resourceBundleName != null) {
// this Logger already has a ResourceBundle // this Logger already has a ResourceBundle
@ -1748,6 +1746,10 @@ public class Logger {
resourceBundleName + " != " + name); resourceBundleName + " != " + name);
} }
if (name == null) {
return;
}
setCallersClassLoaderRef(callersClass); setCallersClassLoaderRef(callersClass);
if (findResourceBundle(name, true) == null) { if (findResourceBundle(name, true) == null) {
// We've failed to find an expected ResourceBundle. // We've failed to find an expected ResourceBundle.

View File

@ -219,7 +219,7 @@ import java.util.stream.StreamSupport;
* *
* <tr><th>&nbsp;</th></tr> * <tr><th>&nbsp;</th></tr>
* <tr align="left"><th colspan="2" id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr> * <tr align="left"><th colspan="2" id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr>
* * <tr><td valign="top" headers="construct unicode">{@code \p{IsLatin}}</td> * <tr><td valign="top" headers="construct unicode">{@code \p{IsLatin}}</td>
* <td headers="matches">A Latin&nbsp;script character (<a href="#usc">script</a>)</td></tr> * <td headers="matches">A Latin&nbsp;script character (<a href="#usc">script</a>)</td></tr>
* <tr><td valign="top" headers="construct unicode">{@code \p{InGreek}}</td> * <tr><td valign="top" headers="construct unicode">{@code \p{InGreek}}</td>
* <td headers="matches">A character in the Greek&nbsp;block (<a href="#ubc">block</a>)</td></tr> * <td headers="matches">A character in the Greek&nbsp;block (<a href="#ubc">block</a>)</td></tr>
@ -4456,16 +4456,16 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
groups[groupIndex+1] = i; groups[groupIndex+1] = i;
groups[groupIndex] = i - k; groups[groupIndex] = i - k;
} }
i = i - k;
return true; return true;
} }
// backing off // backing off
i = i - k;
if (capture) { if (capture) {
groups[groupIndex+1] = i; groups[groupIndex+1] = i;
groups[groupIndex] = i - k; groups[groupIndex] = i - k;
} }
i = i - k;
j--; j--;
} }
break; break;
} }
@ -4883,7 +4883,6 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
int k = matcher.groups[groupIndex+1]; int k = matcher.groups[groupIndex+1];
int groupSize = k - j; int groupSize = k - j;
// If the referenced group didn't match, neither can this // If the referenced group didn't match, neither can this
if (j < 0) if (j < 0)
return false; return false;
@ -4893,7 +4892,6 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
matcher.hitEnd = true; matcher.hitEnd = true;
return false; return false;
} }
// Check each new char to make sure it matches what the group // Check each new char to make sure it matches what the group
// referenced matched last time around // referenced matched last time around
for (int index=0; index<groupSize; index++) for (int index=0; index<groupSize; index++)

View File

@ -137,6 +137,11 @@ public final class Collectors {
return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
} }
@SuppressWarnings("unchecked")
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
/** /**
* Simple implementation class for {@code Collector}. * Simple implementation class for {@code Collector}.
* *
@ -166,7 +171,7 @@ public final class Collectors {
BiConsumer<A, T> accumulator, BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner, BinaryOperator<A> combiner,
Set<Characteristics> characteristics) { Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, i -> (R) i, characteristics); this(supplier, accumulator, combiner, castingIdentity(), characteristics);
} }
@Override @Override
@ -209,7 +214,7 @@ public final class Collectors {
*/ */
public static <T, C extends Collection<T>> public static <T, C extends Collection<T>>
Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) { Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
return new CollectorImpl<>(collectionFactory, Collection::add, return new CollectorImpl<>(collectionFactory, Collection<T>::add,
(r1, r2) -> { r1.addAll(r2); return r1; }, (r1, r2) -> { r1.addAll(r2); return r1; },
CH_ID); CH_ID);
} }
@ -1046,30 +1051,23 @@ public final class Collectors {
public static <T, D, A> public static <T, D, A>
Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
Collector<? super T, A, D> downstream) { Collector<? super T, A, D> downstream) {
@SuppressWarnings("unchecked") BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
BiConsumer<D, ? super T> downstreamAccumulator = (BiConsumer<D, ? super T>) downstream.accumulator(); BiConsumer<Partition<A>, T> accumulator = (result, t) ->
BiConsumer<Map<Boolean, A>, T> accumulator = (result, t) -> { downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
Partition<D> asPartition = ((Partition<D>) result);
downstreamAccumulator.accept(predicate.test(t) ? asPartition.forTrue : asPartition.forFalse, t);
};
BinaryOperator<A> op = downstream.combiner(); BinaryOperator<A> op = downstream.combiner();
BinaryOperator<Map<Boolean, A>> merger = (m1, m2) -> { BinaryOperator<Partition<A>> merger = (left, right) ->
Partition<A> left = (Partition<A>) m1; new Partition<>(op.apply(left.forTrue, right.forTrue),
Partition<A> right = (Partition<A>) m2; op.apply(left.forFalse, right.forFalse));
return new Partition<>(op.apply(left.forTrue, right.forTrue), Supplier<Partition<A>> supplier = () ->
op.apply(left.forFalse, right.forFalse)); new Partition<>(downstream.supplier().get(),
}; downstream.supplier().get());
Supplier<Map<Boolean, A>> supplier = () -> new Partition<>(downstream.supplier().get(),
downstream.supplier().get());
if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
return new CollectorImpl<>(supplier, accumulator, merger, CH_ID); return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
} }
else { else {
Function<Map<Boolean, A>, Map<Boolean, D>> finisher = (Map<Boolean, A> par) -> { Function<Partition<A>, Map<Boolean, D>> finisher = par ->
Partition<A> asAPartition = (Partition<A>) par; new Partition<>(downstream.finisher().apply(par.forTrue),
return new Partition<>(downstream.finisher().apply(asAPartition.forTrue), downstream.finisher().apply(par.forFalse));
downstream.finisher().apply(asAPartition.forFalse));
};
return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID); return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
} }
} }

View File

@ -101,7 +101,7 @@ final class DistinctOps {
if (StreamOpFlag.DISTINCT.isKnown(flags)) { if (StreamOpFlag.DISTINCT.isKnown(flags)) {
return sink; return sink;
} else if (StreamOpFlag.SORTED.isKnown(flags)) { } else if (StreamOpFlag.SORTED.isKnown(flags)) {
return new Sink.ChainedReference<T>(sink) { return new Sink.ChainedReference<T, T>(sink) {
boolean seenNull; boolean seenNull;
T lastSeen; T lastSeen;
@ -132,7 +132,7 @@ final class DistinctOps {
} }
}; };
} else { } else {
return new Sink.ChainedReference<T>(sink) { return new Sink.ChainedReference<T, T>(sink) {
Set<T> seen; Set<T> seen;
@Override @Override

View File

@ -191,7 +191,7 @@ abstract class DoublePipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Double> sink) { Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Double>(sink) {
@Override @Override
public void accept(double t) { public void accept(double t) {
downstream.accept(mapper.applyAsDouble(t)); downstream.accept(mapper.applyAsDouble(t));
@ -208,9 +208,8 @@ abstract class DoublePipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<U> sink) { Sink<Double> opWrapSink(int flags, Sink<U> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<U>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(double t) { public void accept(double t) {
downstream.accept(mapper.apply(t)); downstream.accept(mapper.apply(t));
} }
@ -226,7 +225,7 @@ abstract class DoublePipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Integer> sink) { Sink<Double> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Integer>(sink) {
@Override @Override
public void accept(double t) { public void accept(double t) {
downstream.accept(mapper.applyAsInt(t)); downstream.accept(mapper.applyAsInt(t));
@ -243,7 +242,7 @@ abstract class DoublePipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Long> sink) { Sink<Double> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Long>(sink) {
@Override @Override
public void accept(double t) { public void accept(double t) {
downstream.accept(mapper.applyAsLong(t)); downstream.accept(mapper.applyAsLong(t));
@ -259,7 +258,7 @@ abstract class DoublePipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Double> sink) { Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Double>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
@ -296,7 +295,7 @@ abstract class DoublePipeline<E_IN>
StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Double> sink) { Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Double>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
@ -319,7 +318,7 @@ abstract class DoublePipeline<E_IN>
0) { 0) {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Double> sink) { Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Double>(sink) {
@Override @Override
public void accept(double t) { public void accept(double t) {
consumer.accept(t); consumer.accept(t);

View File

@ -189,9 +189,8 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Long> sink) { Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Long>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(int t) { public void accept(int t) {
downstream.accept((long) t); downstream.accept((long) t);
} }
@ -206,9 +205,8 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Double> sink) { Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Double>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(int t) { public void accept(int t) {
downstream.accept((double) t); downstream.accept((double) t);
} }
@ -229,7 +227,7 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Integer>(sink) {
@Override @Override
public void accept(int t) { public void accept(int t) {
downstream.accept(mapper.applyAsInt(t)); downstream.accept(mapper.applyAsInt(t));
@ -246,9 +244,8 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<U> sink) { Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<U>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(int t) { public void accept(int t) {
downstream.accept(mapper.apply(t)); downstream.accept(mapper.apply(t));
} }
@ -264,7 +261,7 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Long> sink) { Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Long>(sink) {
@Override @Override
public void accept(int t) { public void accept(int t) {
downstream.accept(mapper.applyAsLong(t)); downstream.accept(mapper.applyAsLong(t));
@ -281,7 +278,7 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Double> sink) { Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Double>(sink) {
@Override @Override
public void accept(int t) { public void accept(int t) {
downstream.accept(mapper.applyAsDouble(t)); downstream.accept(mapper.applyAsDouble(t));
@ -297,7 +294,7 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Integer>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
@ -334,7 +331,7 @@ abstract class IntPipeline<E_IN>
StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Integer>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
@ -357,7 +354,7 @@ abstract class IntPipeline<E_IN>
0) { 0) {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Integer>(sink) {
@Override @Override
public void accept(int t) { public void accept(int t) {
consumer.accept(t); consumer.accept(t);

View File

@ -186,7 +186,7 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Double> sink) { Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Double>(sink) {
@Override @Override
public void accept(long t) { public void accept(long t) {
downstream.accept((double) t); downstream.accept((double) t);
@ -208,9 +208,8 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Long> sink) { Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Long>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(long t) { public void accept(long t) {
downstream.accept(mapper.applyAsLong(t)); downstream.accept(mapper.applyAsLong(t));
} }
@ -226,9 +225,8 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<U> sink) { Sink<Long> opWrapSink(int flags, Sink<U> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<U>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(long t) { public void accept(long t) {
downstream.accept(mapper.apply(t)); downstream.accept(mapper.apply(t));
} }
@ -244,9 +242,8 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Integer> sink) { Sink<Long> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Integer>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(long t) { public void accept(long t) {
downstream.accept(mapper.applyAsInt(t)); downstream.accept(mapper.applyAsInt(t));
} }
@ -262,7 +259,7 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Double> sink) { Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Double>(sink) {
@Override @Override
public void accept(long t) { public void accept(long t) {
downstream.accept(mapper.applyAsDouble(t)); downstream.accept(mapper.applyAsDouble(t));
@ -278,7 +275,7 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Long> sink) { Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Long>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
@ -315,7 +312,7 @@ abstract class LongPipeline<E_IN>
StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Long> sink) { Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Long>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
@ -338,7 +335,7 @@ abstract class LongPipeline<E_IN>
0) { 0) {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Long> sink) { Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Long>(sink) {
@Override @Override
public void accept(long t) { public void accept(long t) {
consumer.accept(t); consumer.accept(t);

View File

@ -163,17 +163,16 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
} }
@Override @Override
@SuppressWarnings("unchecked")
public void accept(P_OUT u) { public void accept(P_OUT u) {
if (predicate.test(u)) if (predicate.test(u))
downstream.accept((Object) u); downstream.accept(u);
} }
}; };
} }
@ -188,7 +187,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, R>(sink) {
@Override @Override
public void accept(P_OUT u) { public void accept(P_OUT u) {
downstream.accept(mapper.apply(u)); downstream.accept(mapper.apply(u));
@ -205,7 +204,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, Integer>(sink) {
@Override @Override
public void accept(P_OUT u) { public void accept(P_OUT u) {
downstream.accept(mapper.applyAsInt(u)); downstream.accept(mapper.applyAsInt(u));
@ -222,7 +221,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, Long>(sink) {
@Override @Override
public void accept(P_OUT u) { public void accept(P_OUT u) {
downstream.accept(mapper.applyAsLong(u)); downstream.accept(mapper.applyAsLong(u));
@ -239,7 +238,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, Double>(sink) {
@Override @Override
public void accept(P_OUT u) { public void accept(P_OUT u) {
downstream.accept(mapper.applyAsDouble(u)); downstream.accept(mapper.applyAsDouble(u));
@ -257,14 +256,13 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, R>(sink) {
@Override @Override
public void begin(long size) { public void begin(long size) {
downstream.begin(-1); downstream.begin(-1);
} }
@Override @Override
@SuppressWarnings("unchecked")
public void accept(P_OUT u) { public void accept(P_OUT u) {
// We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
Stream<? extends R> result = mapper.apply(u); Stream<? extends R> result = mapper.apply(u);
@ -284,7 +282,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, Integer>(sink) {
IntConsumer downstreamAsInt = downstream::accept; IntConsumer downstreamAsInt = downstream::accept;
@Override @Override
public void begin(long size) { public void begin(long size) {
@ -311,7 +309,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, Double>(sink) {
DoubleConsumer downstreamAsDouble = downstream::accept; DoubleConsumer downstreamAsDouble = downstream::accept;
@Override @Override
public void begin(long size) { public void begin(long size) {
@ -338,7 +336,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) { StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, Long>(sink) {
LongConsumer downstreamAsLong = downstream::accept; LongConsumer downstreamAsLong = downstream::accept;
@Override @Override
public void begin(long size) { public void begin(long size) {
@ -364,9 +362,8 @@ abstract class ReferencePipeline<P_IN, P_OUT>
0) { 0) {
@Override @Override
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
return new Sink.ChainedReference<P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(P_OUT u) { public void accept(P_OUT u) {
tee.accept(u); tee.accept(u);
downstream.accept(u); downstream.accept(u);
@ -495,6 +492,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
} }
@Override @Override
@SuppressWarnings("unchecked")
public final <R, A> R collect(Collector<? super P_OUT, A, ? extends R> collector) { public final <R, A> R collect(Collector<? super P_OUT, A, ? extends R> collector) {
A container; A container;
if (isParallel() if (isParallel()

View File

@ -241,11 +241,10 @@ interface Sink<T> extends Consumer<T> {
* implementation of the {@code accept()} method must call the correct * implementation of the {@code accept()} method must call the correct
* {@code accept()} method on the downstream {@code Sink}. * {@code accept()} method on the downstream {@code Sink}.
*/ */
static abstract class ChainedReference<T> implements Sink<T> { static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
@SuppressWarnings("rawtypes") protected final Sink<? super E_OUT> downstream;
protected final Sink downstream;
public ChainedReference(Sink downstream) { public ChainedReference(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream); this.downstream = Objects.requireNonNull(downstream);
} }
@ -274,11 +273,10 @@ interface Sink<T> extends Consumer<T> {
* The implementation of the {@code accept()} method must call the correct * The implementation of the {@code accept()} method must call the correct
* {@code accept()} method on the downstream {@code Sink}. * {@code accept()} method on the downstream {@code Sink}.
*/ */
static abstract class ChainedInt implements Sink.OfInt { static abstract class ChainedInt<E_OUT> implements Sink.OfInt {
@SuppressWarnings("rawtypes") protected final Sink<? super E_OUT> downstream;
protected final Sink downstream;
public ChainedInt(Sink downstream) { public ChainedInt(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream); this.downstream = Objects.requireNonNull(downstream);
} }
@ -307,11 +305,10 @@ interface Sink<T> extends Consumer<T> {
* The implementation of the {@code accept()} method must call the correct * The implementation of the {@code accept()} method must call the correct
* {@code accept()} method on the downstream {@code Sink}. * {@code accept()} method on the downstream {@code Sink}.
*/ */
static abstract class ChainedLong implements Sink.OfLong { static abstract class ChainedLong<E_OUT> implements Sink.OfLong {
@SuppressWarnings("rawtypes") protected final Sink<? super E_OUT> downstream;
protected final Sink downstream;
public ChainedLong(Sink downstream) { public ChainedLong(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream); this.downstream = Objects.requireNonNull(downstream);
} }
@ -340,11 +337,10 @@ interface Sink<T> extends Consumer<T> {
* The implementation of the {@code accept()} method must call the correct * The implementation of the {@code accept()} method must call the correct
* {@code accept()} method on the downstream {@code Sink}. * {@code accept()} method on the downstream {@code Sink}.
*/ */
static abstract class ChainedDouble implements Sink.OfDouble { static abstract class ChainedDouble<E_OUT> implements Sink.OfDouble {
@SuppressWarnings("rawtypes") protected final Sink<? super E_OUT> downstream;
protected final Sink downstream;
public ChainedDouble(Sink downstream) { public ChainedDouble(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream); this.downstream = Objects.requireNonNull(downstream);
} }

View File

@ -96,6 +96,11 @@ final class SliceOps {
} }
} }
@SuppressWarnings("unchecked")
private static <T> IntFunction<T[]> castingArray() {
return size -> (T[]) new Object[size];
}
/** /**
* Appends a "slice" operation to the provided stream. The slice operation * Appends a "slice" operation to the provided stream. The slice operation
* may be may be skip-only, limit-only, or skip-and-limit. * may be may be skip-only, limit-only, or skip-and-limit.
@ -107,12 +112,12 @@ final class SliceOps {
* is to be imposed * is to be imposed
*/ */
public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream, public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
long skip, long limit) { long skip, long limit) {
if (skip < 0) if (skip < 0)
throw new IllegalArgumentException("Skip must be non-negative: " + skip); throw new IllegalArgumentException("Skip must be non-negative: " + skip);
return new ReferencePipeline.StatefulOp<T,T>(upstream, StreamShape.REFERENCE, return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
flags(limit)) { flags(limit)) {
Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s, Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
long skip, long limit, long sizeIfKnown) { long skip, long limit, long sizeIfKnown) {
if (skip <= sizeIfKnown) { if (skip <= sizeIfKnown) {
@ -146,7 +151,7 @@ final class SliceOps {
// cancellation will be more aggressive cancelling later tasks // cancellation will be more aggressive cancelling later tasks
// if the target slice size has been reached from a given task, // if the target slice size has been reached from a given task,
// cancellation should also clear local results if any // cancellation should also clear local results if any
return new SliceTask<>(this, helper, spliterator, i -> (T[]) new Object[i], skip, limit). return new SliceTask<>(this, helper, spliterator, castingArray(), skip, limit).
invoke().spliterator(); invoke().spliterator();
} }
} }
@ -182,7 +187,7 @@ final class SliceOps {
@Override @Override
Sink<T> opWrapSink(int flags, Sink<T> sink) { Sink<T> opWrapSink(int flags, Sink<T> sink) {
return new Sink.ChainedReference<T>(sink) { return new Sink.ChainedReference<T, T>(sink) {
long n = skip; long n = skip;
long m = limit >= 0 ? limit : Long.MAX_VALUE; long m = limit >= 0 ? limit : Long.MAX_VALUE;
@ -291,7 +296,7 @@ final class SliceOps {
@Override @Override
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) { Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
return new Sink.ChainedInt(sink) { return new Sink.ChainedInt<Integer>(sink) {
long n = skip; long n = skip;
long m = limit >= 0 ? limit : Long.MAX_VALUE; long m = limit >= 0 ? limit : Long.MAX_VALUE;
@ -400,7 +405,7 @@ final class SliceOps {
@Override @Override
Sink<Long> opWrapSink(int flags, Sink<Long> sink) { Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedLong(sink) { return new Sink.ChainedLong<Long>(sink) {
long n = skip; long n = skip;
long m = limit >= 0 ? limit : Long.MAX_VALUE; long m = limit >= 0 ? limit : Long.MAX_VALUE;
@ -509,7 +514,7 @@ final class SliceOps {
@Override @Override
Sink<Double> opWrapSink(int flags, Sink<Double> sink) { Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedDouble(sink) { return new Sink.ChainedDouble<Double>(sink) {
long n = skip; long n = skip;
long m = limit >= 0 ? limit : Long.MAX_VALUE; long m = limit >= 0 ? limit : Long.MAX_VALUE;
@ -560,13 +565,13 @@ final class SliceOps {
private volatile boolean completed; private volatile boolean completed;
SliceTask(AbstractPipeline<?, P_OUT, ?> op, SliceTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
PipelineHelper<P_OUT> helper, PipelineHelper<P_OUT> helper,
Spliterator<P_IN> spliterator, Spliterator<P_IN> spliterator,
IntFunction<P_OUT[]> generator, IntFunction<P_OUT[]> generator,
long offset, long size) { long offset, long size) {
super(helper, spliterator); super(helper, spliterator);
this.op = (AbstractPipeline<P_OUT, P_OUT, ?>) op; this.op = op;
this.generator = generator; this.generator = generator;
this.targetOffset = offset; this.targetOffset = offset;
this.targetSize = size; this.targetSize = size;

View File

@ -129,7 +129,7 @@ final class SortedOps {
} }
@Override @Override
public Sink<T> opWrapSink(int flags, Sink sink) { public Sink<T> opWrapSink(int flags, Sink<T> sink) {
Objects.requireNonNull(sink); Objects.requireNonNull(sink);
// If the input is already naturally sorted and this operation // If the input is already naturally sorted and this operation
@ -280,12 +280,12 @@ final class SortedOps {
/** /**
* {@link ForkJoinTask} for implementing sort on SIZED reference streams. * {@link ForkJoinTask} for implementing sort on SIZED reference streams.
*/ */
private static final class SizedRefSortingSink<T> extends Sink.ChainedReference<T> { private static final class SizedRefSortingSink<T> extends Sink.ChainedReference<T, T> {
private final Comparator<? super T> comparator; private final Comparator<? super T> comparator;
private T[] array; private T[] array;
private int offset; private int offset;
SizedRefSortingSink(Sink<T> sink, Comparator<? super T> comparator) { SizedRefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
super(sink); super(sink);
this.comparator = comparator; this.comparator = comparator;
} }
@ -320,11 +320,11 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on reference streams. * {@link Sink} for implementing sort on reference streams.
*/ */
private static final class RefSortingSink<T> extends Sink.ChainedReference<T> { private static final class RefSortingSink<T> extends Sink.ChainedReference<T, T> {
private final Comparator<? super T> comparator; private final Comparator<? super T> comparator;
private ArrayList<T> list; private ArrayList<T> list;
RefSortingSink(Sink<T> sink, Comparator<? super T> comparator) { RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
super(sink); super(sink);
this.comparator = comparator; this.comparator = comparator;
} }
@ -352,11 +352,11 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on SIZED int streams. * {@link Sink} for implementing sort on SIZED int streams.
*/ */
private static final class SizedIntSortingSink extends Sink.ChainedInt { private static final class SizedIntSortingSink extends Sink.ChainedInt<Integer> {
private int[] array; private int[] array;
private int offset; private int offset;
SizedIntSortingSink(Sink downstream) { SizedIntSortingSink(Sink<? super Integer> downstream) {
super(downstream); super(downstream);
} }
@ -386,10 +386,10 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on int streams. * {@link Sink} for implementing sort on int streams.
*/ */
private static final class IntSortingSink extends Sink.ChainedInt { private static final class IntSortingSink extends Sink.ChainedInt<Integer> {
private SpinedBuffer.OfInt b; private SpinedBuffer.OfInt b;
IntSortingSink(Sink sink) { IntSortingSink(Sink<? super Integer> sink) {
super(sink); super(sink);
} }
@ -417,11 +417,11 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on SIZED long streams. * {@link Sink} for implementing sort on SIZED long streams.
*/ */
private static final class SizedLongSortingSink extends Sink.ChainedLong { private static final class SizedLongSortingSink extends Sink.ChainedLong<Long> {
private long[] array; private long[] array;
private int offset; private int offset;
SizedLongSortingSink(Sink downstream) { SizedLongSortingSink(Sink<? super Long> downstream) {
super(downstream); super(downstream);
} }
@ -451,10 +451,10 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on long streams. * {@link Sink} for implementing sort on long streams.
*/ */
private static final class LongSortingSink extends Sink.ChainedLong { private static final class LongSortingSink extends Sink.ChainedLong<Long> {
private SpinedBuffer.OfLong b; private SpinedBuffer.OfLong b;
LongSortingSink(Sink sink) { LongSortingSink(Sink<? super Long> sink) {
super(sink); super(sink);
} }
@ -482,11 +482,11 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on SIZED double streams. * {@link Sink} for implementing sort on SIZED double streams.
*/ */
private static final class SizedDoubleSortingSink extends Sink.ChainedDouble { private static final class SizedDoubleSortingSink extends Sink.ChainedDouble<Double> {
private double[] array; private double[] array;
private int offset; private int offset;
SizedDoubleSortingSink(Sink downstream) { SizedDoubleSortingSink(Sink<? super Double> downstream) {
super(downstream); super(downstream);
} }
@ -516,10 +516,10 @@ final class SortedOps {
/** /**
* {@link Sink} for implementing sort on double streams. * {@link Sink} for implementing sort on double streams.
*/ */
private static final class DoubleSortingSink extends Sink.ChainedDouble { private static final class DoubleSortingSink extends Sink.ChainedDouble<Double> {
private SpinedBuffer.OfDouble b; private SpinedBuffer.OfDouble b;
DoubleSortingSink(Sink sink) { DoubleSortingSink(Sink<? super Double> sink) {
super(sink); super(sink);
} }

Some files were not shown because too many files have changed in this diff Show More