Merge
This commit is contained in:
commit
44b5df1ac8
@ -226,3 +226,4 @@ d2dcb110e9dbaf9903c05b211df800e78e4b394e jdk8-b100
|
||||
5eb3c1dc348f72a7f84f7d9d07834e8bbe09a799 jdk8-b102
|
||||
b7e64be81c8a7690703df5711f4fc2375da8a9cb jdk8-b103
|
||||
96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104
|
||||
5166118c59178b5d31001bc4058e92486ee07d9b jdk8-b105
|
||||
|
@ -69,11 +69,11 @@ else
|
||||
# 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.
|
||||
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-)))
|
||||
|
||||
$(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
|
||||
|
||||
.PHONY: $(all_phony_targets)
|
||||
@ -98,6 +98,7 @@ help:
|
||||
$(info . # corba and jdk)
|
||||
$(info . make all # Compile everything, all repos and 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 profiles # Create complete j2re compact profile images)
|
||||
$(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 )
|
||||
$(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>-only # Build <component> only, without dependencies. This)
|
||||
$(info . # is faster but can result in incorrect build results!)
|
||||
|
@ -1210,19 +1210,18 @@
|
||||
<blockquote>
|
||||
|
||||
<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?
|
||||
<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
|
||||
in <code>configure.ac</code> various .m4 files in common/autoconf,
|
||||
which are
|
||||
much more readable.
|
||||
in <code>configure.ac</code> and various .m4 files in common/autoconf,
|
||||
which are much more readable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<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?
|
||||
<br>
|
||||
<b>A:</b>
|
||||
@ -1237,13 +1236,29 @@
|
||||
<p>
|
||||
<b>Q:</b>
|
||||
Do you require a specific version of autoconf for regenerating
|
||||
<code>configure</code>?
|
||||
<code>generated-configure.sh</code>?
|
||||
<br>
|
||||
<b>A:</b>
|
||||
Currently, no, but this will likely be the case when things have
|
||||
settled down a bit more. (The reason for this is to avoid
|
||||
large spurious changes in <code>configure</code>
|
||||
in commits that made small changes to <code>configure.ac</code>).
|
||||
Yes, version 2.69 is required and should be easy
|
||||
enough to aquire on all supported operating
|
||||
systems. The reason for this is to avoid
|
||||
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>
|
||||
|
@ -44,10 +44,8 @@ fi
|
||||
custom_hook=$custom_script_dir/custom-hook.m4
|
||||
|
||||
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-2.67 found: ${AUTOCONF_267}"
|
||||
|
||||
if test "x${AUTOCONF}" = x; then
|
||||
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
|
||||
fi
|
||||
|
||||
if test "x${AUTOCONF_267}" != x; then
|
||||
AUTOCONF=${AUTOCONF_267};
|
||||
fi
|
||||
|
||||
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
|
||||
rm -rf autom4te.cache
|
||||
|
@ -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_CONFIG_AUX_DIR([build-aux])
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -83,7 +83,7 @@ apt_help() {
|
||||
pulse)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libpulse-dev" ;;
|
||||
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)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install ccache" ;;
|
||||
* )
|
||||
@ -102,11 +102,11 @@ yum_help() {
|
||||
cups)
|
||||
PKGHANDLER_COMMAND="sudo yum install cups-devel" ;;
|
||||
freetype2)
|
||||
PKGHANDLER_COMMAND="sudo yum install freetype2-devel" ;;
|
||||
PKGHANDLER_COMMAND="sudo yum install freetype-devel" ;;
|
||||
pulse)
|
||||
PKGHANDLER_COMMAND="sudo yum install pulseaudio-libs-devel" ;;
|
||||
x11)
|
||||
PKGHANDLER_COMMAND="sudo yum install libXtst-devel" ;;
|
||||
PKGHANDLER_COMMAND="sudo yum install libXtst-devel libXt-devel libXrender-devel" ;;
|
||||
ccache)
|
||||
PKGHANDLER_COMMAND="sudo yum install ccache" ;;
|
||||
* )
|
||||
|
@ -185,7 +185,7 @@ OLD_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $X_CFLAGS"
|
||||
|
||||
# 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=no; break],
|
||||
[ # 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
|
||||
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
|
||||
|
||||
AC_SUBST(X_CFLAGS)
|
||||
|
@ -183,7 +183,7 @@ bootcycle-images-only: start-make
|
||||
test: images test-only
|
||||
test-only: start-make
|
||||
@$(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)
|
||||
|
||||
# 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-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: profiles profiles-only profiles-oscheck
|
||||
|
||||
|
@ -371,3 +371,5 @@ c4697c1c448416108743b59118b4a2498b339d0c jdk8-b102
|
||||
580430d131ccd475e2f2ad4006531b8c4813d102 hs25-b46
|
||||
104743074675359cfbf7f4dcd9ab2a5974a16627 jdk8-b104
|
||||
c1604d5885a6f2adc0bcea2fa142a8f6bafad2f0 hs25-b47
|
||||
acac3bde66b2c22791c257a8d99611d6d08c6713 jdk8-b105
|
||||
18b4798adbc42c6fa16f5ecb7d5cd3ca130754bf hs25-b48
|
||||
|
@ -35,8 +35,9 @@ sapkg.c1 = sapkg.hotspot.c1;
|
||||
sapkg.code = sapkg.hotspot.code;
|
||||
sapkg.compiler = sapkg.hotspot.compiler;
|
||||
|
||||
// 'debugger' is a JavaScript keyword :-(
|
||||
// sapkg.debugger = sapkg.hotspot.debugger;
|
||||
// 'debugger' is a JavaScript keyword, but ES5 relaxes the
|
||||
// restriction of using keywords as property name
|
||||
sapkg.debugger = sapkg.hotspot.debugger;
|
||||
|
||||
sapkg.interpreter = sapkg.hotspot.interpreter;
|
||||
sapkg.jdi = sapkg.hotspot.jdi;
|
||||
@ -116,27 +117,36 @@ function main(globals, jvmarg) {
|
||||
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) {
|
||||
return new JSAdapter() {
|
||||
__getIds__: function() {
|
||||
return so.getIds();
|
||||
__getIds__: function() {
|
||||
return so.getIds();
|
||||
},
|
||||
|
||||
__has__ : function(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;
|
||||
}
|
||||
}
|
||||
},
|
||||
__has__ : __has__,
|
||||
|
||||
__delete__ : function(name) {
|
||||
if (typeof(name) == 'number') {
|
||||
@ -147,7 +157,8 @@ function main(globals, jvmarg) {
|
||||
},
|
||||
|
||||
__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;
|
||||
}
|
||||
if (typeof(name) == 'number') {
|
||||
@ -162,7 +173,7 @@ function main(globals, jvmarg) {
|
||||
var args = prepareArgsArray(arguments);
|
||||
var r;
|
||||
try {
|
||||
r = value.call(args);
|
||||
r = value.call(Java.to(args, 'java.lang.Object[]'));
|
||||
} catch (e) {
|
||||
println("call to " + name + " failed!");
|
||||
throw e;
|
||||
@ -204,6 +215,18 @@ function main(globals, jvmarg) {
|
||||
}
|
||||
|
||||
// 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') {
|
||||
writeln = println;
|
||||
}
|
||||
@ -235,7 +258,7 @@ function main(globals, jvmarg) {
|
||||
|
||||
this.jclasses = function() {
|
||||
forEachKlass(function (clazz) {
|
||||
writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString());
|
||||
writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
|
||||
});
|
||||
}
|
||||
registerCommand("classes", "classes", "jclasses");
|
||||
@ -490,14 +513,14 @@ function systemLoader() {
|
||||
function forEachKlass(callback) {
|
||||
var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor;
|
||||
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
|
||||
function forEachKlassAndLoader(callback) {
|
||||
var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
|
||||
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
|
||||
@ -522,7 +545,12 @@ function obj2oop(obj) {
|
||||
|
||||
// iterates Java heap for each Oop
|
||||
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'.
|
||||
@ -536,8 +564,14 @@ function forEachOopOfKlass(callback, klass, includeSubtypes) {
|
||||
if (includeSubtypes == undefined) {
|
||||
includeSubtypes = true;
|
||||
}
|
||||
|
||||
function empty() { }
|
||||
sa.objHeap.iterateObjectsOfKlass(
|
||||
new sapkg.oops.HeapVisitor() { doObj: callback },
|
||||
new sapkg.oops.HeapVisitor() {
|
||||
prologue: empty,
|
||||
doObj: callback,
|
||||
epilogue: empty
|
||||
},
|
||||
klass, includeSubtypes);
|
||||
}
|
||||
|
||||
@ -746,9 +780,9 @@ while (tmp.itr.hasNext()) {
|
||||
// ignore;
|
||||
continue;
|
||||
} else {
|
||||
// some type names have ':'. replace to make it as a
|
||||
// some type names have ':', '<', '>', '*', ' '. replace to make it as a
|
||||
// JavaScript identifier
|
||||
tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_');
|
||||
tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_');
|
||||
eval("function read" + tmp.name + "(addr) {" +
|
||||
" return readVMType('" + tmp.name + "', addr);}");
|
||||
eval("function print" + tmp.name + "(addr) {" +
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
|
||||
|
||||
HS_MAJOR_VER=25
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=47
|
||||
HS_BUILD_NUMBER=48
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=8
|
||||
|
@ -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.
|
||||
#
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
@ -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.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -398,3 +398,10 @@ endif
|
||||
ifdef MINIMIZE_RAM_USAGE
|
||||
CFLAGS += -DMINIMIZE_RAM_USAGE
|
||||
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
|
||||
|
@ -42,8 +42,6 @@ else
|
||||
MKS_HOME=`dirname "$SH"`
|
||||
fi
|
||||
|
||||
echo "EXPORTS" > vm1.def
|
||||
|
||||
AWK="$MKS_HOME/awk.exe"
|
||||
if [ ! -e $AWK ]; then
|
||||
AWK="$MKS_HOME/gawk.exe"
|
||||
@ -55,6 +53,22 @@ CAT="$MKS_HOME/cat.exe"
|
||||
RM="$MKS_HOME/rm.exe"
|
||||
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
|
||||
if [ "x$1" != "x" ]; then
|
||||
LD_VER="$1"
|
||||
|
@ -49,9 +49,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-debug
|
||||
# Force resources to be rebuilt every time
|
||||
$(Res_Files): FORCE
|
||||
|
||||
vm.def: $(Obj_Files)
|
||||
sh $(WorkSpace)/make/windows/build_vm_def.sh
|
||||
|
||||
$(AOUT): $(Res_Files) $(Obj_Files) vm.def
|
||||
$(LD) @<<
|
||||
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)
|
||||
|
@ -48,9 +48,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-fastdebug
|
||||
# Force resources to be rebuilt every time
|
||||
$(Res_Files): FORCE
|
||||
|
||||
vm.def: $(Obj_Files)
|
||||
sh $(WorkSpace)/make/windows/build_vm_def.sh
|
||||
|
||||
$(AOUT): $(Res_Files) $(Obj_Files) vm.def
|
||||
$(LD) @<<
|
||||
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)
|
||||
|
@ -51,9 +51,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)
|
||||
# Force resources to be rebuilt every time
|
||||
$(Res_Files): FORCE
|
||||
|
||||
vm.def: $(Obj_Files)
|
||||
sh $(WorkSpace)/make/windows/build_vm_def.sh
|
||||
|
||||
$(AOUT): $(Res_Files) $(Obj_Files) vm.def
|
||||
$(LD) @<<
|
||||
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)
|
||||
|
@ -92,6 +92,10 @@ ProjectCreatorIDEOptions = \
|
||||
-disablePch getThread_windows_$(Platform_arch).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
|
||||
ProjectCreatorIDEOptions=\
|
||||
$(ProjectCreatorIDEOptions) \
|
||||
@ -104,7 +108,7 @@ ProjectCreatorIDEOptions=\
|
||||
-jdkTargetRoot $(HOTSPOTJDKDIST) \
|
||||
-define ALIGN_STACK_FRAMES \
|
||||
-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 jvmtiEnvRecommended.cpp \
|
||||
-ignoreFile jvmtiEnvStub.cpp \
|
||||
|
@ -393,3 +393,11 @@ default::
|
||||
_build_pch_file.obj:
|
||||
@echo #include "precompiled.hpp" > ../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)
|
||||
|
||||
|
@ -642,13 +642,14 @@ objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NU
|
||||
#endif
|
||||
|
||||
#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
|
||||
thread_identifier_info_data_t m_ident_info;
|
||||
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);
|
||||
|
||||
return m_ident_info.thread_id;
|
||||
}
|
||||
#endif
|
||||
@ -679,9 +680,14 @@ static void *java_start(Thread *thread) {
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// thread_id is mach thread on macos
|
||||
osthread->set_thread_id(::mach_thread_self());
|
||||
osthread->set_unique_thread_id(locate_unique_thread_id());
|
||||
// thread_id is mach thread on macos, which pthreads graciously caches and provides for us
|
||||
mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self());
|
||||
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
|
||||
// thread_id is pthread_id on BSD
|
||||
osthread->set_thread_id(::pthread_self());
|
||||
@ -843,8 +849,14 @@ bool os::create_attached_thread(JavaThread* thread) {
|
||||
|
||||
// Store pthread info into the OSThread
|
||||
#ifdef __APPLE__
|
||||
osthread->set_thread_id(::mach_thread_self());
|
||||
osthread->set_unique_thread_id(locate_unique_thread_id());
|
||||
// thread_id is mach thread on macos, which pthreads graciously caches and provides for us
|
||||
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
|
||||
osthread->set_thread_id(::pthread_self());
|
||||
#endif
|
||||
@ -1115,7 +1127,7 @@ size_t os::lasterror(char *buf, size_t len) {
|
||||
|
||||
intx os::current_thread_id() {
|
||||
#ifdef __APPLE__
|
||||
return (intx)::mach_thread_self();
|
||||
return (intx)::pthread_mach_thread_np(::pthread_self());
|
||||
#else
|
||||
return (intx)::pthread_self();
|
||||
#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
|
||||
// the code cache doesn't have an SHM_X executable permission to check.
|
||||
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
|
||||
if (CheckJNICalls) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -4736,3 +4754,8 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void TestReserveMemorySpecial_test() {
|
||||
// No tests available for this platform
|
||||
}
|
||||
#endif
|
||||
|
@ -40,6 +40,9 @@
|
||||
product(bool, UseHugeTLBFS, false, \
|
||||
"Use MAP_HUGETLB for large pages") \
|
||||
\
|
||||
product(bool, UseTransparentHugePages, false, \
|
||||
"Use MADV_HUGEPAGE for large pages") \
|
||||
\
|
||||
product(bool, LoadExecStackDllInVMThread, true, \
|
||||
"Load DLLs with executable-stack attribute in the VM Thread") \
|
||||
\
|
||||
|
@ -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,
|
||||
size_t alignment_hint, bool exec) {
|
||||
int err;
|
||||
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);
|
||||
int err = os::Linux::commit_memory_impl(addr, size, exec);
|
||||
if (err == 0) {
|
||||
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) {
|
||||
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
|
||||
// be supported or the memory may already be backed by huge pages.
|
||||
::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
|
||||
// small pages on top of the SHM segment. This method always works for small pages, so we
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -3157,11 +3128,31 @@ bool os::unguard_memory(char* addr, size_t size) {
|
||||
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 result = false;
|
||||
void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
|
||||
-1, 0);
|
||||
void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
|
||||
-1, 0);
|
||||
|
||||
if (p != MAP_FAILED) {
|
||||
// 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);
|
||||
}
|
||||
munmap (p, page_size);
|
||||
if (result)
|
||||
return true;
|
||||
munmap(p, page_size);
|
||||
}
|
||||
|
||||
if (warn) {
|
||||
if (warn && !result) {
|
||||
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;
|
||||
|
||||
void os::large_page_init() {
|
||||
if (!UseLargePages) {
|
||||
UseHugeTLBFS = false;
|
||||
UseSHM = false;
|
||||
return;
|
||||
}
|
||||
size_t os::Linux::find_large_page_size() {
|
||||
size_t large_page_size = 0;
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) {
|
||||
// If UseLargePages is specified on the command line try both methods,
|
||||
// if it's default, then try only HugeTLBFS.
|
||||
if (FLAG_IS_DEFAULT(UseLargePages)) {
|
||||
UseHugeTLBFS = true;
|
||||
} else {
|
||||
UseHugeTLBFS = UseSHM = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LargePageSizeInBytes) {
|
||||
_large_page_size = LargePageSizeInBytes;
|
||||
} 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.
|
||||
// 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
|
||||
_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);
|
||||
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);
|
||||
#endif // ZERO
|
||||
|
||||
FILE *fp = fopen("/proc/meminfo", "r");
|
||||
if (fp) {
|
||||
while (!feof(fp)) {
|
||||
int x = 0;
|
||||
char buf[16];
|
||||
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
|
||||
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
|
||||
_large_page_size = x * K;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// skip to next line
|
||||
for (;;) {
|
||||
int ch = fgetc(fp);
|
||||
if (ch == EOF || ch == (int)'\n') break;
|
||||
}
|
||||
FILE *fp = fopen("/proc/meminfo", "r");
|
||||
if (fp) {
|
||||
while (!feof(fp)) {
|
||||
int x = 0;
|
||||
char buf[16];
|
||||
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
|
||||
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
|
||||
large_page_size = x * K;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// skip to next line
|
||||
for (;;) {
|
||||
int ch = fgetc(fp);
|
||||
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
|
||||
bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
|
||||
if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) {
|
||||
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();
|
||||
if (_large_page_size > default_page_size) {
|
||||
_page_sizes[0] = _large_page_size;
|
||||
_page_sizes[1] = default_page_size;
|
||||
_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;
|
||||
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();
|
||||
}
|
||||
@ -3319,16 +3340,22 @@ void os::large_page_init() {
|
||||
#define SHM_HUGETLB 04000
|
||||
#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
|
||||
// the code cache doesn't have an SHM_X executable permission to check.
|
||||
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;
|
||||
char *addr;
|
||||
|
||||
bool warn_on_failure = UseLargePages &&
|
||||
(!FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(UseSHM) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes)
|
||||
);
|
||||
char msg[128];
|
||||
@ -3376,42 +3403,219 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((addr != NULL) && UseNUMAInterleaving) {
|
||||
numa_make_global(addr, bytes);
|
||||
return addr;
|
||||
}
|
||||
|
||||
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
|
||||
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
|
||||
assert(is_ptr_aligned(addr, os::large_page_size()), "Must be");
|
||||
|
||||
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) {
|
||||
assert(UseLargePages, "only for large pages");
|
||||
|
||||
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);
|
||||
if (rslt == 0) {
|
||||
|
||||
bool res;
|
||||
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);
|
||||
return true;
|
||||
} else {
|
||||
tkr.discard();
|
||||
return false;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t os::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.
|
||||
// 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() {
|
||||
return UseHugeTLBFS;
|
||||
return UseTransparentHugePages;
|
||||
}
|
||||
|
||||
bool os::can_execute_large_page_memory() {
|
||||
return UseHugeTLBFS;
|
||||
return UseTransparentHugePages || UseHugeTLBFS;
|
||||
}
|
||||
|
||||
// Reserve memory at an arbitrary address, only if that area is
|
||||
@ -4563,21 +4767,23 @@ jint os::init_2(void)
|
||||
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
|
||||
// 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.
|
||||
if (UseNUMA && UseLargePages && UseSHM) {
|
||||
if (!FLAG_IS_DEFAULT(UseNUMA)) {
|
||||
if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) {
|
||||
if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
|
||||
if (FLAG_IS_DEFAULT(UseNUMA)) {
|
||||
UseNUMA = false;
|
||||
} else {
|
||||
if (FLAG_IS_DEFAULT(UseLargePages) &&
|
||||
FLAG_IS_DEFAULT(UseSHM) &&
|
||||
FLAG_IS_DEFAULT(UseHugeTLBFS)) {
|
||||
UseLargePages = false;
|
||||
} 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;
|
||||
UseAdaptiveNUMAChunkSizing = false;
|
||||
}
|
||||
} else {
|
||||
UseNUMA = false;
|
||||
}
|
||||
}
|
||||
if (!UseNUMA && ForceNUMA) {
|
||||
@ -5848,3 +6054,149 @@ void MemNotifyThread::start() {
|
||||
}
|
||||
|
||||
#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
|
||||
|
@ -32,6 +32,7 @@ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *);
|
||||
|
||||
class Linux {
|
||||
friend class os;
|
||||
friend class TestReserveMemorySpecial;
|
||||
|
||||
// For signal-chaining
|
||||
#define MAXSIGNUM 32
|
||||
@ -92,8 +93,21 @@ class Linux {
|
||||
static void rebuild_cpu_to_node_map();
|
||||
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 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_distro_info(outputStream* st);
|
||||
static void print_libversion_info(outputStream* st);
|
||||
|
@ -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.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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() {
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
|
||||
}
|
||||
|
@ -3385,7 +3385,7 @@ bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
|
||||
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.");
|
||||
return NULL;
|
||||
}
|
||||
@ -6601,3 +6601,9 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
|
||||
|
||||
return strlen(buffer);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void TestReserveMemorySpecial_test() {
|
||||
// No tests available for this platform
|
||||
}
|
||||
#endif
|
||||
|
@ -3156,7 +3156,12 @@ bool os::can_execute_large_page_memory() {
|
||||
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 flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
|
||||
@ -5394,6 +5399,75 @@ inline BOOL os::Advapi32Dll::AdvapiAvailable() {
|
||||
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
|
||||
// Kernel32 API
|
||||
typedef BOOL (WINAPI* SwitchToThread_Fn)(void);
|
||||
@ -5638,3 +5712,9 @@ BOOL os::Advapi32Dll::AdvapiAvailable() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
void TestReserveMemorySpecial_test() {
|
||||
// No tests available for this platform
|
||||
}
|
||||
#endif
|
||||
|
@ -3460,7 +3460,9 @@ void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) {
|
||||
void ConcurrentMarkSweepGeneration::shrink(size_t bytes) {
|
||||
assert_locked_or_safepoint(Heap_lock);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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.");
|
||||
HeapWord* const eob = ((HeapWord*)fc) + chunk_size;
|
||||
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 ")",
|
||||
_limit, _sp->bottom(), _sp->end(), fc, chunk_size));
|
||||
eob, eob-1, _limit, _sp->bottom(), _sp->end(), fc, chunk_size));
|
||||
if (eob >= _limit) {
|
||||
assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit");
|
||||
if (CMSTraceSweeper) {
|
||||
|
@ -981,7 +981,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
|
||||
|
||||
if (should_try_gc) {
|
||||
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) {
|
||||
assert(succeeded, "only way to get back a non-NULL 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.
|
||||
|
||||
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) {
|
||||
assert(succeeded, "only way to get back a non-NULL result");
|
||||
return result;
|
||||
@ -2006,10 +2008,12 @@ jint G1CollectedHeap::initialize() {
|
||||
|
||||
size_t init_byte_size = collector_policy()->initial_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.
|
||||
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, heap_alignment, "g1 heap");
|
||||
|
||||
_cg1r = new ConcurrentG1Refine(this);
|
||||
|
||||
@ -2026,12 +2030,8 @@ jint G1CollectedHeap::initialize() {
|
||||
// If this happens then we could end up using a non-optimal
|
||||
// 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,
|
||||
HeapRegion::GrainBytes);
|
||||
heap_alignment);
|
||||
|
||||
// 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
|
||||
@ -3700,14 +3700,15 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) {
|
||||
|
||||
HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
|
||||
unsigned int gc_count_before,
|
||||
bool* succeeded) {
|
||||
bool* succeeded,
|
||||
GCCause::Cause gc_cause) {
|
||||
assert_heap_not_locked_and_not_at_safepoint();
|
||||
g1_policy()->record_stop_world_start();
|
||||
VM_G1IncCollectionPause op(gc_count_before,
|
||||
word_size,
|
||||
false, /* should_initiate_conc_mark */
|
||||
g1_policy()->max_pause_time_ms(),
|
||||
GCCause::_g1_inc_collection_pause);
|
||||
gc_cause);
|
||||
VMThread::execute(&op);
|
||||
|
||||
HeapWord* result = op.result();
|
||||
|
@ -776,9 +776,10 @@ protected:
|
||||
// it has to be read while holding the Heap_lock. Currently, both
|
||||
// methods that call do_collection_pause() release the Heap_lock
|
||||
// before the call, so it's easy to read gc_count_before just before.
|
||||
HeapWord* do_collection_pause(size_t word_size,
|
||||
unsigned int gc_count_before,
|
||||
bool* succeeded);
|
||||
HeapWord* do_collection_pause(size_t word_size,
|
||||
unsigned int gc_count_before,
|
||||
bool* succeeded,
|
||||
GCCause::Cause gc_cause);
|
||||
|
||||
// The guts of the incremental collection pause, executed by the vm
|
||||
// thread. It returns false if it is unable to do the collection due
|
||||
|
@ -313,7 +313,8 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
||||
void G1CollectorPolicy::initialize_flags() {
|
||||
set_min_alignment(HeapRegion::GrainBytes);
|
||||
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) {
|
||||
vm_exit_during_initialization("Invalid survivor ratio specified");
|
||||
}
|
||||
|
@ -70,9 +70,6 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause(
|
||||
guarantee(target_pause_time_ms > 0.0,
|
||||
err_msg("target_pause_time_ms = %1.6lf should be positive",
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -666,7 +666,7 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC {
|
||||
NEW_RESOURCE_ARRAY_RETURN_NULL(type, 1)
|
||||
|
||||
#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)\
|
||||
(type*) (AllocateHeap((size) * sizeof(type), memflags, pc))
|
||||
@ -675,16 +675,16 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC {
|
||||
(type*) (AllocateHeap((size) * sizeof(type), memflags))
|
||||
|
||||
#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)\
|
||||
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)\
|
||||
(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)\
|
||||
(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) \
|
||||
FreeHeap((char*)(old), memflags)
|
||||
|
@ -193,6 +193,8 @@ size_t GenCollectorPolicy::compute_max_alignment() {
|
||||
alignment = lcm(os::large_page_size(), alignment);
|
||||
}
|
||||
|
||||
assert(alignment >= min_alignment(), "Must be");
|
||||
|
||||
return alignment;
|
||||
}
|
||||
|
||||
|
@ -95,13 +95,13 @@ jint GenCollectedHeap::initialize() {
|
||||
guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize");
|
||||
|
||||
// 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();
|
||||
|
||||
// Make sure the sizes are all aligned.
|
||||
for (i = 0; i < _n_gens; i++) {
|
||||
_gen_specs[i]->align(alignment);
|
||||
_gen_specs[i]->align(gen_alignment);
|
||||
}
|
||||
|
||||
// Allocate space for the heap.
|
||||
@ -109,9 +109,11 @@ jint GenCollectedHeap::initialize() {
|
||||
char* heap_address;
|
||||
size_t total_reserved = 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);
|
||||
|
||||
if (!heap_rs.is_reserved()) {
|
||||
@ -168,6 +170,8 @@ char* GenCollectedHeap::allocate(size_t alignment,
|
||||
const size_t pageSize = UseLargePages ?
|
||||
os::large_page_size() : os::vm_page_size();
|
||||
|
||||
assert(alignment % pageSize == 0, "Must be");
|
||||
|
||||
for (int i = 0; i < _n_gens; i++) {
|
||||
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();
|
||||
}
|
||||
assert(total_reserved % pageSize == 0,
|
||||
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize="
|
||||
SIZE_FORMAT, total_reserved, pageSize));
|
||||
assert(total_reserved % alignment == 0,
|
||||
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment="
|
||||
SIZE_FORMAT, total_reserved, alignment));
|
||||
|
||||
// Needed until the cardtable is fixed to have the right number
|
||||
// of covered regions.
|
||||
n_covered_regions += 2;
|
||||
|
||||
if (UseLargePages) {
|
||||
assert(total_reserved != 0, "total_reserved cannot be 0");
|
||||
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;
|
||||
|
||||
*_total_reserved = total_reserved;
|
||||
*_n_covered_regions = n_covered_regions;
|
||||
*heap_rs = Universe::reserve_heap(total_reserved, alignment);
|
||||
return heap_rs->base();
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
|
||||
};
|
||||
|
||||
// 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
|
||||
byte_size = align_size_up(byte_size, os::vm_allocation_granularity());
|
||||
|
||||
|
@ -681,17 +681,23 @@ static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1);
|
||||
// 32Gb
|
||||
// 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;
|
||||
#ifdef _LP64
|
||||
if (UseCompressedOops) {
|
||||
assert(mode == UnscaledNarrowOop ||
|
||||
mode == ZeroBasedNarrowOop ||
|
||||
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.
|
||||
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
|
||||
// just use UnscaledNarrowOop.
|
||||
@ -742,6 +748,8 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(is_ptr_aligned((char*)base, alignment), "Must be");
|
||||
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);
|
||||
assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),
|
||||
"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 (addr != NULL && !total_rs.is_reserved()) {
|
||||
// Failed to reserve at specified address - the requested memory
|
||||
// region is taken already, for example, by 'java' launcher.
|
||||
// Try again to reserver heap higher.
|
||||
addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop);
|
||||
addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);
|
||||
|
||||
ReservedHeapSpace total_rs0(total_reserved, alignment,
|
||||
UseLargePages, addr);
|
||||
use_large_pages, addr);
|
||||
|
||||
if (addr != NULL && !total_rs0.is_reserved()) {
|
||||
// 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, "");
|
||||
|
||||
ReservedHeapSpace total_rs1(total_reserved, alignment,
|
||||
UseLargePages, addr);
|
||||
use_large_pages, addr);
|
||||
total_rs = total_rs1;
|
||||
} else {
|
||||
total_rs = total_rs0;
|
||||
|
@ -346,7 +346,7 @@ class Universe: AllStatic {
|
||||
};
|
||||
static NARROW_OOP_MODE narrow_oop_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 address narrow_oop_base() { return _narrow_oop._base; }
|
||||
static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); }
|
||||
|
@ -3234,19 +3234,22 @@ JNI_QUICK_ENTRY(const jchar*, jni_GetStringChars(
|
||||
HOTSPOT_JNI_GETSTRINGCHARS_ENTRY(
|
||||
env, string, (uintptr_t *) isCopy);
|
||||
#endif /* USDT2 */
|
||||
//%note jni_5
|
||||
if (isCopy != NULL) {
|
||||
*isCopy = JNI_TRUE;
|
||||
}
|
||||
oop s = JNIHandles::resolve_non_null(string);
|
||||
int s_len = java_lang_String::length(s);
|
||||
typeArrayOop s_value = java_lang_String::value(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
|
||||
if (s_len > 0) {
|
||||
memcpy(buf, s_value->char_at_addr(s_offset), sizeof(jchar)*s_len);
|
||||
jchar* buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination
|
||||
/* JNI Specification states return NULL on OOM */
|
||||
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
|
||||
DTRACE_PROBE1(hotspot_jni, GetStringChars__return, buf);
|
||||
#else /* USDT2 */
|
||||
@ -3335,9 +3338,14 @@ JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboole
|
||||
#endif /* USDT2 */
|
||||
oop java_string = JNIHandles::resolve_non_null(string);
|
||||
size_t length = java_lang_String::utf8_length(java_string);
|
||||
char* result = AllocateHeap(length + 1, mtInternal);
|
||||
java_lang_String::as_utf8_string(java_string, result, (int) length + 1);
|
||||
if (isCopy != NULL) *isCopy = JNI_TRUE;
|
||||
/* JNI Specification states return NULL on OOM */
|
||||
char* result = AllocateHeap(length + 1, mtInternal, 0, AllocFailStrategy::RETURN_NULL);
|
||||
if (result != NULL) {
|
||||
java_lang_String::as_utf8_string(java_string, result, (int) length + 1);
|
||||
if (isCopy != NULL) {
|
||||
*isCopy = JNI_TRUE;
|
||||
}
|
||||
}
|
||||
#ifndef USDT2
|
||||
DTRACE_PROBE1(hotspot_jni, GetStringUTFChars__return, result);
|
||||
#else /* USDT2 */
|
||||
@ -3591,11 +3599,16 @@ JNI_QUICK_ENTRY(ElementType*, \
|
||||
* Avoid asserts in typeArrayOop. */ \
|
||||
result = (ElementType*)get_bad_address(); \
|
||||
} else { \
|
||||
result = NEW_C_HEAP_ARRAY(ElementType, len, mtInternal); \
|
||||
/* copy the array to the c chunk */ \
|
||||
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len); \
|
||||
/* JNI Specification states return NULL on OOM */ \
|
||||
result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \
|
||||
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);\
|
||||
return result; \
|
||||
JNI_END
|
||||
@ -3628,11 +3641,16 @@ JNI_QUICK_ENTRY(ElementType*, \
|
||||
* Avoid asserts in typeArrayOop. */ \
|
||||
result = (ElementType*)get_bad_address(); \
|
||||
} else { \
|
||||
result = NEW_C_HEAP_ARRAY(ElementType, len, mtInternal); \
|
||||
/* copy the array to the c chunk */ \
|
||||
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len); \
|
||||
/* JNI Specification states return NULL on OOM */ \
|
||||
result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \
|
||||
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; \
|
||||
return result; \
|
||||
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); \
|
||||
unit_test_function_call
|
||||
|
||||
// Forward declaration
|
||||
void TestReservedSpace_test();
|
||||
void TestReserveMemorySpecial_test();
|
||||
|
||||
void execute_internal_vm_tests() {
|
||||
if (ExecuteInternalVMTests) {
|
||||
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(GCTimerAllTest::all());
|
||||
run_unit_test(arrayOopDesc::test_max_array_length());
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<?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.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
@ -358,7 +358,7 @@
|
||||
<specification label="JVM(TM) Tool Interface"
|
||||
majorversion="1"
|
||||
minorversion="2"
|
||||
microversion="2">
|
||||
microversion="3">
|
||||
<title subtitle="Version">
|
||||
<tm>JVM</tm> Tool Interface
|
||||
</title>
|
||||
@ -431,12 +431,46 @@
|
||||
On the <tm>Solaris</tm> Operating Environment, an agent library is a shared
|
||||
object (<code>.so</code> file).
|
||||
<p/>
|
||||
|
||||
An agent may be started at VM startup by specifying the agent library
|
||||
name using a <internallink id="starting">command line option</internallink>.
|
||||
Some implementations may support a mechanism to <internallink id="onattach">
|
||||
start agents</internallink> in the live <functionlink id="GetPhase">phase</functionlink>.
|
||||
The details of how this is initiated are implementation specific.
|
||||
</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">
|
||||
The term "command-line option" is used below to
|
||||
@ -455,7 +489,7 @@
|
||||
<dd>
|
||||
The name following <code>-agentlib:</code> is the name of the
|
||||
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><agent-lib-name></i> is expanded to an
|
||||
operating system specific file name.
|
||||
The <i><options></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
|
||||
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
|
||||
<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>
|
||||
<dt><code>-agentpath:</code><i><path-to-agent></i><code>=</code><i><options></i></dt>
|
||||
<dd>
|
||||
@ -473,11 +511,20 @@
|
||||
The <i><options></i> will be passed to the agent on start-up.
|
||||
For example, if the option
|
||||
<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>
|
||||
</dl>
|
||||
The start-up routine <internallink id="onload"><code>Agent_OnLoad</code></internallink>
|
||||
in the library will be invoked.
|
||||
For a dynamic shared library agent, the start-up routine
|
||||
<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_<agent-lib-name></code> entry point where
|
||||
<agent-lib-name> 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/>
|
||||
Libraries loaded with <code>-agentlib:</code> or <code>-agentpath:</code>
|
||||
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>
|
||||
<functionlink id="GetPhase">phase</functionlink> the function
|
||||
<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
|
||||
<functionlink id="GetPhase">phase</functionlink> the function
|
||||
<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.
|
||||
</intro>
|
||||
|
||||
@ -516,6 +565,11 @@
|
||||
<example>
|
||||
JNIEXPORT jint JNICALL
|
||||
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.
|
||||
It will be called early enough in VM initialization that:
|
||||
<ul>
|
||||
@ -531,7 +585,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
|
||||
<li>no objects have been created</li>
|
||||
</ul>
|
||||
<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_<agent-lib-name></code> function with
|
||||
<i><options></i> as the second argument -
|
||||
that is, using the command-line option examples,
|
||||
<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.
|
||||
If <i>=<options></i> is not specified,
|
||||
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_<agent-lib-name></code>
|
||||
call. If needed beyond this time the string or parts of the string must
|
||||
be copied.
|
||||
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.
|
||||
</rationale>
|
||||
<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_<agent-lib-name></code> is used to indicate an error.
|
||||
Any value other than zero indicates an error and causes termination of the VM.
|
||||
</intro>
|
||||
|
||||
@ -587,6 +644,11 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
|
||||
<example>
|
||||
JNIEXPORT jint JNICALL
|
||||
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/>
|
||||
The VM will start the agent by calling this function.
|
||||
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.
|
||||
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>Agent_OnAttach</code> call. If needed beyond this time the string or parts of
|
||||
the string must be copied.
|
||||
<code>Agent_OnAttach</code> or <code>Agent_OnAttach_<agent-lib-name></code> call.
|
||||
If needed beyond this time the string or parts of the string must be copied.
|
||||
<p/>
|
||||
Note that some <internallink id="capability">capabilities</internallink>
|
||||
may not be available in the live phase.
|
||||
<p/>
|
||||
The <code>Agent_OnAttach</code> function initializes the agent and returns a value
|
||||
The <code>Agent_OnAttach</code> or <code>Agent_OnAttach_<agent-lib-name
|
||||
></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.
|
||||
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,
|
||||
@ -615,8 +678,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
|
||||
<example>
|
||||
JNIEXPORT void JNICALL
|
||||
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.
|
||||
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)
|
||||
or the library is (in effect) unloaded by the termination of the VM whether through
|
||||
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
|
||||
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
|
||||
and enabled the event
|
||||
None of these are required for <code>Agent_OnUnload</code> and this function
|
||||
and enabled the event.
|
||||
None of these are required for <code>Agent_OnUnload</code> or
|
||||
<code>Agent_OnUnload_<agent-lib-name></code> and this function
|
||||
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
|
||||
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">
|
||||
<constant id="JVMTI_PHASE_ONLOAD" num="1">
|
||||
<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_<agent-lib-name>
|
||||
</code></internallink> function.
|
||||
</constant>
|
||||
<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_<agent-lib-name></code> and the
|
||||
<code>VMStart</code> event.
|
||||
</constant>
|
||||
<constant id="JVMTI_PHASE_START" num="6">
|
||||
@ -14261,6 +14335,9 @@ typedef void (JNICALL *jvmtiEventVMInit)
|
||||
<change date="11 October 2012" version="1.2.2">
|
||||
Fixed the "HTTP" and "Missing Anchor" errors reported by the LinkCheck tool.
|
||||
</change>
|
||||
<change date="19 June 2013" version="1.2.3">
|
||||
Added support for statically linked agents.
|
||||
</change>
|
||||
</changehistory>
|
||||
|
||||
</specification>
|
||||
|
@ -2191,6 +2191,8 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
|
||||
char buffer[JVM_MAXPATHLEN];
|
||||
void* library = NULL;
|
||||
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
|
||||
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"
|
||||
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
|
||||
// load it from the standard dll directory.
|
||||
// Check for statically linked in agent. If not found then if the path is
|
||||
// absolute we attempt to load the library. Otherwise we try to load it
|
||||
// from the standard dll directory.
|
||||
|
||||
if (is_absolute_path) {
|
||||
library = os::dll_load(agent, ebuf, sizeof ebuf);
|
||||
} else {
|
||||
// Try to load the agent from the standard dll directory
|
||||
if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
|
||||
agent)) {
|
||||
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)) {
|
||||
if (!os::find_builtin_agent(agent_lib, on_attach_symbols, num_symbol_entries)) {
|
||||
if (is_absolute_path) {
|
||||
library = os::dll_load(agent, ebuf, sizeof ebuf);
|
||||
} else {
|
||||
// Try to load the agent from the standard dll directory
|
||||
if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
|
||||
agent)) {
|
||||
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
|
||||
// function
|
||||
if (library != NULL) {
|
||||
|
||||
if (agent_lib->valid()) {
|
||||
// Lookup the Agent_OnAttach function
|
||||
OnAttachEntry_t on_attach_entry = NULL;
|
||||
const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS;
|
||||
for (uint symbol_index = 0; symbol_index < ARRAY_SIZE(on_attach_symbols); symbol_index++) {
|
||||
on_attach_entry =
|
||||
CAST_TO_FN_PTR(OnAttachEntry_t, os::dll_lookup(library, on_attach_symbols[symbol_index]));
|
||||
if (on_attach_entry != NULL) break;
|
||||
}
|
||||
|
||||
on_attach_entry = CAST_TO_FN_PTR(OnAttachEntry_t,
|
||||
os::find_agent_function(agent_lib, false, on_attach_symbols, num_symbol_entries));
|
||||
if (on_attach_entry == NULL) {
|
||||
// Agent_OnAttach missing - unload library
|
||||
os::dll_unload(library);
|
||||
if (!agent_lib->is_static_lib()) {
|
||||
os::dll_unload(library);
|
||||
}
|
||||
delete agent_lib;
|
||||
} else {
|
||||
// Invoke the Agent_OnAttach function
|
||||
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
|
||||
// agent libraries so that we can call Agent_OnUnload later.
|
||||
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
|
||||
|
@ -1554,18 +1554,22 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class,
|
||||
return false;
|
||||
}
|
||||
|
||||
// rewrite sourc file name index:
|
||||
// rewrite source file name index:
|
||||
u2 source_file_name_idx = scratch_class->source_file_name_index();
|
||||
if (source_file_name_idx != 0) {
|
||||
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:
|
||||
u2 generic_signature_index = scratch_class->generic_signature_index();
|
||||
if (generic_signature_index != 0) {
|
||||
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;
|
||||
@ -1737,7 +1741,10 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method,
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
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()
|
||||
|
@ -128,7 +128,7 @@ WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
|
||||
WB_END
|
||||
#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
|
||||
// NMT picks it up correctly
|
||||
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();
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env))
|
||||
return MemTracker::tracking_level() == MemTracker::NMT_detail;
|
||||
WB_END
|
||||
|
||||
#endif // INCLUDE_NMT
|
||||
|
||||
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"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize },
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
#ifdef INCLUDE_NMT
|
||||
#if INCLUDE_NMT
|
||||
{CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
|
||||
{CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree },
|
||||
{CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory },
|
||||
@ -447,6 +451,7 @@ static JNINativeMethod methods[] = {
|
||||
{CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory },
|
||||
{CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory },
|
||||
{CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge},
|
||||
{CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported},
|
||||
#endif // INCLUDE_NMT
|
||||
{CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll },
|
||||
{CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I",
|
||||
|
@ -118,11 +118,21 @@ class SystemProperty: public CHeapObj<mtInternal> {
|
||||
// For use by -agentlib, -agentpath and -Xrun
|
||||
class AgentLibrary : public CHeapObj<mtInternal> {
|
||||
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:
|
||||
char* _name;
|
||||
char* _options;
|
||||
void* _os_lib;
|
||||
bool _is_absolute_path;
|
||||
bool _is_static_lib;
|
||||
AgentState _state;
|
||||
AgentLibrary* _next;
|
||||
|
||||
public:
|
||||
@ -133,6 +143,11 @@ class AgentLibrary : public CHeapObj<mtInternal> {
|
||||
void* os_lib() const { return _os_lib; }
|
||||
void set_os_lib(void* os_lib) { _os_lib = os_lib; }
|
||||
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
|
||||
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;
|
||||
_os_lib = os_lib;
|
||||
_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)); }
|
||||
|
||||
// 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)
|
||||
{ _agentList.add(new AgentLibrary(name, options, absolute_path, os_lib)); }
|
||||
|
||||
|
@ -1933,6 +1933,9 @@ class CommandLineFlags {
|
||||
notproduct(bool, ExecuteInternalVMTests, false, \
|
||||
"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, ResizeTLAB, \
|
||||
|
@ -124,13 +124,15 @@ Monitor* GCTaskManager_lock = NULL;
|
||||
|
||||
Mutex* Management_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;
|
||||
Mutex* JfrBuffer_lock = NULL;
|
||||
Mutex* JfrStream_lock = NULL;
|
||||
Monitor* PeriodicTask_lock = NULL;
|
||||
Mutex* JfrThreadGroups_lock = NULL;
|
||||
#endif
|
||||
|
||||
#define MAX_NUM_MUTEX 128
|
||||
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(ObjAllocPost_lock , Monitor, special, false);
|
||||
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(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(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread
|
||||
def(CompileThread_lock , Monitor, nonleaf+5, false );
|
||||
def(PeriodicTask_lock , Monitor, nonleaf+5, true);
|
||||
|
||||
#ifdef INCLUDE_TRACE
|
||||
def(JfrMsg_lock , Monitor, leaf, true);
|
||||
def(JfrBuffer_lock , Mutex, nonleaf+1, true);
|
||||
def(JfrThreadGroups_lock , Mutex, nonleaf+1, 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) {
|
||||
|
@ -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 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 Mutex* JfrBuffer_lock; // protects JFR buffer operations
|
||||
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
|
||||
// for the scope which contains the locker. The lock is an OS lock, not
|
||||
|
@ -443,6 +443,67 @@ void* os::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 ---------------------
|
||||
|
||||
char *os::strdup(const char *str, MEMFLAGS flags) {
|
||||
|
@ -46,6 +46,8 @@
|
||||
# include <setjmp.h>
|
||||
#endif
|
||||
|
||||
class AgentLibrary;
|
||||
|
||||
// os defines the interface to operating system; this includes traditional
|
||||
// OS services (time, I/O) as well as other functionality with system-
|
||||
// dependent code.
|
||||
@ -328,8 +330,8 @@ class os: AllStatic {
|
||||
|
||||
static char* non_memory_address_word();
|
||||
// reserve, commit and pin the entire memory region
|
||||
static char* reserve_memory_special(size_t size, char* addr = NULL,
|
||||
bool executable = false);
|
||||
static char* reserve_memory_special(size_t size, size_t alignment,
|
||||
char* addr, bool executable);
|
||||
static bool release_memory_special(char* addr, size_t bytes);
|
||||
static void large_page_init();
|
||||
static size_t large_page_size();
|
||||
@ -537,6 +539,17 @@ class os: AllStatic {
|
||||
// Unload library
|
||||
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.
|
||||
// Output format may be different on different platforms.
|
||||
static void print_os_info(outputStream* st);
|
||||
@ -806,6 +819,11 @@ class os: AllStatic {
|
||||
// ResumeThread call)
|
||||
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 {
|
||||
public:
|
||||
SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {}
|
||||
|
@ -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.
|
||||
static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_symbols[], size_t num_symbol_entries) {
|
||||
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 ebuf[1024];
|
||||
const char *name = agent->name();
|
||||
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);
|
||||
if (library == NULL) {
|
||||
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_valid();
|
||||
}
|
||||
|
||||
// Find the OnLoad function.
|
||||
for (size_t symbol_index = 0; symbol_index < num_symbol_entries; symbol_index++) {
|
||||
on_load_entry = CAST_TO_FN_PTR(OnLoadEntry_t, os::dll_lookup(library, on_load_symbols[symbol_index]));
|
||||
if (on_load_entry != NULL) break;
|
||||
}
|
||||
on_load_entry =
|
||||
CAST_TO_FN_PTR(OnLoadEntry_t, os::find_agent_function(agent,
|
||||
false,
|
||||
on_load_symbols,
|
||||
num_symbol_entries));
|
||||
return on_load_entry;
|
||||
}
|
||||
|
||||
@ -3819,22 +3824,23 @@ extern "C" {
|
||||
void Threads::shutdown_vm_agents() {
|
||||
// Send any Agent_OnUnload notifications
|
||||
const char *on_unload_symbols[] = AGENT_ONUNLOAD_SYMBOLS;
|
||||
size_t num_symbol_entries = ARRAY_SIZE(on_unload_symbols);
|
||||
extern struct JavaVM_ main_vm;
|
||||
for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
|
||||
|
||||
// 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,
|
||||
os::dll_lookup(agent->os_lib(), on_unload_symbols[symbol_index]));
|
||||
Agent_OnUnload_t unload_entry = CAST_TO_FN_PTR(Agent_OnUnload_t,
|
||||
os::find_agent_function(agent,
|
||||
false,
|
||||
on_unload_symbols,
|
||||
num_symbol_entries));
|
||||
|
||||
// Invoke the Agent_OnUnload function
|
||||
if (unload_entry != NULL) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
ThreadToNativeFromVM ttn(thread);
|
||||
HandleMark hm(thread);
|
||||
(*unload_entry)(&main_vm);
|
||||
break;
|
||||
}
|
||||
// Invoke the Agent_OnUnload function
|
||||
if (unload_entry != NULL) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
ThreadToNativeFromVM ttn(thread);
|
||||
HandleMark hm(thread);
|
||||
(*unload_entry)(&main_vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,19 @@
|
||||
|
||||
|
||||
// ReservedSpace
|
||||
|
||||
// Dummy constructor
|
||||
ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0),
|
||||
_alignment(0), _special(false), _executable(false) {
|
||||
}
|
||||
|
||||
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,
|
||||
@ -129,16 +140,18 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
|
||||
|
||||
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 (failed_to_reserve_as_requested(base, requested_address, size, true)) {
|
||||
// OS ignored requested address. Try different address.
|
||||
return;
|
||||
}
|
||||
// Check alignment constraints
|
||||
// Check alignment constraints.
|
||||
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;
|
||||
} else {
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
/////////////// 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
|
||||
|
@ -53,6 +53,7 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
ReservedSpace();
|
||||
ReservedSpace(size_t size);
|
||||
ReservedSpace(size_t size, size_t alignment, bool large,
|
||||
char* requested_address = NULL,
|
||||
|
@ -876,8 +876,6 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap))
|
||||
total_used += u.used();
|
||||
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) {
|
||||
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),
|
||||
total_used,
|
||||
total_committed,
|
||||
|
@ -87,6 +87,8 @@ class MemTracker : AllStatic {
|
||||
MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
|
||||
static inline void record_virtual_memory_commit(address addr, size_t size,
|
||||
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,
|
||||
Thread* thread = NULL) { }
|
||||
static inline Tracker get_realloc_tracker() { return _tkr; }
|
||||
@ -372,6 +374,13 @@ class MemTracker : AllStatic {
|
||||
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
|
||||
static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
|
||||
|
@ -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))
|
||||
|
||||
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) {
|
||||
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)))
|
||||
|
||||
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.
|
||||
|
||||
#define align_object_size_(size) align_size_up_(size, MinObjAlignment)
|
||||
|
@ -25,7 +25,8 @@
|
||||
|
||||
# This file identifies the root of the test-suite hierarchy.
|
||||
# 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
|
||||
keys=cte_test jcmd nmt regression gc
|
||||
|
||||
groups=TEST.groups [closed/TEST.groups]
|
||||
|
192
hotspot/test/TEST.groups
Normal file
192
hotspot/test/TEST.groups
Normal 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
|
56
hotspot/test/compiler/8004051/Test8004051.java
Normal file
56
hotspot/test/compiler/8004051/Test8004051.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -45,6 +45,13 @@ public class ThreadedVirtualAllocTestType {
|
||||
String pid = Integer.toString(ProcessTools.getProcessId());
|
||||
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() {
|
||||
public void run() {
|
||||
addr = wb.NMTReserveMemory(reserveSize);
|
||||
@ -58,7 +65,9 @@ public class ThreadedVirtualAllocTestType {
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
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() {
|
||||
public void run() {
|
||||
@ -72,7 +81,9 @@ public class ThreadedVirtualAllocTestType {
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
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() {
|
||||
public void run() {
|
||||
|
@ -46,13 +46,22 @@ public class VirtualAllocTestType {
|
||||
String pid = Integer.toString(ProcessTools.getProcessId());
|
||||
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);
|
||||
mergeData();
|
||||
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
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);
|
||||
|
||||
@ -60,7 +69,9 @@ public class VirtualAllocTestType {
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
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);
|
||||
|
||||
@ -71,7 +82,6 @@ public class VirtualAllocTestType {
|
||||
output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed");
|
||||
|
||||
wb.NMTReleaseMemory(addr, reserveSize);
|
||||
|
||||
mergeData();
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
|
82
hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java
Normal file
82
hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java
Normal 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);
|
||||
}
|
||||
}
|
@ -90,6 +90,7 @@ public class WhiteBox {
|
||||
public native void NMTUncommitMemory(long addr, long size);
|
||||
public native void NMTReleaseMemory(long addr, long size);
|
||||
public native boolean NMTWaitForDataMerge();
|
||||
public native boolean NMTIsDetailSupported();
|
||||
|
||||
// Compiler
|
||||
public native void deoptimizeAll();
|
||||
|
@ -226,3 +226,4 @@ c4908732fef5235f1b98cafe0ce507771ef7892c jdk8-b98
|
||||
8ed8e2b4b90e0ac9aa5b3efef51cd576a9db96a9 jdk8-b102
|
||||
e0f6039c0290b7381042a6fec3100a69a5a67e37 jdk8-b103
|
||||
f1d8d15bfcb5ada858a942f8a31f6598f23214d1 jdk8-b104
|
||||
1fe211ae3d2b8cc2dfc4f58d9a6eb96418679672 jdk8-b105
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,8 +43,6 @@ FILES_java = \
|
||||
com/sun/security/auth/UserPrincipal.java \
|
||||
com/sun/security/auth/LdapPrincipal.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/callback/TextCallbackHandler.java \
|
||||
com/sun/security/auth/callback/DialogCallbackHandler.java
|
||||
|
@ -65,10 +65,6 @@ PROFILE_2_JARS := \
|
||||
$(if $(PROFILE_2_JRE_JAR_FILES), $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_2_JRE_JAR_FILES))) \
|
||||
$(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 := \
|
||||
$(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_3_JRE_JAR_FILES)) \
|
||||
$(PROFILE_2_JARS)
|
||||
@ -77,6 +73,10 @@ ifdef OPENJDK
|
||||
FULL_JRE_JAR_FILES := $(filter-out alt-rt.jar, $(FULL_JRE_JAR_FILES))
|
||||
endif
|
||||
|
||||
ifneq ($(ENABLE_JFR), true)
|
||||
FULL_JRE_JAR_FILES := $(filter-out jfr.jar, $(FULL_JRE_JAR_FILES))
|
||||
endif
|
||||
|
||||
FULL_JRE_JARS := \
|
||||
$(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(FULL_JRE_JAR_FILES)) \
|
||||
$(PROFILE_3_JARS)
|
||||
|
@ -87,6 +87,7 @@ class KQueueArrayWrapper {
|
||||
private int incomingInterruptFD;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initStructSizes();
|
||||
String datamodel = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("sun.arch.data.model")
|
||||
|
@ -246,9 +246,4 @@ class KQueueSelectorImpl
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
Util.load();
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,12 @@
|
||||
#include "util.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
|
||||
* allow concurrent translation - due to caching method.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -59,7 +59,7 @@ import java.io.IOException;
|
||||
* {@link java.lang.instrument} for a detailed description on how these agents
|
||||
* are loaded and started). The {@link #loadAgentLibrary loadAgentLibrary} and
|
||||
* {@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
|
||||
* Interface</a>. </p>
|
||||
*
|
||||
@ -298,25 +298,29 @@ public abstract class VirtualMachine {
|
||||
* <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.
|
||||
* 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
|
||||
* library to be loaded into the target VM (if not already loaded).
|
||||
* platform equivalent of a dynamic library. Alternatively, it may be statically linked into the VM.
|
||||
* 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
|
||||
* 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
|
||||
* this method.
|
||||
*
|
||||
* <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
|
||||
* 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
|
||||
* <tt>libfoo.so</tt>, and located using the search path specified by the
|
||||
* <tt>LD_LIBRARY_PATH</tt> environment variable.</p>
|
||||
* name. For example, on UNIX systems, the name <tt>L</tt> might be expanded to
|
||||
* <tt>libL.so</tt>, and located using the search path specified by the
|
||||
* <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
|
||||
* 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
|
||||
* com.sun.tools.attach.AgentInitializationException#returnValue() returnValue}
|
||||
* method on the exception. </p>
|
||||
@ -325,15 +329,16 @@ public abstract class VirtualMachine {
|
||||
* The name of the agent library.
|
||||
*
|
||||
* @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>).
|
||||
*
|
||||
* @throws AgentLoadException
|
||||
* If the agent library does not exist, or cannot be loaded for
|
||||
* another reason.
|
||||
* If the agent library does not exist, the agent library is not
|
||||
* statically linked with the VM, or the agent library cannot be
|
||||
* loaded for another reason.
|
||||
*
|
||||
* @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
|
||||
* If an I/O error occurs
|
||||
@ -359,11 +364,12 @@ public abstract class VirtualMachine {
|
||||
* The name of the agent library.
|
||||
*
|
||||
* @throws AgentLoadException
|
||||
* If the agent library does not exist, or cannot be loaded for
|
||||
* another reason.
|
||||
* If the agent library does not exist, the agent library is not
|
||||
* statically linked with the VM, or the agent library cannot be
|
||||
* loaded for another reason.
|
||||
*
|
||||
* @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
|
||||
* If an I/O error occurs
|
||||
@ -383,12 +389,23 @@ public abstract class VirtualMachine {
|
||||
* <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.
|
||||
* 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
|
||||
* library to be loaded into the target VM (if not already loaded).
|
||||
* It then causes the target VM to invoke the <code>Agent_OnAttach</code> function
|
||||
* as specified in the
|
||||
* platform equivalent of a dynamic library. Alternatively, the native
|
||||
* library specified by the agentPath parameter may be statically
|
||||
* linked with the VM. The parsing of the agentPath parameter into
|
||||
* 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
|
||||
* 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
|
||||
* this method.
|
||||
*
|
||||
@ -396,9 +413,9 @@ public abstract class VirtualMachine {
|
||||
* agent library. Unlike {@link #loadAgentLibrary loadAgentLibrary}, the library name
|
||||
* 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
|
||||
* 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
|
||||
* com.sun.tools.attach.AgentInitializationException#returnValue() returnValue}
|
||||
* method on the exception. </p>
|
||||
@ -407,15 +424,16 @@ public abstract class VirtualMachine {
|
||||
* The full path of the agent library.
|
||||
*
|
||||
* @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>).
|
||||
*
|
||||
* @throws AgentLoadException
|
||||
* If the agent library does not exist, or cannot be loaded for
|
||||
* another reason.
|
||||
* If the agent library does not exist, the agent library is not
|
||||
* statically linked with the VM, or the agent library cannot be
|
||||
* loaded for another reason.
|
||||
*
|
||||
* @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
|
||||
* If an I/O error occurs
|
||||
@ -441,11 +459,12 @@ public abstract class VirtualMachine {
|
||||
* The full path to the agent library.
|
||||
*
|
||||
* @throws AgentLoadException
|
||||
* If the agent library does not exist, or cannot be loaded for
|
||||
* another reason.
|
||||
* If the agent library does not exist, the agent library is not
|
||||
* statically linked with the VM, or the agent library cannot be
|
||||
* loaded for another reason.
|
||||
*
|
||||
* @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
|
||||
* If an I/O error occurs
|
||||
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -50,7 +50,15 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||
public
|
||||
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,
|
||||
@ -172,7 +180,7 @@ class BufferedInputStream extends FilterInputStream {
|
||||
* @param in the underlying input stream.
|
||||
*/
|
||||
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) {
|
||||
markpos = -1; /* buffer got too big, invalidate mark */
|
||||
pos = 0; /* drop buffer contents */
|
||||
} else if (buffer.length >= MAX_BUFFER_SIZE) {
|
||||
throw new OutOfMemoryError("Required array size too large");
|
||||
} else { /* grow buffer */
|
||||
int nsz = pos * 2;
|
||||
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
|
||||
pos * 2 : MAX_BUFFER_SIZE;
|
||||
if (nsz > marklimit)
|
||||
nsz = marklimit;
|
||||
byte nbuf[] = new byte[nsz];
|
||||
|
@ -1307,7 +1307,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* specified substring, starting at the specified index. The integer
|
||||
* returned is the smallest value {@code k} for which:
|
||||
* <blockquote><pre>
|
||||
* k >= Math.min(fromIndex, str.length()) &&
|
||||
* k >= Math.min(fromIndex, this.length()) &&
|
||||
* this.toString().startsWith(str, k)
|
||||
* </pre></blockquote>
|
||||
* 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>
|
||||
* such that:
|
||||
* <blockquote><pre>
|
||||
* k <= Math.min(fromIndex, str.length()) &&
|
||||
* k <= Math.min(fromIndex, this.length()) &&
|
||||
* this.toString().startsWith(str, k)
|
||||
* </pre></blockquote>
|
||||
* If no such value of <i>k</i> exists, then -1 is returned.
|
||||
|
@ -3338,8 +3338,16 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @since 1.8
|
||||
*/
|
||||
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
|
||||
|
@ -698,11 +698,8 @@ public final class Math {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static Random randomNumberGenerator;
|
||||
|
||||
private static synchronized Random initRNG() {
|
||||
Random rnd = randomNumberGenerator;
|
||||
return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
|
||||
private static final class RandomNumberGeneratorHolder {
|
||||
static final Random randomNumberGenerator = new Random();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -729,9 +726,7 @@ public final class Math {
|
||||
* @see Random#nextDouble()
|
||||
*/
|
||||
public static double random() {
|
||||
Random rnd = randomNumberGenerator;
|
||||
if (rnd == null) rnd = initRNG();
|
||||
return rnd.nextDouble();
|
||||
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -1033,9 +1032,9 @@ public final class ProcessBuilder
|
||||
// Can not disclose the fail reason for read-protected files.
|
||||
try {
|
||||
security.checkRead(prog);
|
||||
} catch (AccessControlException ace) {
|
||||
} catch (SecurityException se) {
|
||||
exceptionInfo = "";
|
||||
cause = ace;
|
||||
cause = se;
|
||||
}
|
||||
}
|
||||
// It's much easier for us to create a high-quality error
|
||||
|
@ -678,11 +678,8 @@ public final class StrictMath {
|
||||
return Math.round(a);
|
||||
}
|
||||
|
||||
private static Random randomNumberGenerator;
|
||||
|
||||
private static synchronized Random initRNG() {
|
||||
Random rnd = randomNumberGenerator;
|
||||
return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
|
||||
private static final class RandomNumberGeneratorHolder {
|
||||
static final Random randomNumberGenerator = new Random();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -709,9 +706,7 @@ public final class StrictMath {
|
||||
* @see Random#nextDouble()
|
||||
*/
|
||||
public static double random() {
|
||||
Random rnd = randomNumberGenerator;
|
||||
if (rnd == null) rnd = initRNG();
|
||||
return rnd.nextDouble();
|
||||
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2659,28 +2659,32 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
if (ys == 0)
|
||||
return 1;
|
||||
|
||||
int sdiff = this.scale - val.scale;
|
||||
long sdiff = (long)this.scale - val.scale;
|
||||
if (sdiff != 0) {
|
||||
// Avoid matching scales if the (adjusted) exponents differ
|
||||
int xae = this.precision() - this.scale; // [-1]
|
||||
int yae = val.precision() - val.scale; // [-1]
|
||||
long xae = (long)this.precision() - this.scale; // [-1]
|
||||
long yae = (long)val.precision() - val.scale; // [-1]
|
||||
if (xae < yae)
|
||||
return -1;
|
||||
if (xae > yae)
|
||||
return 1;
|
||||
BigInteger rb = null;
|
||||
if (sdiff < 0) {
|
||||
if ( (xs == INFLATED ||
|
||||
(xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
|
||||
// The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
|
||||
if ( sdiff > Integer.MIN_VALUE &&
|
||||
(xs == INFLATED ||
|
||||
(xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
|
||||
ys == INFLATED) {
|
||||
rb = bigMultiplyPowerTen(-sdiff);
|
||||
rb = bigMultiplyPowerTen((int)-sdiff);
|
||||
return rb.compareMagnitude(val.intVal);
|
||||
}
|
||||
} else { // sdiff > 0
|
||||
if ( (ys == INFLATED ||
|
||||
(ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
|
||||
// The cases sdiff > Integer.MAX_VALUE intentionally fall through.
|
||||
if ( sdiff <= Integer.MAX_VALUE &&
|
||||
(ys == INFLATED ||
|
||||
(ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
|
||||
xs == INFLATED) {
|
||||
rb = val.bigMultiplyPowerTen(sdiff);
|
||||
rb = val.bigMultiplyPowerTen((int)sdiff);
|
||||
return this.intVal.compareMagnitude(rb);
|
||||
}
|
||||
}
|
||||
@ -4545,7 +4549,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
if(cmp > 0) { // satisfy constraint (b)
|
||||
yscale -= 1; // [that is, divisor *= 10]
|
||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
||||
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||
// assert newScale >= xscale
|
||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||
long scaledXs;
|
||||
@ -4626,7 +4630,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
// return BigDecimal object whose scale will be set to 'scl'.
|
||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||
BigDecimal quotient;
|
||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
||||
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||
long scaledXs;
|
||||
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'.
|
||||
BigDecimal quotient;
|
||||
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);
|
||||
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
||||
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'.
|
||||
BigDecimal quotient;
|
||||
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);
|
||||
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
||||
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'.
|
||||
BigDecimal quotient;
|
||||
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);
|
||||
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
||||
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
||||
|
@ -2109,7 +2109,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
// This is a quick way to approximate the size of the result,
|
||||
// similar to doing log2[n] * exponent. This will give an upper bound
|
||||
// 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.
|
||||
// See if the result will safely fit into a long. (Largest 2^63-1)
|
||||
|
@ -50,13 +50,13 @@ import java.net.*;
|
||||
* @implNote
|
||||
* <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,
|
||||
* 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.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class LoopbackSocketFactory extends RMISocketFactory {
|
||||
* 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 {
|
||||
@ -72,8 +72,8 @@ import java.net.*;
|
||||
* }</pre>
|
||||
*
|
||||
* Set the {@code java.rmi.server.hostname} system property
|
||||
* to a host name (typically {@code localhost}) that resolves to the loopback
|
||||
* interface to ensure that the generated stubs use the right network interface.
|
||||
* to {@code 127.0.0.1} to ensure that the generated stubs connect to the right
|
||||
* network interface.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @author Peter Jones
|
||||
|
@ -27,7 +27,6 @@ package java.util;
|
||||
import java.io.Serializable;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
@ -35,6 +34,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@ -1148,7 +1148,16 @@ public class Collections {
|
||||
public Spliterator<E> 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>
|
||||
*
|
||||
* It is imperative that the user manually synchronize on the returned
|
||||
* collection when traversing it via {@link Iterator} or
|
||||
* {@link Spliterator}:
|
||||
* collection when traversing it via {@link Iterator}, {@link Spliterator}
|
||||
* or {@link Stream}:
|
||||
* <pre>
|
||||
* Collection c = Collections.synchronizedCollection(myCollection);
|
||||
* ...
|
||||
@ -2120,6 +2129,14 @@ public class Collections {
|
||||
public Spliterator<E> spliterator() {
|
||||
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 {
|
||||
synchronized (mutex) {s.defaultWriteObject();}
|
||||
}
|
||||
@ -3172,6 +3189,10 @@ public class Collections {
|
||||
}
|
||||
@Override
|
||||
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 + ")");
|
||||
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
|
||||
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;
|
||||
|
||||
@ -5568,10 +5609,14 @@ public class Collections {
|
||||
@Override
|
||||
public void forEach(Consumer<? super E> action) {q.forEach(action);}
|
||||
@Override
|
||||
public Spliterator<E> spliterator() {return q.spliterator();}
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super E> 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();}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2009 Google Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -146,7 +147,7 @@ class ComparableTimSort {
|
||||
*/
|
||||
int stackLen = (len < 120 ? 5 :
|
||||
len < 1542 ? 10 :
|
||||
len < 119151 ? 19 : 40);
|
||||
len < 119151 ? 24 : 40);
|
||||
runBase = new int[stackLen];
|
||||
runLen = new int[stackLen];
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ public interface Comparator<T> {
|
||||
* composed using following code,
|
||||
*
|
||||
* <pre>{@code
|
||||
* Comparator<String> cmp = Comparator.comparing(String::length)
|
||||
* Comparator<String> cmp = Comparator.comparingInt(String::length)
|
||||
* .thenComparing(String.CASE_INSENSITIVE_ORDER);
|
||||
* }</pre>
|
||||
*
|
||||
@ -270,18 +270,18 @@ public interface Comparator<T> {
|
||||
* extracts a {@code int} sort key.
|
||||
*
|
||||
* @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
|
||||
* @return a lexicographic-order comparator composed of this and then the
|
||||
* {@code int} sort key
|
||||
* @throws NullPointerException if the argument is null.
|
||||
* @see #comparing(ToIntFunction)
|
||||
* @see #comparingInt(ToIntFunction)
|
||||
* @see #thenComparing(Comparator)
|
||||
* @since 1.8
|
||||
*/
|
||||
default Comparator<T> thenComparing(ToIntFunction<? super T> keyExtractor) {
|
||||
return thenComparing(comparing(keyExtractor));
|
||||
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
|
||||
return thenComparing(comparingInt(keyExtractor));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -289,18 +289,18 @@ public interface Comparator<T> {
|
||||
* extracts a {@code long} sort key.
|
||||
*
|
||||
* @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
|
||||
* @return a lexicographic-order comparator composed of this and then the
|
||||
* {@code long} sort key
|
||||
* @throws NullPointerException if the argument is null.
|
||||
* @see #comparing(ToLongFunction)
|
||||
* @see #comparingLong(ToLongFunction)
|
||||
* @see #thenComparing(Comparator)
|
||||
* @since 1.8
|
||||
*/
|
||||
default Comparator<T> thenComparing(ToLongFunction<? super T> keyExtractor) {
|
||||
return thenComparing(comparing(keyExtractor));
|
||||
default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
|
||||
return thenComparing(comparingLong(keyExtractor));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,18 +308,18 @@ public interface Comparator<T> {
|
||||
* extracts a {@code double} sort key.
|
||||
*
|
||||
* @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
|
||||
* @return a lexicographic-order comparator composed of this and then the
|
||||
* {@code double} sort key
|
||||
* @throws NullPointerException if the argument is null.
|
||||
* @see #comparing(ToDoubleFunction)
|
||||
* @see #comparingDouble(ToDoubleFunction)
|
||||
* @see #thenComparing(Comparator)
|
||||
* @since 1.8
|
||||
*/
|
||||
default Comparator<T> thenComparing(ToDoubleFunction<? super T> keyExtractor) {
|
||||
return thenComparing(comparing(keyExtractor));
|
||||
default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
|
||||
return thenComparing(comparingDouble(keyExtractor));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -484,7 +484,7 @@ public interface Comparator<T> {
|
||||
* @throws NullPointerException if the argument is null
|
||||
* @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);
|
||||
return (Comparator<T> & Serializable)
|
||||
(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
|
||||
* @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);
|
||||
return (Comparator<T> & Serializable)
|
||||
(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
|
||||
* @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);
|
||||
return (Comparator<T> & Serializable)
|
||||
(c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
|
||||
|
@ -26,9 +26,13 @@
|
||||
package java.util;
|
||||
import java.io.*;
|
||||
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.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
@ -85,6 +89,13 @@ class Random implements java.io.Serializable {
|
||||
private static final long addend = 0xBL;
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* 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
|
||||
* this random number generator's sequence. The general contract of
|
||||
* {@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
|
||||
* 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:
|
||||
* <pre> {@code
|
||||
* public int nextInt(int n) {
|
||||
* if (n <= 0)
|
||||
* throw new IllegalArgumentException("n must be positive");
|
||||
* public int nextInt(int bound) {
|
||||
* if (bound <= 0)
|
||||
* throw new IllegalArgumentException("bound must be positive");
|
||||
*
|
||||
* if ((n & -n) == n) // i.e., n is a power of 2
|
||||
* return (int)((n * (long)next(31)) >> 31);
|
||||
* if ((bound & -bound) == bound) // i.e., bound is a power of 2
|
||||
* return (int)((bound * (long)next(31)) >> 31);
|
||||
*
|
||||
* int bits, val;
|
||||
* do {
|
||||
* bits = next(31);
|
||||
* val = bits % n;
|
||||
* } while (bits - val + (n-1) < 0);
|
||||
* val = bits % bound;
|
||||
* } while (bits - val + (bound-1) < 0);
|
||||
* return val;
|
||||
* }}</pre>
|
||||
*
|
||||
@ -289,28 +376,28 @@ class Random implements java.io.Serializable {
|
||||
* greatly increases the length of the sequence of values returned by
|
||||
* 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
|
||||
* positive.
|
||||
* @param bound the upper bound (exclusive). Must be positive.
|
||||
* @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
|
||||
* @throws IllegalArgumentException if n is not positive
|
||||
* @throws IllegalArgumentException if bound is not positive
|
||||
* @since 1.2
|
||||
*/
|
||||
public int nextInt(int bound) {
|
||||
if (bound <= 0)
|
||||
throw new IllegalArgumentException(BadBound);
|
||||
|
||||
public int nextInt(int n) {
|
||||
if (n <= 0)
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
|
||||
if ((n & -n) == n) // i.e., n is a power of 2
|
||||
return (int)((n * (long)next(31)) >> 31);
|
||||
|
||||
int bits, val;
|
||||
do {
|
||||
bits = next(31);
|
||||
val = bits % n;
|
||||
} while (bits - val + (n-1) < 0);
|
||||
return val;
|
||||
int r = next(31);
|
||||
int m = bound - 1;
|
||||
if ((bound & m) == 0) // i.e., bound is a power of 2
|
||||
r = (int)((bound * (long)r) >> 31);
|
||||
else {
|
||||
for (int u = r;
|
||||
u - (r = u % bound) + m < 0;
|
||||
u = next(31))
|
||||
;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -442,8 +529,7 @@ class Random implements java.io.Serializable {
|
||||
* @see Math#random
|
||||
*/
|
||||
public double nextDouble() {
|
||||
return (((long)(next(26)) << 27) + next(27))
|
||||
/ (double)(1L << 53);
|
||||
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
|
||||
}
|
||||
|
||||
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
|
||||
* {@code integer} values from this random number generator's
|
||||
* sequence. Values are obtained as needed by calling
|
||||
* {@link #nextInt()}.
|
||||
* Returns a stream producing the given {@code streamSize} number of
|
||||
* pseudorandom {@code int} values.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* {@code long} values from this random number generator's
|
||||
* sequence. Values are obtained as needed by calling
|
||||
* {@link #nextLong()}.
|
||||
* Returns a stream producing the given {@code streamSize} number
|
||||
* of pseudorandom {@code int} values, each conforming to the given
|
||||
* origin (inclusive) and bound (exclusive).
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* {@code double} values between {@code 0.0} and {@code 1.0}
|
||||
* from this random number generator's sequence. Values are
|
||||
* obtained as needed by calling {@link #nextDouble()}.
|
||||
* Returns a stream producing the given {@code streamSize} number of
|
||||
* pseudorandom {@code long}, each conforming to the given origin
|
||||
* (inclusive) and bound (exclusive).
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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")
|
||||
* distributed {@code double} values with mean {@code 0.0}
|
||||
* and standard deviation {@code 1.0} from this random number
|
||||
* generator's sequence. Values are obtained as needed by
|
||||
* calling {@link #nextGaussian()}.
|
||||
* Returns a stream producing the given {@code streamSize} number of
|
||||
* pseudorandom {@code double} values, each conforming to the given origin
|
||||
* (inclusive) and bound (exclusive).
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public DoubleStream gaussians() {
|
||||
return DoubleStream.generate(this::nextGaussian);
|
||||
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
|
||||
(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
1002
jdk/src/share/classes/java/util/SplittableRandom.java
Normal file
1002
jdk/src/share/classes/java/util/SplittableRandom.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2009 Google Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -176,7 +177,7 @@ class TimSort<T> {
|
||||
*/
|
||||
int stackLen = (len < 120 ? 5 :
|
||||
len < 1542 ? 10 :
|
||||
len < 119151 ? 19 : 40);
|
||||
len < 119151 ? 24 : 40);
|
||||
runBase = new int[stackLen];
|
||||
runLen = new int[stackLen];
|
||||
}
|
||||
|
@ -972,6 +972,27 @@ public class TreeMap<K,V>
|
||||
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
|
||||
public void forEach(BiConsumer<? super K, ? super V> action) {
|
||||
Objects.requireNonNull(action);
|
||||
|
@ -37,11 +37,16 @@ package java.util.concurrent;
|
||||
|
||||
import java.io.ObjectStreamField;
|
||||
import java.util.Random;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
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.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* @author Doug Lea
|
||||
*/
|
||||
@ -85,28 +94,26 @@ public class ThreadLocalRandom extends Random {
|
||||
* application-level overhead and footprint of most concurrent
|
||||
* 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,
|
||||
* field access methods use Unsafe to bypass access control rules.
|
||||
* The base functionality of Random methods is conveniently
|
||||
* isolated in method next(bits), that just reads and writes the
|
||||
* Thread field rather than its own field. However, to conform to
|
||||
* the requirements of the Random superclass constructor, the
|
||||
* common static ThreadLocalRandom maintains an "initialized"
|
||||
* field for the sake of rejecting user calls to setSeed while
|
||||
* still allowing a call from constructor. Note that
|
||||
* serialization is completely unnecessary because there is only a
|
||||
* static singleton. But we generate a serial form containing
|
||||
* "rnd" and "initialized" fields to ensure compatibility across
|
||||
* versions.
|
||||
* To conform to the requirements of the Random superclass
|
||||
* constructor, the common static ThreadLocalRandom maintains an
|
||||
* "initialized" field for the sake of rejecting user calls to
|
||||
* setSeed while still allowing a call from constructor. Note
|
||||
* that serialization is completely unnecessary because there is
|
||||
* only a 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
|
||||
* Random constructor, but we avoid correlation among not only
|
||||
* initial seeds of those created in different threads, but also
|
||||
* 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.
|
||||
* Implementations of non-core methods are mostly the same as in
|
||||
* SplittableRandom, that were in part derived from a previous
|
||||
* version of this class.
|
||||
*
|
||||
* The nextLocalGaussian ThreadLocal supports the very rarely used
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// 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 */
|
||||
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 */
|
||||
private static final ThreadLocal<Double> nextLocalGaussian =
|
||||
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.
|
||||
* True when constructor completes.
|
||||
@ -155,16 +189,11 @@ public class ThreadLocalRandom extends Random {
|
||||
* rely on (static) atomic generators to initialize the values.
|
||||
*/
|
||||
static final void localInit() {
|
||||
int p = probeGenerator.getAndAdd(PROBE_INCREMENT);
|
||||
int p = probeGenerator.addAndGet(PROBE_INCREMENT);
|
||||
int probe = (p == 0) ? 1 : p; // skip 0
|
||||
long current, next;
|
||||
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();
|
||||
long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
|
||||
Thread t = Thread.currentThread();
|
||||
UNSAFE.putLong(t, SEED, r);
|
||||
UNSAFE.putLong(t, SEED, seed);
|
||||
UNSAFE.putInt(t, PROBE, probe);
|
||||
}
|
||||
|
||||
@ -191,124 +220,264 @@ public class ThreadLocalRandom extends Random {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected int next(int bits) {
|
||||
final long nextSeed() {
|
||||
Thread t; long r; // read and update per-thread seed
|
||||
UNSAFE.putLong
|
||||
(t = Thread.currentThread(), SEED,
|
||||
r = (UNSAFE.getLong(t, SEED) * multiplier + addend) & mask);
|
||||
return (int) (r >>> (48-bits));
|
||||
UNSAFE.putLong(t = Thread.currentThread(), SEED,
|
||||
r = UNSAFE.getLong(t, SEED) + GAMMA);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudorandom, uniformly distributed value between the
|
||||
* given least value (inclusive) and bound (exclusive).
|
||||
*
|
||||
* @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;
|
||||
// We must define this, but never use it.
|
||||
protected int next(int bits) {
|
||||
return (int)(mix64(nextSeed()) >>> (64 - bits));
|
||||
}
|
||||
|
||||
// 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
|
||||
* between 0 (inclusive) and the specified value (exclusive).
|
||||
* 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 n the bound on the random number to be returned. Must be
|
||||
* positive.
|
||||
* @return the next value
|
||||
* @throws IllegalArgumentException if n is not positive
|
||||
* @param origin the least value, unless greater than bound
|
||||
* @param bound the upper bound (exclusive), must not equal origin
|
||||
* @return a pseudorandom value
|
||||
*/
|
||||
public long nextLong(long n) {
|
||||
if (n <= 0)
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
// Divide n by two until small enough for nextInt. On each
|
||||
// iteration (at most 31 of them but usually much less),
|
||||
// randomly choose both whether to include high bit in result
|
||||
// (offset) and whether to continue with the lower vs upper
|
||||
// half (which makes a difference only if odd).
|
||||
long offset = 0;
|
||||
while (n >= Integer.MAX_VALUE) {
|
||||
int bits = next(2);
|
||||
long half = n >>> 1;
|
||||
long nextn = ((bits & 2) == 0) ? half : n - half;
|
||||
if ((bits & 1) == 0)
|
||||
offset += n - nextn;
|
||||
n = nextn;
|
||||
final long internalNextLong(long origin, long bound) {
|
||||
long r = mix64(nextSeed());
|
||||
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 = mix64(nextSeed()) >>> 1) // retry
|
||||
;
|
||||
r += origin;
|
||||
}
|
||||
else { // range not representable as long
|
||||
while (r < origin || r >= bound)
|
||||
r = mix64(nextSeed());
|
||||
}
|
||||
}
|
||||
return offset + nextInt((int) n);
|
||||
}
|
||||
|
||||
@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());
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudorandom, uniformly distributed value between the
|
||||
* given least value (inclusive) and bound (exclusive).
|
||||
* The form of nextInt used by IntStream Spliterators.
|
||||
* 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)
|
||||
* @return the next value
|
||||
* @throws IllegalArgumentException if least greater than or equal
|
||||
* to bound
|
||||
* @return a pseudorandom {@code int} value between the origin
|
||||
* (inclusive) and the bound (exclusive)
|
||||
* @throws IllegalArgumentException if {@code origin} is greater than
|
||||
* or equal to {@code bound}
|
||||
*/
|
||||
public long nextLong(long least, long bound) {
|
||||
if (least >= bound)
|
||||
throw new IllegalArgumentException();
|
||||
return nextLong(bound - least) + least;
|
||||
public int nextInt(int origin, int bound) {
|
||||
if (origin >= bound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
return internalNextInt(origin, bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudorandom, uniformly distributed {@code double} value
|
||||
* between 0 (inclusive) and the specified value (exclusive).
|
||||
* Returns a pseudorandom {@code long} value.
|
||||
*
|
||||
* @param n the bound on the random number to be returned. Must be
|
||||
* positive.
|
||||
* @return the next value
|
||||
* @throws IllegalArgumentException if n is not positive
|
||||
* @return a pseudorandom {@code long} value
|
||||
*/
|
||||
public double nextDouble(double n) {
|
||||
if (n <= 0)
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
return nextDouble() * n;
|
||||
public long nextLong() {
|
||||
return mix64(nextSeed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudorandom, uniformly distributed value between the
|
||||
* given least value (inclusive) and bound (exclusive).
|
||||
* Returns a pseudorandom {@code long} value between zero (inclusive)
|
||||
* 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)
|
||||
* @return the next value
|
||||
* @throws IllegalArgumentException if least greater than or equal
|
||||
* to bound
|
||||
* @return a pseudorandom {@code long} 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 least, double bound) {
|
||||
if (least >= bound)
|
||||
throw new IllegalArgumentException();
|
||||
return nextDouble() * (bound - least) + least;
|
||||
public long nextLong(long origin, long bound) {
|
||||
if (origin >= bound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
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() {
|
||||
@ -329,6 +498,445 @@ public class ThreadLocalRandom extends Random {
|
||||
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
|
||||
|
||||
/*
|
||||
@ -401,23 +1009,26 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
private static final ObjectStreamField[] serialPersistentFields = {
|
||||
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).
|
||||
* @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 {
|
||||
|
||||
java.io.ObjectOutputStream.PutField fields = out.putFields();
|
||||
java.io.ObjectOutputStream.PutField fields = s.putFields();
|
||||
fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED));
|
||||
fields.put("initialized", true);
|
||||
out.writeFields();
|
||||
s.writeFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
|
||||
* @return the {@link #current() current} thread's {@code ThreadLocalRandom}
|
||||
*/
|
||||
private Object readResolve() {
|
||||
return current();
|
||||
|
@ -226,7 +226,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
* incoming reader arrives while read lock is held but there is a
|
||||
* queued writer, this incoming reader is queued. (This rule is
|
||||
* 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
|
||||
* 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 */
|
||||
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;
|
||||
|
||||
/** 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 */
|
||||
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 */
|
||||
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
|
||||
*/
|
||||
public long readLock() {
|
||||
long s, next; // bypass acquireRead on fully unlocked case only
|
||||
return ((((s = state) & ABITS) == 0L &&
|
||||
long s = state, next; // bypass acquireRead on common uncontended case
|
||||
return ((whead == wtail && (s & ABITS) < RFULL &&
|
||||
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
|
||||
next : acquireRead(false, 0L));
|
||||
}
|
||||
@ -1012,17 +1019,8 @@ public class StampedLock implements java.io.Serializable {
|
||||
if (t.status <= 0)
|
||||
q = t;
|
||||
}
|
||||
if (q != null) {
|
||||
for (WNode r = q;;) { // release co-waiters too
|
||||
if ((w = r.thread) != null) {
|
||||
r.thread = null;
|
||||
U.unpark(w);
|
||||
}
|
||||
if ((r = q.cowait) == null)
|
||||
break;
|
||||
U.compareAndSwapObject(q, WCOWAIT, r, r.cowait);
|
||||
}
|
||||
}
|
||||
if (q != null && (w = q.thread) != null)
|
||||
U.unpark(w);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1038,22 +1036,22 @@ public class StampedLock implements java.io.Serializable {
|
||||
private long acquireWrite(boolean interruptible, long deadline) {
|
||||
WNode node = null, p;
|
||||
for (int spins = -1;;) { // spin while enqueuing
|
||||
long s, ns;
|
||||
if (((s = state) & ABITS) == 0L) {
|
||||
long m, s, ns;
|
||||
if ((m = (s = state) & ABITS) == 0L) {
|
||||
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
|
||||
return ns;
|
||||
}
|
||||
else if (spins < 0)
|
||||
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
|
||||
else if (spins > 0) {
|
||||
if (LockSupport.nextSecondarySeed() >= 0)
|
||||
--spins;
|
||||
}
|
||||
else if ((p = wtail) == null) { // initialize queue
|
||||
WNode h = new WNode(WMODE, null);
|
||||
if (U.compareAndSwapObject(this, WHEAD, null, h))
|
||||
wtail = h;
|
||||
WNode hd = new WNode(WMODE, null);
|
||||
if (U.compareAndSwapObject(this, WHEAD, null, hd))
|
||||
wtail = hd;
|
||||
}
|
||||
else if (spins < 0)
|
||||
spins = (p == whead) ? SPINS : 0;
|
||||
else if (node == null)
|
||||
node = new WNode(WMODE, p);
|
||||
else if (node.prev != p)
|
||||
@ -1064,14 +1062,18 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
for (int spins = SPINS;;) {
|
||||
WNode np, pp; int ps; long s, ns; Thread w;
|
||||
while ((np = node.prev) != p && np != null)
|
||||
(p = np).next = node; // stale
|
||||
if (whead == p) {
|
||||
for (int spins = -1;;) {
|
||||
WNode h, np, pp; int ps;
|
||||
if ((h = whead) == p) {
|
||||
if (spins < 0)
|
||||
spins = HEAD_SPINS;
|
||||
else if (spins < MAX_HEAD_SPINS)
|
||||
spins <<= 1;
|
||||
for (int k = spins;;) { // spin at head
|
||||
long s, ns;
|
||||
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;
|
||||
node.prev = null;
|
||||
return ns;
|
||||
@ -1081,33 +1083,45 @@ public class StampedLock implements java.io.Serializable {
|
||||
--k <= 0)
|
||||
break;
|
||||
}
|
||||
if (spins < MAX_HEAD_SPINS)
|
||||
spins <<= 1;
|
||||
}
|
||||
if ((ps = p.status) == 0)
|
||||
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
|
||||
else if (ps == CANCELLED) {
|
||||
if ((pp = p.prev) != null) {
|
||||
node.prev = pp;
|
||||
pp.next = node;
|
||||
else if (h != null) { // help release stale waiters
|
||||
WNode c; Thread w;
|
||||
while ((c = h.cowait) != null) {
|
||||
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
|
||||
(w = c.thread) != null)
|
||||
U.unpark(w);
|
||||
}
|
||||
}
|
||||
else {
|
||||
long time; // 0 argument to park means no timeout
|
||||
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); // emulate LockSupport.park
|
||||
node.thread = wt;
|
||||
if (node.prev == p && p.status == WAITING && // recheck
|
||||
(p != whead || (state & ABITS) != 0L))
|
||||
U.park(false, time);
|
||||
node.thread = null;
|
||||
U.putObject(wt, PARKBLOCKER, null);
|
||||
if (interruptible && Thread.interrupted())
|
||||
return cancelWaiter(node, node, true);
|
||||
if (whead == h) {
|
||||
if ((np = node.prev) != p) {
|
||||
if (np != null)
|
||||
(p = np).next = node; // stale
|
||||
}
|
||||
else if ((ps = p.status) == 0)
|
||||
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
|
||||
else if (ps == CANCELLED) {
|
||||
if ((pp = p.prev) != null) {
|
||||
node.prev = pp;
|
||||
pp.next = node;
|
||||
}
|
||||
}
|
||||
else {
|
||||
long time; // 0 argument to park means no timeout
|
||||
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
|
||||
*/
|
||||
private long acquireRead(boolean interruptible, long deadline) {
|
||||
WNode node = null, group = null, p;
|
||||
WNode node = null, p;
|
||||
for (int spins = -1;;) {
|
||||
for (;;) {
|
||||
long s, m, ns; WNode h, q; Thread w; // anti-barging guard
|
||||
if (group == null && (h = whead) != null &&
|
||||
(q = h.next) != null && q.mode != RMODE)
|
||||
break;
|
||||
if ((m = (s = state) & ABITS) < RFULL ?
|
||||
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
|
||||
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
|
||||
if (group != null) { // help release others
|
||||
for (WNode r = group;;) {
|
||||
if ((w = r.thread) != null) {
|
||||
r.thread = null;
|
||||
U.unpark(w);
|
||||
WNode h;
|
||||
if ((h = whead) == (p = wtail)) {
|
||||
for (long m, s, ns;;) {
|
||||
if ((m = (s = state) & ABITS) < RFULL ?
|
||||
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
|
||||
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
|
||||
return ns;
|
||||
else if (m >= WBIT) {
|
||||
if (spins > 0) {
|
||||
if (LockSupport.nextSecondarySeed() >= 0)
|
||||
--spins;
|
||||
}
|
||||
else {
|
||||
if (spins == 0) {
|
||||
WNode nh = whead, np = wtail;
|
||||
if ((nh == h && np == p) || (h = nh) != (p = np))
|
||||
break;
|
||||
}
|
||||
if ((r = group.cowait) == null)
|
||||
break;
|
||||
U.compareAndSwapObject(group, WCOWAIT, r, r.cowait);
|
||||
spins = SPINS;
|
||||
}
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
if (m >= WBIT)
|
||||
break;
|
||||
}
|
||||
if (spins > 0) {
|
||||
if (LockSupport.nextSecondarySeed() >= 0)
|
||||
--spins;
|
||||
if (p == null) { // initialize queue
|
||||
WNode hd = new WNode(WMODE, null);
|
||||
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)
|
||||
node = new WNode(WMODE, p);
|
||||
else if (node.prev != p)
|
||||
node.prev = p;
|
||||
else if (p.mode == RMODE && p != whead) {
|
||||
WNode pp = p.prev; // become co-waiter with group p
|
||||
if (pp != null && p == wtail &&
|
||||
U.compareAndSwapObject(p, WCOWAIT,
|
||||
node.cowait = p.cowait, node)) {
|
||||
node.thread = Thread.currentThread();
|
||||
for (long time;;) {
|
||||
node = new WNode(RMODE, p);
|
||||
else if (h == p || p.mode != RMODE) {
|
||||
if (node.prev != p)
|
||||
node.prev = p;
|
||||
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
|
||||
p.next = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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)
|
||||
time = 0L;
|
||||
else if ((time = deadline - System.nanoTime()) <= 0L)
|
||||
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();
|
||||
U.putObject(wt, PARKBLOCKER, this);
|
||||
if (node.thread == null) // must recheck
|
||||
break;
|
||||
U.park(false, time);
|
||||
node.thread = wt;
|
||||
if ((h != pp || (state & ABITS) == WBIT) &&
|
||||
whead == h && p.prev == pp)
|
||||
U.park(false, time);
|
||||
node.thread = null;
|
||||
U.putObject(wt, PARKBLOCKER, null);
|
||||
if (interruptible && Thread.interrupted())
|
||||
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;;) {
|
||||
WNode np, pp, r; int ps; long m, s, ns; Thread w;
|
||||
while ((np = node.prev) != p && np != null)
|
||||
(p = np).next = node;
|
||||
if (whead == p) {
|
||||
for (int k = spins;;) {
|
||||
if ((m = (s = state) & ABITS) != WBIT) {
|
||||
if (m < RFULL ?
|
||||
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT):
|
||||
(ns = tryIncReaderOverflow(s)) != 0L) {
|
||||
whead = node;
|
||||
node.prev = null;
|
||||
while ((r = node.cowait) != null) {
|
||||
if (U.compareAndSwapObject(node, WCOWAIT,
|
||||
r, r.cowait) &&
|
||||
(w = r.thread) != null) {
|
||||
r.thread = null;
|
||||
U.unpark(w); // release co-waiter
|
||||
}
|
||||
}
|
||||
return ns;
|
||||
for (int spins = -1;;) {
|
||||
WNode h, np, pp; int ps;
|
||||
if ((h = whead) == p) {
|
||||
if (spins < 0)
|
||||
spins = HEAD_SPINS;
|
||||
else if (spins < MAX_HEAD_SPINS)
|
||||
spins <<= 1;
|
||||
for (int k = spins;;) { // spin at head
|
||||
long m, s, ns;
|
||||
if ((m = (s = state) & ABITS) < RFULL ?
|
||||
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
|
||||
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
|
||||
WNode c; Thread w;
|
||||
whead = node;
|
||||
node.prev = null;
|
||||
while ((c = node.cowait) != null) {
|
||||
if (U.compareAndSwapObject(node, WCOWAIT,
|
||||
c, c.cowait) &&
|
||||
(w = c.thread) != null)
|
||||
U.unpark(w);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
else if (LockSupport.nextSecondarySeed() >= 0 &&
|
||||
--k <= 0)
|
||||
else if (m >= WBIT &&
|
||||
LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
|
||||
break;
|
||||
}
|
||||
if (spins < MAX_HEAD_SPINS)
|
||||
spins <<= 1;
|
||||
}
|
||||
if ((ps = p.status) == 0)
|
||||
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
|
||||
else if (ps == CANCELLED) {
|
||||
if ((pp = p.prev) != null) {
|
||||
node.prev = pp;
|
||||
pp.next = node;
|
||||
else if (h != null) {
|
||||
WNode c; Thread w;
|
||||
while ((c = h.cowait) != null) {
|
||||
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
|
||||
(w = c.thread) != null)
|
||||
U.unpark(w);
|
||||
}
|
||||
}
|
||||
else {
|
||||
long time;
|
||||
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 (node.prev == p && p.status == WAITING &&
|
||||
(p != whead || (state & ABITS) != WBIT))
|
||||
U.park(false, time);
|
||||
node.thread = null;
|
||||
U.putObject(wt, PARKBLOCKER, null);
|
||||
if (interruptible && Thread.interrupted())
|
||||
return cancelWaiter(node, node, true);
|
||||
if (whead == h) {
|
||||
if ((np = node.prev) != p) {
|
||||
if (np != null)
|
||||
(p = np).next = node; // stale
|
||||
}
|
||||
else if ((ps = p.status) == 0)
|
||||
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
|
||||
else if (ps == CANCELLED) {
|
||||
if ((pp = p.prev) != null) {
|
||||
node.prev = pp;
|
||||
pp.next = node;
|
||||
}
|
||||
}
|
||||
else {
|
||||
long time;
|
||||
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) {
|
||||
Thread w;
|
||||
node.status = CANCELLED;
|
||||
node.thread = null;
|
||||
// unsplice cancelled nodes from group
|
||||
for (WNode p = group, q; (q = p.cowait) != null;) {
|
||||
if (q.status == CANCELLED)
|
||||
U.compareAndSwapObject(p, WNEXT, q, q.next);
|
||||
if (q.status == CANCELLED) {
|
||||
U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
|
||||
p = group; // restart
|
||||
}
|
||||
else
|
||||
p = q;
|
||||
}
|
||||
if (group == node) {
|
||||
WNode r; // detach and wake up uncancelled co-waiters
|
||||
while ((r = node.cowait) != null) {
|
||||
if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) &&
|
||||
(w = r.thread) != null) {
|
||||
r.thread = null;
|
||||
U.unpark(w);
|
||||
}
|
||||
for (WNode r = group.cowait; r != null; r = r.cowait) {
|
||||
if ((w = r.thread) != null)
|
||||
U.unpark(w); // wake up uncancelled co-waiters
|
||||
}
|
||||
for (WNode pred = node.prev; pred != null; ) { // unsplice
|
||||
WNode succ, pp; // find valid successor
|
||||
|
@ -32,6 +32,7 @@ import java.security.*;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import sun.misc.JarIndex;
|
||||
import sun.security.util.ManifestDigester;
|
||||
import sun.security.util.ManifestEntryVerifier;
|
||||
import sun.security.util.SignatureFileVerifier;
|
||||
@ -139,7 +140,8 @@ class JarVerifier {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uname.equals(JarFile.MANIFEST_NAME)) {
|
||||
if (uname.equals(JarFile.MANIFEST_NAME) ||
|
||||
uname.equals(JarIndex.INDEX_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -457,13 +457,15 @@ public class Logger {
|
||||
* of the subsystem, such as java.net
|
||||
* or javax.swing
|
||||
* @param resourceBundleName name of ResourceBundle to be used for localizing
|
||||
* messages for this logger. May be <CODE>null</CODE> if none of
|
||||
* the messages require localization.
|
||||
* messages for this logger. May be {@code null}
|
||||
* if none of the messages require localization.
|
||||
* @return a suitable Logger
|
||||
* @throws MissingResourceException if the resourceBundleName is non-null and
|
||||
* no corresponding resource can be found.
|
||||
* @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.
|
||||
*/
|
||||
|
||||
@ -1731,10 +1733,6 @@ public class Logger {
|
||||
// Synchronized to prevent races in setting the fields.
|
||||
private synchronized void setupResourceInfo(String name,
|
||||
Class<?> callersClass) {
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (resourceBundleName != null) {
|
||||
// this Logger already has a ResourceBundle
|
||||
|
||||
@ -1748,6 +1746,10 @@ public class Logger {
|
||||
resourceBundleName + " != " + name);
|
||||
}
|
||||
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCallersClassLoaderRef(callersClass);
|
||||
if (findResourceBundle(name, true) == null) {
|
||||
// We've failed to find an expected ResourceBundle.
|
||||
|
@ -219,7 +219,7 @@ import java.util.stream.StreamSupport;
|
||||
*
|
||||
* <tr><th> </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 script character (<a href="#usc">script</a>)</td></tr>
|
||||
* <tr><td valign="top" headers="construct unicode">{@code \p{InGreek}}</td>
|
||||
* <td headers="matches">A character in the Greek 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] = i - k;
|
||||
}
|
||||
i = i - k;
|
||||
return true;
|
||||
}
|
||||
// backing off
|
||||
i = i - k;
|
||||
if (capture) {
|
||||
groups[groupIndex+1] = i;
|
||||
groups[groupIndex] = i - k;
|
||||
}
|
||||
i = i - k;
|
||||
j--;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -4883,7 +4883,6 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
||||
int k = matcher.groups[groupIndex+1];
|
||||
|
||||
int groupSize = k - j;
|
||||
|
||||
// If the referenced group didn't match, neither can this
|
||||
if (j < 0)
|
||||
return false;
|
||||
@ -4893,7 +4892,6 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
||||
matcher.hitEnd = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each new char to make sure it matches what the group
|
||||
// referenced matched last time around
|
||||
for (int index=0; index<groupSize; index++)
|
||||
|
@ -137,6 +137,11 @@ public final class Collectors {
|
||||
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}.
|
||||
*
|
||||
@ -166,7 +171,7 @@ public final class Collectors {
|
||||
BiConsumer<A, T> accumulator,
|
||||
BinaryOperator<A> combiner,
|
||||
Set<Characteristics> characteristics) {
|
||||
this(supplier, accumulator, combiner, i -> (R) i, characteristics);
|
||||
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -209,7 +214,7 @@ public final class Collectors {
|
||||
*/
|
||||
public static <T, C extends Collection<T>>
|
||||
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; },
|
||||
CH_ID);
|
||||
}
|
||||
@ -1046,30 +1051,23 @@ public final class Collectors {
|
||||
public static <T, D, A>
|
||||
Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
|
||||
Collector<? super T, A, D> downstream) {
|
||||
@SuppressWarnings("unchecked")
|
||||
BiConsumer<D, ? super T> downstreamAccumulator = (BiConsumer<D, ? super T>) downstream.accumulator();
|
||||
BiConsumer<Map<Boolean, A>, T> accumulator = (result, t) -> {
|
||||
Partition<D> asPartition = ((Partition<D>) result);
|
||||
downstreamAccumulator.accept(predicate.test(t) ? asPartition.forTrue : asPartition.forFalse, t);
|
||||
};
|
||||
BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
|
||||
BiConsumer<Partition<A>, T> accumulator = (result, t) ->
|
||||
downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
|
||||
BinaryOperator<A> op = downstream.combiner();
|
||||
BinaryOperator<Map<Boolean, A>> merger = (m1, m2) -> {
|
||||
Partition<A> left = (Partition<A>) m1;
|
||||
Partition<A> right = (Partition<A>) m2;
|
||||
return new Partition<>(op.apply(left.forTrue, right.forTrue),
|
||||
op.apply(left.forFalse, right.forFalse));
|
||||
};
|
||||
Supplier<Map<Boolean, A>> supplier = () -> new Partition<>(downstream.supplier().get(),
|
||||
downstream.supplier().get());
|
||||
BinaryOperator<Partition<A>> merger = (left, right) ->
|
||||
new Partition<>(op.apply(left.forTrue, right.forTrue),
|
||||
op.apply(left.forFalse, right.forFalse));
|
||||
Supplier<Partition<A>> supplier = () ->
|
||||
new Partition<>(downstream.supplier().get(),
|
||||
downstream.supplier().get());
|
||||
if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
|
||||
return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
|
||||
}
|
||||
else {
|
||||
Function<Map<Boolean, A>, Map<Boolean, D>> finisher = (Map<Boolean, A> par) -> {
|
||||
Partition<A> asAPartition = (Partition<A>) par;
|
||||
return new Partition<>(downstream.finisher().apply(asAPartition.forTrue),
|
||||
downstream.finisher().apply(asAPartition.forFalse));
|
||||
};
|
||||
Function<Partition<A>, Map<Boolean, D>> finisher = par ->
|
||||
new Partition<>(downstream.finisher().apply(par.forTrue),
|
||||
downstream.finisher().apply(par.forFalse));
|
||||
return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ final class DistinctOps {
|
||||
if (StreamOpFlag.DISTINCT.isKnown(flags)) {
|
||||
return sink;
|
||||
} else if (StreamOpFlag.SORTED.isKnown(flags)) {
|
||||
return new Sink.ChainedReference<T>(sink) {
|
||||
return new Sink.ChainedReference<T, T>(sink) {
|
||||
boolean seenNull;
|
||||
T lastSeen;
|
||||
|
||||
@ -132,7 +132,7 @@ final class DistinctOps {
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new Sink.ChainedReference<T>(sink) {
|
||||
return new Sink.ChainedReference<T, T>(sink) {
|
||||
Set<T> seen;
|
||||
|
||||
@Override
|
||||
|
@ -191,7 +191,7 @@ abstract class DoublePipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Double>(sink) {
|
||||
@Override
|
||||
public void accept(double t) {
|
||||
downstream.accept(mapper.applyAsDouble(t));
|
||||
@ -208,9 +208,8 @@ abstract class DoublePipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<U> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<U>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(double t) {
|
||||
downstream.accept(mapper.apply(t));
|
||||
}
|
||||
@ -226,7 +225,7 @@ abstract class DoublePipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Integer>(sink) {
|
||||
@Override
|
||||
public void accept(double t) {
|
||||
downstream.accept(mapper.applyAsInt(t));
|
||||
@ -243,7 +242,7 @@ abstract class DoublePipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Long>(sink) {
|
||||
@Override
|
||||
public void accept(double t) {
|
||||
downstream.accept(mapper.applyAsLong(t));
|
||||
@ -259,7 +258,7 @@ abstract class DoublePipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Double>(sink) {
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
@ -296,7 +295,7 @@ abstract class DoublePipeline<E_IN>
|
||||
StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Double>(sink) {
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
@ -319,7 +318,7 @@ abstract class DoublePipeline<E_IN>
|
||||
0) {
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Double>(sink) {
|
||||
@Override
|
||||
public void accept(double t) {
|
||||
consumer.accept(t);
|
||||
|
@ -189,9 +189,8 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Long>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(int t) {
|
||||
downstream.accept((long) t);
|
||||
}
|
||||
@ -206,9 +205,8 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Double>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(int t) {
|
||||
downstream.accept((double) t);
|
||||
}
|
||||
@ -229,7 +227,7 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Integer>(sink) {
|
||||
@Override
|
||||
public void accept(int t) {
|
||||
downstream.accept(mapper.applyAsInt(t));
|
||||
@ -246,9 +244,8 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<U>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(int t) {
|
||||
downstream.accept(mapper.apply(t));
|
||||
}
|
||||
@ -264,7 +261,7 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Long>(sink) {
|
||||
@Override
|
||||
public void accept(int t) {
|
||||
downstream.accept(mapper.applyAsLong(t));
|
||||
@ -281,7 +278,7 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Double>(sink) {
|
||||
@Override
|
||||
public void accept(int t) {
|
||||
downstream.accept(mapper.applyAsDouble(t));
|
||||
@ -297,7 +294,7 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Integer>(sink) {
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
@ -334,7 +331,7 @@ abstract class IntPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Integer>(sink) {
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
@ -357,7 +354,7 @@ abstract class IntPipeline<E_IN>
|
||||
0) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Integer>(sink) {
|
||||
@Override
|
||||
public void accept(int t) {
|
||||
consumer.accept(t);
|
||||
|
@ -186,7 +186,7 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Double>(sink) {
|
||||
@Override
|
||||
public void accept(long t) {
|
||||
downstream.accept((double) t);
|
||||
@ -208,9 +208,8 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Long>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(long t) {
|
||||
downstream.accept(mapper.applyAsLong(t));
|
||||
}
|
||||
@ -226,9 +225,8 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<U> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<U>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(long t) {
|
||||
downstream.accept(mapper.apply(t));
|
||||
}
|
||||
@ -244,9 +242,8 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Integer>(sink) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(long t) {
|
||||
downstream.accept(mapper.applyAsInt(t));
|
||||
}
|
||||
@ -262,7 +259,7 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Double>(sink) {
|
||||
@Override
|
||||
public void accept(long t) {
|
||||
downstream.accept(mapper.applyAsDouble(t));
|
||||
@ -278,7 +275,7 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Long>(sink) {
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
@ -315,7 +312,7 @@ abstract class LongPipeline<E_IN>
|
||||
StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Long>(sink) {
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
@ -338,7 +335,7 @@ abstract class LongPipeline<E_IN>
|
||||
0) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Long>(sink) {
|
||||
@Override
|
||||
public void accept(long t) {
|
||||
consumer.accept(t);
|
||||
|
@ -163,17 +163,16 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
||||
StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
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
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(P_OUT 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) {
|
||||
@Override
|
||||
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
|
||||
public void accept(P_OUT u) {
|
||||
downstream.accept(mapper.apply(u));
|
||||
@ -205,7 +204,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
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
|
||||
public void accept(P_OUT u) {
|
||||
downstream.accept(mapper.applyAsInt(u));
|
||||
@ -222,7 +221,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
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
|
||||
public void accept(P_OUT u) {
|
||||
downstream.accept(mapper.applyAsLong(u));
|
||||
@ -239,7 +238,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
|
||||
@Override
|
||||
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
|
||||
public void accept(P_OUT 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) {
|
||||
@Override
|
||||
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
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
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
|
||||
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) {
|
||||
@Override
|
||||
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;
|
||||
@Override
|
||||
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) {
|
||||
@Override
|
||||
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;
|
||||
@Override
|
||||
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) {
|
||||
@Override
|
||||
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;
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
@ -364,9 +362,8 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
||||
0) {
|
||||
@Override
|
||||
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
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(P_OUT u) {
|
||||
tee.accept(u);
|
||||
downstream.accept(u);
|
||||
@ -495,6 +492,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <R, A> R collect(Collector<? super P_OUT, A, ? extends R> collector) {
|
||||
A container;
|
||||
if (isParallel()
|
||||
|
@ -241,11 +241,10 @@ interface Sink<T> extends Consumer<T> {
|
||||
* implementation of the {@code accept()} method must call the correct
|
||||
* {@code accept()} method on the downstream {@code Sink}.
|
||||
*/
|
||||
static abstract class ChainedReference<T> implements Sink<T> {
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected final Sink downstream;
|
||||
static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
|
||||
protected final Sink<? super E_OUT> downstream;
|
||||
|
||||
public ChainedReference(Sink downstream) {
|
||||
public ChainedReference(Sink<? super E_OUT> 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
|
||||
* {@code accept()} method on the downstream {@code Sink}.
|
||||
*/
|
||||
static abstract class ChainedInt implements Sink.OfInt {
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected final Sink downstream;
|
||||
static abstract class ChainedInt<E_OUT> implements Sink.OfInt {
|
||||
protected final Sink<? super E_OUT> downstream;
|
||||
|
||||
public ChainedInt(Sink downstream) {
|
||||
public ChainedInt(Sink<? super E_OUT> 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
|
||||
* {@code accept()} method on the downstream {@code Sink}.
|
||||
*/
|
||||
static abstract class ChainedLong implements Sink.OfLong {
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected final Sink downstream;
|
||||
static abstract class ChainedLong<E_OUT> implements Sink.OfLong {
|
||||
protected final Sink<? super E_OUT> downstream;
|
||||
|
||||
public ChainedLong(Sink downstream) {
|
||||
public ChainedLong(Sink<? super E_OUT> 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
|
||||
* {@code accept()} method on the downstream {@code Sink}.
|
||||
*/
|
||||
static abstract class ChainedDouble implements Sink.OfDouble {
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected final Sink downstream;
|
||||
static abstract class ChainedDouble<E_OUT> implements Sink.OfDouble {
|
||||
protected final Sink<? super E_OUT> downstream;
|
||||
|
||||
public ChainedDouble(Sink downstream) {
|
||||
public ChainedDouble(Sink<? super E_OUT> downstream) {
|
||||
this.downstream = Objects.requireNonNull(downstream);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* may be may be skip-only, limit-only, or skip-and-limit.
|
||||
@ -107,12 +112,12 @@ final class SliceOps {
|
||||
* is to be imposed
|
||||
*/
|
||||
public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
|
||||
long skip, long limit) {
|
||||
long skip, long limit) {
|
||||
if (skip < 0)
|
||||
throw new IllegalArgumentException("Skip must be non-negative: " + skip);
|
||||
|
||||
return new ReferencePipeline.StatefulOp<T,T>(upstream, StreamShape.REFERENCE,
|
||||
flags(limit)) {
|
||||
return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
|
||||
flags(limit)) {
|
||||
Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
|
||||
long skip, long limit, long sizeIfKnown) {
|
||||
if (skip <= sizeIfKnown) {
|
||||
@ -146,7 +151,7 @@ final class SliceOps {
|
||||
// cancellation will be more aggressive cancelling later tasks
|
||||
// if the target slice size has been reached from a given task,
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
@ -182,7 +187,7 @@ final class SliceOps {
|
||||
|
||||
@Override
|
||||
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 m = limit >= 0 ? limit : Long.MAX_VALUE;
|
||||
|
||||
@ -291,7 +296,7 @@ final class SliceOps {
|
||||
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedInt(sink) {
|
||||
return new Sink.ChainedInt<Integer>(sink) {
|
||||
long n = skip;
|
||||
long m = limit >= 0 ? limit : Long.MAX_VALUE;
|
||||
|
||||
@ -400,7 +405,7 @@ final class SliceOps {
|
||||
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedLong(sink) {
|
||||
return new Sink.ChainedLong<Long>(sink) {
|
||||
long n = skip;
|
||||
long m = limit >= 0 ? limit : Long.MAX_VALUE;
|
||||
|
||||
@ -509,7 +514,7 @@ final class SliceOps {
|
||||
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedDouble(sink) {
|
||||
return new Sink.ChainedDouble<Double>(sink) {
|
||||
long n = skip;
|
||||
long m = limit >= 0 ? limit : Long.MAX_VALUE;
|
||||
|
||||
@ -560,13 +565,13 @@ final class SliceOps {
|
||||
|
||||
private volatile boolean completed;
|
||||
|
||||
SliceTask(AbstractPipeline<?, P_OUT, ?> op,
|
||||
SliceTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
|
||||
PipelineHelper<P_OUT> helper,
|
||||
Spliterator<P_IN> spliterator,
|
||||
IntFunction<P_OUT[]> generator,
|
||||
long offset, long size) {
|
||||
super(helper, spliterator);
|
||||
this.op = (AbstractPipeline<P_OUT, P_OUT, ?>) op;
|
||||
this.op = op;
|
||||
this.generator = generator;
|
||||
this.targetOffset = offset;
|
||||
this.targetSize = size;
|
||||
|
@ -129,7 +129,7 @@ final class SortedOps {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sink<T> opWrapSink(int flags, Sink sink) {
|
||||
public Sink<T> opWrapSink(int flags, Sink<T> sink) {
|
||||
Objects.requireNonNull(sink);
|
||||
|
||||
// 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.
|
||||
*/
|
||||
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 T[] array;
|
||||
private int offset;
|
||||
|
||||
SizedRefSortingSink(Sink<T> sink, Comparator<? super T> comparator) {
|
||||
SizedRefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
|
||||
super(sink);
|
||||
this.comparator = comparator;
|
||||
}
|
||||
@ -320,11 +320,11 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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 ArrayList<T> list;
|
||||
|
||||
RefSortingSink(Sink<T> sink, Comparator<? super T> comparator) {
|
||||
RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
|
||||
super(sink);
|
||||
this.comparator = comparator;
|
||||
}
|
||||
@ -352,11 +352,11 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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 offset;
|
||||
|
||||
SizedIntSortingSink(Sink downstream) {
|
||||
SizedIntSortingSink(Sink<? super Integer> downstream) {
|
||||
super(downstream);
|
||||
}
|
||||
|
||||
@ -386,10 +386,10 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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;
|
||||
|
||||
IntSortingSink(Sink sink) {
|
||||
IntSortingSink(Sink<? super Integer> sink) {
|
||||
super(sink);
|
||||
}
|
||||
|
||||
@ -417,11 +417,11 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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 int offset;
|
||||
|
||||
SizedLongSortingSink(Sink downstream) {
|
||||
SizedLongSortingSink(Sink<? super Long> downstream) {
|
||||
super(downstream);
|
||||
}
|
||||
|
||||
@ -451,10 +451,10 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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;
|
||||
|
||||
LongSortingSink(Sink sink) {
|
||||
LongSortingSink(Sink<? super Long> sink) {
|
||||
super(sink);
|
||||
}
|
||||
|
||||
@ -482,11 +482,11 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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 int offset;
|
||||
|
||||
SizedDoubleSortingSink(Sink downstream) {
|
||||
SizedDoubleSortingSink(Sink<? super Double> downstream) {
|
||||
super(downstream);
|
||||
}
|
||||
|
||||
@ -516,10 +516,10 @@ final class SortedOps {
|
||||
/**
|
||||
* {@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;
|
||||
|
||||
DoubleSortingSink(Sink sink) {
|
||||
DoubleSortingSink(Sink<? super Double> sink) {
|
||||
super(sink);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user