提交 f2ab9739 编写于 作者: L lana

Merge

......@@ -50,6 +50,7 @@ BUG_SUBMIT_LINE = <a href="$(BUG_SUBMIT_URL)">Submit a bug or feature</a>
DEV_DOCS_URL-5 = http://java.sun.com/j2se/1.5.0/docs/index.html
DEV_DOCS_URL-6 = http://download.oracle.com/javase/6/docs/index.html
DEV_DOCS_URL-7 = http://download.oracle.com/javase/7/docs/index.html
DEV_DOCS_URL-8 = http://download.oracle.com/javase/8/docs/index.html
DEV_DOCS_URL = $(DEV_DOCS_URL-$(JDK_MINOR_VERSION))
DOCS_BASE_URL = http://download.oracle.com/javase/7/docs
......
......@@ -33,6 +33,7 @@ FILES_c = \
Console_md.c \
Double.c \
Executable.c \
Field.c \
FileDescriptor_md.c \
FileInputStream.c \
FileInputStream_md.c \
......
......@@ -190,6 +190,8 @@ SUNWprivate_1.1 {
Java_java_lang_reflect_Array_setLong;
Java_java_lang_reflect_Array_setShort;
Java_java_lang_reflect_Executable_getParameters0;
Java_java_lang_reflect_Executable_getTypeAnnotationBytes0;
Java_java_lang_reflect_Field_getTypeAnnotationBytes0;
Java_java_lang_Runtime_freeMemory;
Java_java_lang_Runtime_maxMemory;
Java_java_lang_Runtime_gc;
......
......@@ -31,14 +31,14 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/4">
<compilation-unit>
<package-root>${root}/src/share/classes</package-root>
<package-root>${root}/src/macosx/classes</package-root>
<package-root>${root}/src/solaris/classes</package-root>
<package-root>${root}/src/windows/classes</package-root>
<classpath mode="boot">${bootstrap.jdk}/jre/lib/rt.jar</classpath>
<built-to>${root}/build/${platform}-${arch}/classes</built-to>
<built-to>${root}/../build/${platform}-${arch}/jdk/classes</built-to>
<javadoc-built-to>${root}/build/${platform}-${arch}/docs/api</javadoc-built-to>
<source-level>1.8</source-level>
</compilation-unit>
......
......@@ -31,11 +31,11 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/4">
<compilation-unit>
<package-root>${root}/src/share/classes</package-root>
<classpath mode="boot">${bootstrap.jdk}/jre/lib/rt.jar</classpath>
<built-to>${root}/build/${platform}-${arch}/classes</built-to>
<built-to>${root}/../build/${platform}-${arch}/jdk/classes</built-to>
<javadoc-built-to>${root}/build/${platform}-${arch}/docs/api</javadoc-built-to>
<source-level>1.8</source-level>
</compilation-unit>
......
......@@ -173,6 +173,44 @@ class JarMetaIndex {
*/
private HashMap<String, HashSet<String>> knownPrefixMap = new HashMap<>();
/*
* A class for mapping package prefixes to the number of
* levels of package elements to include.
*/
static class ExtraLevel {
public ExtraLevel(String prefix, int levels) {
this.prefix = prefix;
this.levels = levels;
}
String prefix;
int levels;
}
/*
* A list of the special-cased package names.
*/
private static ArrayList<ExtraLevel> extraLevels = new ArrayList<>();
static {
// The order of these statements is significant,
// since we stop looking after the first match.
// Need more precise information to disambiguate
// (illegal) references from applications to
// obsolete backported collections classes in
// com/sun/java/util
extraLevels.add(new ExtraLevel("com/sun/java/util/", Integer.MAX_VALUE));
extraLevels.add(new ExtraLevel("com/sun/java/", 4));
// Need more information than just first two package
// name elements to determine that classes in
// deploy.jar are not in rt.jar
extraLevels.add(new ExtraLevel("com/sun/", 3));
// Need to make sure things in jfr.jar aren't
// confused with other com/oracle/** packages
extraLevels.add(new ExtraLevel("com/oracle/jrockit", 3));
}
/*
* We add maximum 5 second level entries to "sun", "java" and
* "javax" entries. Tune this parameter to get a balance on the
......@@ -237,39 +275,25 @@ class JarMetaIndex {
String[] pkgElements = name.split("/");
// Last one is the class name; definitely ignoring that
if (pkgElements.length > 2) {
String meta = null;
// Need more information than just first two package
// name elements to determine that classes in
// deploy.jar are not in rt.jar
if (pkgElements.length > 3 &&
pkgElements[0].equals("com") &&
pkgElements[1].equals("sun")) {
// Need more precise information to disambiguate
// (illegal) references from applications to
// obsolete backported collections classes in
// com/sun/java/util
if (pkgElements.length > 4 &&
pkgElements[2].equals("java")) {
int bound = 0;
if (pkgElements[3].equals("util")) {
// Take all of the packages
bound = pkgElements.length - 1;
} else {
// Trim it somewhat more
bound = 4;
}
meta = "";
for (int j = 0; j < bound; j++) {
meta += pkgElements[j] + "/";
}
} else {
meta = pkgElements[0] + "/" + pkgElements[1]
+ "/" + pkgElements[2] + "/";
String meta = "";
// Default is 2 levels of package elements
int levels = 2;
// But for some packages we add more elements
for(ExtraLevel el : extraLevels) {
if (name.startsWith(el.prefix)) {
levels = el.levels;
break;
}
} else {
meta = pkgElements[0] + "/" + pkgElements[1] + "/";
}
indexSet.add(meta);
for (int i = 0; i < levels && i < pkgElements.length - 1; i++) {
meta += pkgElements[i] + "/";
}
if (!meta.equals("")) {
indexSet.add(meta);
}
}
} // end of "while" loop;
......
......@@ -237,10 +237,10 @@ endif
# These files do not appear in the build result of the old build. This
# is because they are generated sources, but the AUTO_JAVA_FILES won't
# pick them up since they aren't generated when the source dirs are
# pick them up since they aren't generated when the source dirs are
# searched and they aren't referenced by any other classes so they won't
# be picked up by implicit compilation. On a rebuild, they are picked up
# and compiled. Exclude them here to produce the same rt.jar as the old
# and compiled. Exclude them here to produce the same rt.jar as the old
# build does when building just once.
EXFILES+=javax/swing/plaf/nimbus/InternalFrameTitlePanePainter.java \
javax/swing/plaf/nimbus/OptionPaneMessageAreaPainter.java \
......@@ -308,19 +308,6 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\
##########################################################################################
ifndef OPENJDK
$(eval $(call SetupJavaCompilation,BUILD_ALTCLASSES,\
SETUP:=GENERATE_JDKBYTECODE,\
SRC:=$(JDK_TOPDIR)/src/closed/share/altclasses, \
BIN:=$(JDK_OUTPUTDIR)/altclasses_classes))
$(BUILD_ALTCLASSES): $(BUILD_JDK)
endif
##########################################################################################
$(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin:
$(MKDIR) -p $(@D)
$(TOUCH) $@
......@@ -403,7 +390,7 @@ endif
##########################################################################################
all: $(BUILD_JDK) $(BUILD_ALTCLASSES) $(BUILD_JOBJC) $(BUILD_JOBJC_HEADERS) $(COPY_EXTRA) \
all: $(BUILD_JDK) $(BUILD_JOBJC) $(BUILD_JOBJC_HEADERS) $(COPY_EXTRA) \
$(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin \
$(BUILD_ACCESSBRIDGE_32) $(BUILD_ACCESSBRIDGE_64) \
$(BUILD_ACCESSBRIDGE_LEGACY)
......
......@@ -1003,15 +1003,6 @@ endif
##########################################################################################
ifndef OPENJDK
$(eval $(call SetupArchive,BUILD_ALT_RT_JAR,,\
SRCS:=$(JDK_OUTPUTDIR)/altclasses_classes,\
JAR:=$(IMAGES_OUTPUTDIR)/lib/alt-rt.jar))
endif
##########################################################################################
# This file is imported from hotspot in Import.gmk. Copying it into images/lib so that
# all jars can be found in one place when creating images in Images.gmk. It needs to be
# done here so that clean targets can be simple and accurate.
......
......@@ -40,8 +40,8 @@ include profile-includes.txt
# imported (signed jars) rather than built.
#
# The incoming lists, eg PROFILE_1_JRE_JARS_FILES, are the jars to be
# included in this profile. They have the jar name relative to the lib
# directory. We have to turn these into targets by adding the
# included in this profile. They have the jar name relative to the lib
# directory. We have to turn these into targets by adding the
# $(IMAGES_OUTPUTDIR)/lib prefix
#
# Note that some jars may be optional depending on the type of build (jdk vs.
......@@ -69,10 +69,6 @@ PROFILE_3_JARS := \
$(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_3_JRE_JAR_FILES)) \
$(PROFILE_2_JARS)
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
......@@ -107,7 +103,7 @@ endif
ifeq ($(OPENJDK_TARGET_OS),windows)
ALL_JARS += $(IMAGES_OUTPUTDIR)/lib/ext/sunmscapi.jar
endif
endif
ifeq ($(OPENJDK_TARGET_OS),macosx)
ALL_JARS += $(IMAGES_OUTPUTDIR)/lib/JObjC.jar
......@@ -142,7 +138,7 @@ ALL_JRE_BIN_FILES := \
$(PROFILE_1_JRE_BIN_FILES) \
$(PROFILE_2_JRE_BIN_FILES) \
$(PROFILE_3_JRE_BIN_FILES) \
$(FULL_JRE_BIN_FILES)
$(FULL_JRE_BIN_FILES)
NOT_JRE_BIN_FILES := $(filter-out $(ALL_JRE_BIN_FILES), $(NEW_ALL_BIN_LIST))
......@@ -151,18 +147,18 @@ ifeq ($(PROFILE), profile_1)
NOT_JRE_BIN_FILES += \
$(PROFILE_2_JRE_BIN_FILES) \
$(PROFILE_3_JRE_BIN_FILES) \
$(FULL_JRE_BIN_FILES)
$(FULL_JRE_BIN_FILES)
endif
ifeq ($(PROFILE), profile_2)
NOT_JRE_BIN_FILES += \
$(PROFILE_3_JRE_BIN_FILES) \
$(FULL_JRE_BIN_FILES)
$(FULL_JRE_BIN_FILES)
endif
ifeq ($(PROFILE), profile_3)
NOT_JRE_BIN_FILES += \
$(FULL_JRE_BIN_FILES)
$(FULL_JRE_BIN_FILES)
endif
NOT_JRE_BIN_FILES := $(addprefix $(JDK_OUTPUTDIR)/bin/, $(NOT_JRE_BIN_FILES))
......@@ -175,7 +171,7 @@ ALL_JRE_LIB_FILES := \
$(PROFILE_1_JRE_LIB_FILES) \
$(PROFILE_2_JRE_LIB_FILES) \
$(PROFILE_3_JRE_LIB_FILES) \
$(FULL_JRE_LIB_FILES)
$(FULL_JRE_LIB_FILES)
NOT_JRE_LIB_FILES := $(filter-out $(ALL_JRE_LIB_FILES), $(NEW_ALL_LIB_LIST))
......@@ -191,18 +187,18 @@ ifeq ($(PROFILE), profile_1)
NOT_JRE_LIB_FILES += \
$(PROFILE_2_JRE_LIB_FILES) \
$(PROFILE_3_JRE_LIB_FILES) \
$(FULL_JRE_LIB_FILES)
$(FULL_JRE_LIB_FILES)
endif
ifeq ($(PROFILE), profile_2)
NOT_JRE_LIB_FILES += \
$(PROFILE_3_JRE_LIB_FILES) \
$(FULL_JRE_LIB_FILES)
$(FULL_JRE_LIB_FILES)
endif
ifeq ($(PROFILE), profile_3)
NOT_JRE_LIB_FILES += \
$(FULL_JRE_LIB_FILES)
$(FULL_JRE_LIB_FILES)
endif
# Exclude the custom jar files as these will be added back via a special rule
......@@ -210,7 +206,7 @@ NOT_JRE_LIB_FILES += $(CUSTOM_JARS)
###############################################################################
# Customization of rt.jar file contents
# These are expressed as exclusions from everything found in the
# These are expressed as exclusions from everything found in the
# JDK_OUTPUTDIR/classes directory
###############################################################################
......@@ -231,8 +227,8 @@ NOT_JRE_LIB_FILES += $(CUSTOM_JARS)
#
# These are specific types that must be included within a package.
# There are two cases:
# - individual types in a package that is otherwise excluded at this
# profile level. The only arises if there are split packages.
# - individual types in a package that is otherwise excluded at this
# profile level. The only arises if there are split packages.
#
# - A higher-level package is included in a high profile where a subpackage
# is included in a lower profile. Including the package in the high profile
......@@ -247,7 +243,7 @@ NOT_JRE_LIB_FILES += $(CUSTOM_JARS)
# containing package is include. Again this occurs with split packges.
#
# So the exclude list for each profile consists of the include lists
# for all profiles above it, together with any explicitly excluded types.
# for all profiles above it, together with any explicitly excluded types.
# This is then combined with the overall RT_JAR_EXCLUDES list (which covers
# things that go into other jar files).
#
......@@ -257,7 +253,7 @@ NOT_JRE_LIB_FILES += $(CUSTOM_JARS)
# profile 3 includes the entire package, but it is harmless to add them
# explicitly, and complex to determine if we still need to include them.
#
# Need a way to express:
# Need a way to express:
# for (int i = profile+1; i < 4; i++)
# RT_JAR_EXCLUDES += PROFILE_$i_RTJAR_INCLUDE_PACKAGES
#
......@@ -267,7 +263,7 @@ NOT_JRE_LIB_FILES += $(CUSTOM_JARS)
#
# These are META-INF/services/ entries found in resources.jar. Together
# resources.jar and rt.jar hold the contents of the classes directory, (the
# classes in rt.jar and everything else in resources.jar).Hence the
# classes in rt.jar and everything else in resources.jar).Hence the
# include/exclude information for resources.jar is tied to that of rt.jar
include profile-rtjar-includes.txt
......@@ -324,7 +320,7 @@ endif
# Filter out non-OpenJDK services
ifdef OPENJDK
EXCLUDED_SERVICES := META-INF/services/javax.script.ScriptEngineFactory
EXCLUDED_SERVICES := META-INF/services/javax.script.ScriptEngineFactory
PROFILE_INCLUDE_METAINF_SERVICES := $(filter-out $(EXCLUDED_SERVICES),$(PROFILE_INCLUDE_METAINF_SERVICES))
endif
......
......@@ -190,6 +190,8 @@ SUNWprivate_1.1 {
Java_java_lang_reflect_Array_setLong;
Java_java_lang_reflect_Array_setShort;
Java_java_lang_reflect_Executable_getParameters0;
Java_java_lang_reflect_Executable_getTypeAnnotationBytes0;
Java_java_lang_reflect_Field_getTypeAnnotationBytes0;
Java_java_lang_Runtime_freeMemory;
Java_java_lang_Runtime_maxMemory;
Java_java_lang_Runtime_gc;
......
......@@ -107,14 +107,14 @@ PROFILE_2_JRE_BIN_FILES := \
rmid$(EXE_SUFFIX) \
rmiregistry$(EXE_SUFFIX)
PROFILE_2_JRE_LIB_FILES :=
PROFILE_2_JRE_LIB_FILES :=
PROFILE_2_JRE_OTHER_FILES :=
PROFILE_2_JRE_OTHER_FILES :=
PROFILE_2_JRE_JAR_FILES :=
PROFILE_2_JRE_JAR_FILES :=
PROFILE_3_JRE_BIN_FILES :=
PROFILE_3_JRE_BIN_FILES :=
PROFILE_3_JRE_LIB_FILES := \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)hprof$(SHARED_LIBRARY_SUFFIX) \
......@@ -138,7 +138,7 @@ PROFILE_3_JRE_LIB_FILES := \
management/management.properties \
management/snmp.acl.template
PROFILE_3_JRE_OTHER_FILES :=
PROFILE_3_JRE_OTHER_FILES :=
PROFILE_3_JRE_JAR_FILES := \
management-agent.jar
......@@ -171,7 +171,6 @@ FULL_JRE_LIB_FILES := \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)splashscreen$(SHARED_LIBRARY_SUFFIX) \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)t2k$(SHARED_LIBRARY_SUFFIX) \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX) \
alt-rt.jar \
charsets.jar \
cmm/CIEXYZ.pf \
cmm/GRAY.pf \
......@@ -248,7 +247,6 @@ FULL_JRE_OTHER_FILES := \
man/man1/unpack200.1
FULL_JRE_JAR_FILES := \
alt-rt.jar \
charsets.jar \
ext/cldrdata.jar \
ext/dnsns.jar \
......
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -43,7 +43,7 @@ public final class AppleProvider extends Provider {
public AppleProvider() {
/* We are the Apple provider */
super("Apple", 1.1, info);
super("Apple", 1.8d, info);
AccessController.<Object>doPrivileged(new java.security.PrivilegedAction<Object>() {
public Object run() {
......
......@@ -104,7 +104,7 @@ public final class SunJCE extends Provider {
public SunJCE() {
/* We are the "SunJCE" provider */
super("SunJCE", 1.7d, info);
super("SunJCE", 1.8d, info);
final String BLOCK_MODES = "ECB|CBC|PCBC|CTR|CTS|CFB|OFB" +
"|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" +
......
/*
* Copyright (c) 2003, 2012, 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
......@@ -303,7 +303,7 @@ class Driver {
} else {
if (!packfile.toLowerCase().endsWith(".pack") &&
!packfile.toLowerCase().endsWith(".pac")) {
System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.WIRTE_PACKGZ_FILE),packfile));
System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.WRITE_PACKGZ_FILE),packfile));
printUsage(doPack, false, System.err);
System.exit(2);
}
......
/*
* Copyright (c) 2005, 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
......@@ -22,110 +22,99 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.java.util.jar.pack;
import java.util.ListResourceBundle;
public class DriverResource extends ListResourceBundle {
public static final String VERSION ="VERSION";
public static final String BAD_ARGUMENT ="BAD_ARGUMENT";
public static final String BAD_OPTION ="BAD_OPTION";
public static final String BAD_REPACK_OUTPUT="BAD_REPACK_OUTPUT";
public static final String DETECTED_ZIP_COMMENT="DETECTED_ZIP_COMMENT";
public static final String SKIP_FOR_REPACKED ="SKIP_FOR_REPACKED";
public static final String WRITE_PACK_FILE ="WRITE_PACK_FILE";
public static final String WIRTE_PACKGZ_FILE="WIRTE_PACKGZ_FILE";
public static final String SKIP_FOR_MOVE_FAILED="SKIP_FOR_MOVE_FAILED";
public static final String PACK_HELP="PACK_HELP";
public static final String UNPACK_HELP ="UNPACK_HELP";
public static final String MORE_INFO = "MORE_INFO";
public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION";
public static final String BAD_SPEC = "BAD_SPEC";
//The following string is duplicate in PACK and UNPACK comment,which was draw out to ruduce translation work.
private static final String PARAMETER_V = " -v, --verbose increase program verbosity";
private static final String PARAMETER_Q = " -q, --quiet set verbosity to lowest level";
private static final String PARAMETER_LF = " -l{F}, --log-file={F} output to the given log file, or '-' for System.out";
private static final String PARAMETER_H = " -?, -h, --help print this message";
private static final String PARAMETER_VER = " -V, --version print program version";
private static final String PARAMETER_J = " -J{X} pass option X to underlying Java VM";
//The following are outputs of command 'pack200' and 'unpack200'.
//Don't translate command arguments ,words with a prefix of '-' or '--'.
//
private static final Object[][] resource= {
{VERSION,"{0} version {1}"},//parameter 0:class name;parameter 1: version value
{BAD_ARGUMENT,"Bad argument: {0}"},
{BAD_OPTION,"Bad option: {0}={1}"},//parameter 0:option name;parameter 1:option value
{BAD_REPACK_OUTPUT,"Bad --repack output: {0}"},//parameter 0:filename
{DETECTED_ZIP_COMMENT,"Detected ZIP comment: {0}"},//parameter 0:comment
{SKIP_FOR_REPACKED,"Skipping because already repacked: {0}"},//parameter 0:filename
{WRITE_PACK_FILE,"To write a *.pack file, specify --no-gzip: {0}"},//parameter 0:filename
{WIRTE_PACKGZ_FILE,"To write a *.pack.gz file, specify --gzip: {0}"},//parameter 0:filename
{SKIP_FOR_MOVE_FAILED,"Skipping unpack because move failed: {0}"},//parameter 0:filename
{PACK_HELP,new String[]{
"Usage: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar",
"",
"Packing Options",
" -g, --no-gzip output a plain *.pack file with no zipping",
" --gzip (default) post-process the pack output with gzip",
" -G, --strip-debug remove debugging attributes while packing",
" -O, --no-keep-file-order do not transmit file ordering information",
" --keep-file-order (default) preserve input file ordering",
" -S{N}, --segment-limit={N} output segment limit (default N=1Mb)",
" -E{N}, --effort={N} packing effort (default N=5)",
" -H{h}, --deflate-hint={h} transmit deflate hint: true, false, or keep (default)",
" -m{V}, --modification-time={V} transmit modtimes: latest or keep (default)",
" -P{F}, --pass-file={F} transmit the given input element(s) uncompressed",
" -U{a}, --unknown-attribute={a} unknown attribute action: error, strip, or pass (default)",
" -C{N}={L}, --class-attribute={N}={L} (user-defined attribute)",
" -F{N}={L}, --field-attribute={N}={L} (user-defined attribute)",
" -M{N}={L}, --method-attribute={N}={L} (user-defined attribute)",
" -D{N}={L}, --code-attribute={N}={L} (user-defined attribute)",
" -f{F}, --config-file={F} read file F for Pack200.Packer properties",
PARAMETER_V ,
PARAMETER_Q ,
PARAMETER_LF ,
PARAMETER_H ,
PARAMETER_VER ,
PARAMETER_J,
"",
"Notes:",
" The -P, -C, -F, -M, and -D options accumulate.",
" Example attribute definition: -C SourceFile=RUH .",
" Config. file properties are defined by the Pack200 API.",
" For meaning of -S, -E, -H-, -m, -U values, see Pack200 API.",
" Layout definitions (like RUH) are defined by JSR 200.",
"",
"Repacking mode updates the JAR file with a pack/unpack cycle:",
" pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n"
}
},
{UNPACK_HELP,new String[]{
"Usage: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n",
"",
"Unpacking Options",
" -H{h}, --deflate-hint={h} override transmitted deflate hint: true, false, or keep (default)",
" -r, --remove-pack-file remove input file after unpacking",
PARAMETER_V ,
PARAMETER_Q ,
PARAMETER_LF ,
PARAMETER_H ,
PARAMETER_VER ,
PARAMETER_J,
}
},
{MORE_INFO,"(For more information, run {0} --help .)"},//parameter 0:command name
{DUPLICATE_OPTION,"duplicate option: {0}"},//parameter 0:option
{BAD_SPEC,"bad spec for {0}: {1}"},//parameter 0:option;parameter 1:specifier
};
protected Object[][] getContents() {
return resource;
}
public static final String VERSION = "VERSION";
public static final String BAD_ARGUMENT = "BAD_ARGUMENT";
public static final String BAD_OPTION = "BAD_OPTION";
public static final String BAD_REPACK_OUTPUT = "BAD_REPACK_OUTPUT";
public static final String DETECTED_ZIP_COMMENT = "DETECTED_ZIP_COMMENT";
public static final String SKIP_FOR_REPACKED = "SKIP_FOR_REPACKED";
public static final String WRITE_PACK_FILE = "WRITE_PACK_FILE";
public static final String WRITE_PACKGZ_FILE = "WRITE_PACKGZ_FILE";
public static final String SKIP_FOR_MOVE_FAILED = "SKIP_FOR_MOVE_FAILED";
public static final String PACK_HELP = "PACK_HELP";
public static final String UNPACK_HELP = "UNPACK_HELP";
public static final String MORE_INFO = "MORE_INFO";
public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION";
public static final String BAD_SPEC = "BAD_SPEC";
/*
* The following are the output of 'pack200' and 'unpack200' commands.
* Do not translate command arguments and words with a prefix of '-' or '--'.
*/
private static final Object[][] resource = {
{VERSION, "{0} version {1}"}, // parameter 0:class name;parameter 1: version value
{BAD_ARGUMENT, "Bad argument: {0}"},
{BAD_OPTION, "Bad option: {0}={1}"}, // parameter 0:option name;parameter 1:option value
{BAD_REPACK_OUTPUT, "Bad --repack output: {0}"}, // parameter 0:filename
{DETECTED_ZIP_COMMENT, "Detected ZIP comment: {0}"}, // parameter 0:comment
{SKIP_FOR_REPACKED, "Skipping because already repacked: {0}"}, // parameter 0:filename
{WRITE_PACK_FILE, "To write a *.pack file, specify --no-gzip: {0}"}, // parameter 0:filename
{WRITE_PACKGZ_FILE, "To write a *.pack.gz file, specify --gzip: {0}"}, // parameter 0:filename
{SKIP_FOR_MOVE_FAILED, "Skipping unpack because move failed: {0}"}, // parameter 0:filename
{PACK_HELP, new String[] {
"Usage: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar",
"",
"Packing Options",
" -g, --no-gzip output a plain *.pack file with no zipping",
" --gzip (default) post-process the pack output with gzip",
" -G, --strip-debug remove debugging attributes while packing",
" -O, --no-keep-file-order do not transmit file ordering information",
" --keep-file-order (default) preserve input file ordering",
" -S{N}, --segment-limit={N} output segment limit (default N=1Mb)",
" -E{N}, --effort={N} packing effort (default N=5)",
" -H{h}, --deflate-hint={h} transmit deflate hint: true, false, or keep (default)",
" -m{V}, --modification-time={V} transmit modtimes: latest or keep (default)",
" -P{F}, --pass-file={F} transmit the given input element(s) uncompressed",
" -U{a}, --unknown-attribute={a} unknown attribute action: error, strip, or pass (default)",
" -C{N}={L}, --class-attribute={N}={L} (user-defined attribute)",
" -F{N}={L}, --field-attribute={N}={L} (user-defined attribute)",
" -M{N}={L}, --method-attribute={N}={L} (user-defined attribute)",
" -D{N}={L}, --code-attribute={N}={L} (user-defined attribute)",
" -f{F}, --config-file={F} read file F for Pack200.Packer properties",
" -v, --verbose increase program verbosity",
" -q, --quiet set verbosity to lowest level",
" -l{F}, --log-file={F} output to the given log file, or '-' for System.out",
" -?, -h, --help print this message",
" -V, --version print program version",
" -J{X} pass option X to underlying Java VM",
"",
"Notes:",
" The -P, -C, -F, -M, and -D options accumulate.",
" Example attribute definition: -C SourceFile=RUH .",
" Config. file properties are defined by the Pack200 API.",
" For meaning of -S, -E, -H-, -m, -U values, see Pack200 API.",
" Layout definitions (like RUH) are defined by JSR 200.",
"",
"Repacking mode updates the JAR file with a pack/unpack cycle:",
" pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n"
}
},
{UNPACK_HELP, new String[] {
"Usage: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n",
"",
"Unpacking Options",
" -H{h}, --deflate-hint={h} override transmitted deflate hint: true, false, or keep (default)",
" -r, --remove-pack-file remove input file after unpacking",
" -v, --verbose increase program verbosity",
" -q, --quiet set verbosity to lowest level",
" -l{F}, --log-file={F} output to the given log file, or '-' for System.out",
" -?, -h, --help print this message",
" -V, --version print program version",
" -J{X} pass option X to underlying Java VM"
}
},
{MORE_INFO, "(For more information, run {0} --help .)"}, // parameter 0:command name
{DUPLICATE_OPTION, "duplicate option: {0}"}, // parameter 0:option
{BAD_SPEC, "bad spec for {0}: {1}"}, // parameter 0:option;parameter 1:specifier
};
protected Object[][] getContents() {
return resource;
}
}
/*
* 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
......@@ -53,7 +53,7 @@ public final class Provider extends java.security.Provider {
" server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)";
public Provider() {
super("SunSASL", 1.7d, info);
super("SunSASL", 1.8d, info);
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
......
......@@ -1908,10 +1908,18 @@ public class File
} else {
n = Math.abs(n);
}
// Use only the file name from the supplied prefix
prefix = (new File(prefix)).getName();
String name = prefix + Long.toString(n) + suffix;
File f = new File(dir, name);
if (!name.equals(f.getName()) || f.isInvalid())
throw new IOException("Unable to create temporary file");
if (!name.equals(f.getName()) || f.isInvalid()) {
if (System.getSecurityManager() != null)
throw new IOException("Unable to create temporary file");
else
throw new IOException("Unable to create temporary file, " + f);
}
return f;
}
}
......
......@@ -3414,16 +3414,20 @@ public final class Class<T> implements java.io.Serializable,
transient ClassValue.ClassValueMap classValueMap;
/**
* Returns an AnnotatedType object that represents the use of a type to specify
* the superclass of the entity represented by this Class. (The <em>use</em> of type
* Foo to specify the superclass in '... extends Foo' is distinct from the
* <em>declaration</em> of type Foo.)
* Returns an {@code AnnotatedType} object that represents the use of a
* type to specify the superclass of the entity represented by this {@code
* Class} object. (The <em>use</em> of type Foo to specify the superclass
* in '... extends Foo' is distinct from the <em>declaration</em> of type
* Foo.)
*
* If this Class represents a class type whose declaration does not explicitly
* indicate an annotated superclass, the return value is null.
* <p> If this {@code Class} object represents a type whose declaration
* does not explicitly indicate an annotated superclass, then the return
* value is an {@code AnnotatedType} object representing an element with no
* annotations.
*
* If this Class represents either the Object class, an interface type, an
* array type, a primitive type, or void, the return value is null.
* <p> If this {@code Class} represents either the {@code Object} class, an
* interface type, an array type, a primitive type, or void, the return
* value is {@code null}.
*
* @return an object representing the superclass
* @since 1.8
......@@ -3441,29 +3445,32 @@ public final class Class<T> implements java.io.Serializable,
}
/**
* Returns an array of AnnotatedType objects that represent the use of types to
* specify superinterfaces of the entity represented by this Class. (The <em>use</em>
* of type Foo to specify a superinterface in '... implements Foo' is
* distinct from the <em>declaration</em> of type Foo.)
*
* If this Class represents a class, the return value is an array
* containing objects representing the uses of interface types to specify
* interfaces implemented by the class. The order of the objects in the
* array corresponds to the order of the interface types used in the
* 'implements' clause of the declaration of this Class.
* Returns an array of {@code AnnotatedType} objects that represent the use
* of types to specify superinterfaces of the entity represented by this
* {@code Class} object. (The <em>use</em> of type Foo to specify a
* superinterface in '... implements Foo' is distinct from the
* <em>declaration</em> of type Foo.)
*
* If this Class represents an interface, the return value is an array
* containing objects representing the uses of interface types to specify
* interfaces directly extended by the interface. The order of the objects in
* <p> If this {@code Class} object represents a class, the return value is
* an array containing objects representing the uses of interface types to
* specify interfaces implemented by the class. The order of the objects in
* the array corresponds to the order of the interface types used in the
* 'extends' clause of the declaration of this Class.
* 'implements' clause of the declaration of this {@code Class} object.
*
* If this Class represents a class or interface whose declaration does not
* explicitly indicate any annotated superinterfaces, the return value is an
* array of length 0.
* <p> If this {@code Class} object represents an interface, the return
* value is an array containing objects representing the uses of interface
* types to specify interfaces directly extended by the interface. The
* order of the objects in the array corresponds to the order of the
* interface types used in the 'extends' clause of the declaration of this
* {@code Class} object.
*
* <p> If this {@code Class} object represents a class or interface whose
* declaration does not explicitly indicate any annotated superinterfaces,
* the return value is an array of length 0.
*
* If this Class represents either the Object class, an array type, a
* primitive type, or void, the return value is an array of length 0.
* <p> If this {@code Class} object represents either the {@code Object}
* class, an array type, a primitive type, or void, the return value is an
* array of length 0.
*
* @return an array representing the superinterfaces
* @since 1.8
......
......@@ -125,10 +125,7 @@ import static sun.invoke.util.Wrapper.isWrapperType;
this.implMethod = implMethod;
this.implInfo = caller.revealDirect(implMethod);
// @@@ Temporary work-around pending resolution of 8005119
this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
? MethodHandleInfo.REF_invokeVirtual
: implInfo.getReferenceKind();
this.implKind = implInfo.getReferenceKind();
this.implIsInstanceMethod =
implKind == MethodHandleInfo.REF_invokeVirtual ||
implKind == MethodHandleInfo.REF_invokeSpecial ||
......
......@@ -360,6 +360,10 @@ import jdk.internal.org.objectweb.asm.Type;
return new Name(mh, mhName);
}
NamedFunction getterFunction(int i) {
return new NamedFunction(getters[i]);
}
static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
......@@ -394,6 +398,7 @@ import jdk.internal.org.objectweb.asm.Type;
private boolean isPlaceholder() { return clazz == null; }
private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
static { CACHE.put("", EMPTY); } // make bootstrap predictable
private static final boolean INIT_DONE; // set after <clinit> finishes...
SpeciesData extendWithType(char type) {
......@@ -524,18 +529,18 @@ import jdk.internal.org.objectweb.asm.Type;
* A concrete BMH species adheres to the following schema:
*
* <pre>
* class Species_<<types>> extends BoundMethodHandle {
* <<fields>>
* final SpeciesData speciesData() { return SpeciesData.get("<<types>>"); }
* class Species_[[types]] extends BoundMethodHandle {
* [[fields]]
* final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
* }
* </pre>
*
* The {@code <<types>>} signature is precisely the string that is passed to this
* The {@code [[types]]} signature is precisely the string that is passed to this
* method.
*
* The {@code <<fields>>} section consists of one field definition per character in
* The {@code [[fields]]} section consists of one field definition per character in
* the type signature, adhering to the naming schema described in the definition of
* {@link #makeFieldName()}.
* {@link #makeFieldName}.
*
* For example, a concrete BMH species for two reference and one integral bound values
* would have the following shape:
......@@ -817,7 +822,7 @@ import jdk.internal.org.objectweb.asm.Type;
* {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
* {@link MethodHandle#linkToSpecial}.
*
* The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void}
* The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
* result of the {@code <init>} invocation. This entry is replaced.
*/
private static MethodHandle linkConstructor(MethodHandle cmh) {
......
......@@ -60,7 +60,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
* <p>
* Here is a sample use of call sites and bootstrap methods which links every
* dynamic call site to print its arguments:
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
<blockquote><pre>{@code
static void test() throws Throwable {
// THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
......@@ -79,7 +79,7 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam
// ignore caller and name, but match the type:
return new ConstantCallSite(printArgs.asType(type));
}
</pre></blockquote>
}</pre></blockquote>
* @author John Rose, JSR 292 EG
*/
abstract
......@@ -199,12 +199,12 @@ public class CallSite {
* which has been linked to this call site.
* <p>
* This method is equivalent to the following code:
* <blockquote><pre>
* <blockquote><pre>{@code
* MethodHandle getTarget, invoker, result;
* getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
* invoker = MethodHandles.exactInvoker(this.type());
* result = MethodHandles.foldArguments(invoker, getTarget)
* </pre></blockquote>
* }</pre></blockquote>
*
* @return a method handle which always invokes this call site's current target
*/
......@@ -261,7 +261,7 @@ public class CallSite {
Object info,
// Caller information:
Class<?> callerClass) {
Object caller = IMPL_LOOKUP.in(callerClass);
MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
CallSite site;
try {
Object binding;
......@@ -273,14 +273,44 @@ public class CallSite {
} else {
Object[] argv = (Object[]) info;
maybeReBoxElements(argv);
if (3 + argv.length > 255)
throw new BootstrapMethodError("too many bootstrap method arguments");
MethodType bsmType = bootstrapMethod.type();
if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
binding = bootstrapMethod.invoke(caller, name, type, argv);
else
binding = MethodHandles.spreadInvoker(bsmType, 3)
.invoke(bootstrapMethod, caller, name, type, argv);
switch (argv.length) {
case 0:
binding = bootstrapMethod.invoke(caller, name, type);
break;
case 1:
binding = bootstrapMethod.invoke(caller, name, type,
argv[0]);
break;
case 2:
binding = bootstrapMethod.invoke(caller, name, type,
argv[0], argv[1]);
break;
case 3:
binding = bootstrapMethod.invoke(caller, name, type,
argv[0], argv[1], argv[2]);
break;
case 4:
binding = bootstrapMethod.invoke(caller, name, type,
argv[0], argv[1], argv[2], argv[3]);
break;
case 5:
binding = bootstrapMethod.invoke(caller, name, type,
argv[0], argv[1], argv[2], argv[3], argv[4]);
break;
case 6:
binding = bootstrapMethod.invoke(caller, name, type,
argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
break;
default:
final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type)
if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
throw new BootstrapMethodError("too many bootstrap method arguments");
MethodType bsmType = bootstrapMethod.type();
MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
binding = spreader.invokeExact(typedBSM, (Object)caller, (Object)name, (Object)type, argv);
}
}
//System.out.println("BSM for "+name+type+" => "+binding);
if (binding instanceof CallSite) {
......
......@@ -257,12 +257,12 @@ class DirectMethodHandle extends MethodHandle {
assert(names.length == nameCursor);
if (doesAlloc) {
// names = { argx,y,z,... new C, init method }
names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
} else if (needsInit) {
names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
} else {
names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
}
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
......@@ -637,18 +637,18 @@ class DirectMethodHandle extends MethodHandle {
final int RESULT = nameCursor-1; // either the call or the cast
Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
if (needsInit)
names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
if (needsCast && !isGetter)
names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
assert(outArgs.length == (isGetter ? 3 : 4));
outArgs[0] = UNSAFE;
if (isStatic) {
outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]);
outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
} else {
outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
outArgs[2] = names[F_OFFSET] = new Name(NF_fieldOffset, names[DMH_THIS]);
outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
}
if (!isGetter) {
outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
......@@ -656,7 +656,7 @@ class DirectMethodHandle extends MethodHandle {
for (Object a : outArgs) assert(a != null);
names[LINKER_CALL] = new Name(linker, outArgs);
if (needsCast && isGetter)
names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
for (Name n : names) assert(n != null);
String fieldOrStatic = (isStatic ? "Static" : "Field");
String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging
......@@ -665,48 +665,54 @@ class DirectMethodHandle extends MethodHandle {
return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
}
private static final NamedFunction
NF_internalMemberName,
NF_internalMemberNameEnsureInit,
NF_ensureInitialized,
NF_fieldOffset,
NF_checkBase,
NF_staticBase,
NF_staticOffset,
NF_checkCast,
NF_allocateInstance,
NF_constructorMethod;
static {
try {
NamedFunction nfs[] = {
NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("internalMemberName", Object.class)),
NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("ensureInitialized", Object.class)),
NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("fieldOffset", Object.class)),
NF_checkBase = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("checkBase", Object.class)),
NF_staticBase = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("staticBase", Object.class)),
NF_staticOffset = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("staticOffset", Object.class)),
NF_checkCast = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("checkCast", Object.class, Object.class)),
NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("allocateInstance", Object.class)),
NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("constructorMethod", Object.class))
};
for (NamedFunction nf : nfs) {
// Each nf must be statically invocable or we get tied up in our bootstraps.
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
nf.resolve();
/**
* Pre-initialized NamedFunctions for bootstrapping purposes.
* Factored in an inner class to delay initialization until first usage.
*/
private static class Lazy {
static final NamedFunction
NF_internalMemberName,
NF_internalMemberNameEnsureInit,
NF_ensureInitialized,
NF_fieldOffset,
NF_checkBase,
NF_staticBase,
NF_staticOffset,
NF_checkCast,
NF_allocateInstance,
NF_constructorMethod;
static {
try {
NamedFunction nfs[] = {
NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("internalMemberName", Object.class)),
NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("ensureInitialized", Object.class)),
NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("fieldOffset", Object.class)),
NF_checkBase = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("checkBase", Object.class)),
NF_staticBase = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("staticBase", Object.class)),
NF_staticOffset = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("staticOffset", Object.class)),
NF_checkCast = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("checkCast", Object.class, Object.class)),
NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("allocateInstance", Object.class)),
NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("constructorMethod", Object.class))
};
for (NamedFunction nf : nfs) {
// Each nf must be statically invocable or we get tied up in our bootstraps.
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
nf.resolve();
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
}
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.invoke;
import sun.invoke.util.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Adapters which manage inexact MethodHandle.invoke calls.
* The JVM calls one of these when the exact type match fails.
* @author jrose
*/
class InvokeGeneric {
// erased type for the call, which originates from an inexact invoke site
private final MethodType erasedCallerType;
// an invoker of type (MT, MH; A...) -> R
private final MethodHandle initialInvoker;
/** Compute and cache information for this adapter, so that it can
* call out to targets of the erasure-family of the given erased type.
*/
/*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
assert(erasedCallerType.equals(erasedCallerType.erase()));
this.erasedCallerType = erasedCallerType;
this.initialInvoker = makeInitialInvoker();
assert initialInvoker.type().equals(erasedCallerType
.insertParameterTypes(0, MethodType.class, MethodHandle.class))
: initialInvoker.type();
}
private static MethodHandles.Lookup lookup() {
return IMPL_LOOKUP;
}
/** Return the adapter information for this type's erasure. */
/*non-public*/ static MethodHandle generalInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException {
InvokeGeneric gen = new InvokeGeneric(erasedCallerType);
return gen.initialInvoker;
}
private MethodHandle makeInitialInvoker() throws ReflectiveOperationException {
// postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
MethodHandle postDispatch = makePostDispatchInvoker();
MethodHandle invoker;
if (returnConversionPossible()) {
invoker = MethodHandles.foldArguments(postDispatch,
dispatcher("dispatchWithConversion"));
} else {
invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
}
return invoker;
}
private static final Class<?>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
private MethodHandle makePostDispatchInvoker() {
// Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
return invokerType.invokers().exactInvoker();
}
private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
}
private MethodHandle dispatcher(String dispatchName) throws ReflectiveOperationException {
return lookup().bind(this, dispatchName,
MethodType.methodType(MethodHandle.class,
MethodType.class, MethodHandle.class));
}
static final boolean USE_AS_TYPE_PATH = true;
/** Return a method handle to invoke on the callerType, target, and remaining arguments.
* The method handle must finish the call.
* This is the first look at the caller type and target.
*/
private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
MethodType targetType = target.type();
if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
MethodHandle newTarget = target.asType(callerType);
targetType = callerType;
Invokers invokers = targetType.invokers();
MethodHandle invoker = invokers.erasedInvokerWithDrops;
if (invoker == null) {
invokers.erasedInvokerWithDrops = invoker =
dropDispatchArguments(invokers.erasedInvoker());
}
return invoker.bindTo(newTarget);
}
throw new RuntimeException("NYI");
}
private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
MethodHandle finisher = dispatch(callerType, target);
if (returnConversionNeeded(callerType, target))
finisher = addReturnConversion(finisher, callerType.returnType()); //FIXME: slow
return finisher;
}
private boolean returnConversionPossible() {
Class<?> needType = erasedCallerType.returnType();
return !needType.isPrimitive();
}
private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
Class<?> needType = callerType.returnType();
if (needType == erasedCallerType.returnType())
return false; // no conversions possible, since must be primitive or Object
Class<?> haveType = target.type().returnType();
if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface())
return false;
return true;
}
private MethodHandle addReturnConversion(MethodHandle finisher, Class<?> type) {
// FIXME: This is slow because it creates a closure node on every call that requires a return cast.
MethodType finisherType = finisher.type();
MethodHandle caster = ValueConversions.identity(type);
caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType()));
finisher = MethodHandles.filterReturnValue(finisher, caster);
return finisher.asType(finisherType);
}
public String toString() {
return "InvokeGeneric"+erasedCallerType;
}
}
......@@ -242,9 +242,6 @@ class InvokerBytecodeGenerator {
/**
* Extract the MemberName of a newly-defined method.
*
* @param classFile
* @return
*/
private MemberName loadMethod(byte[] classFile) {
Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
......@@ -253,10 +250,6 @@ class InvokerBytecodeGenerator {
/**
* Define a given class as anonymous class in the runtime system.
*
* @param classBytes
* @param patches
* @return
*/
private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
......@@ -264,14 +257,6 @@ class InvokerBytecodeGenerator {
return invokerClass;
}
/**
* TODO
*
* @param invokerClass
* @param name
* @param type
* @return
*/
private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
//System.out.println("resolveInvokerMember => "+member);
......@@ -499,10 +484,6 @@ class InvokerBytecodeGenerator {
/**
* Generate customized bytecode for a given LambdaForm.
*
* @param form
* @param invokerType
* @return
*/
static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
......@@ -565,8 +546,6 @@ class InvokerBytecodeGenerator {
/**
* Emit an invoke for the given name.
*
* @param name
*/
void emitInvoke(Name name) {
if (true) {
......@@ -645,8 +624,6 @@ class InvokerBytecodeGenerator {
/**
* Emit an invoke for the given name, using the MemberName directly.
*
* @param name
*/
void emitStaticInvoke(MemberName member, Name name) {
assert(member.equals(name.function.member()));
......@@ -690,9 +667,6 @@ class InvokerBytecodeGenerator {
/**
* Check if MemberName is a call to MethodHandleImpl.selectAlternative.
*
* @param member
* @return true if member is a call to MethodHandleImpl.selectAlternative
*/
private boolean isSelectAlternative(MemberName member) {
return member != null &&
......@@ -704,14 +678,12 @@ class InvokerBytecodeGenerator {
* Emit bytecode for the selectAlternative idiom.
*
* The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
*
* <blockquote><pre>{@code
* Lambda(a0:L,a1:I)=>{
* t2:I=foo.test(a1:I);
* t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
* t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
*
* @param selectAlternativeName
* @param invokeBasicName
* }</pre></blockquote>
*/
private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
MethodType type = selectAlternativeName.function.methodType();
......@@ -750,11 +722,6 @@ class InvokerBytecodeGenerator {
mv.visitLabel(L_done);
}
/**
*
* @param name
* @param paramIndex
*/
private void emitPushArgument(Name name, int paramIndex) {
Object arg = name.arguments[paramIndex];
char ptype = name.function.parameterType(paramIndex);
......@@ -923,9 +890,6 @@ class InvokerBytecodeGenerator {
/**
* Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
*
* @param sig
* @return
*/
static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
assert(LambdaForm.isValidSignature(sig));
......@@ -993,10 +957,6 @@ class InvokerBytecodeGenerator {
/**
* Generate bytecode for a NamedFunction invoker.
*
* @param srcType
* @param dstType
* @return
*/
static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
......
......@@ -44,6 +44,7 @@ class Invokers {
// exact invoker for the outgoing call
private /*lazy*/ MethodHandle exactInvoker;
private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact)
// erased (partially untyped but with primitives) invoker for the outgoing call
// FIXME: get rid of
......@@ -74,21 +75,7 @@ class Invokers {
/*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker;
MethodType mtype = targetType;
MethodType invokerType = mtype.invokerType();
LambdaForm lform;
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) {
lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
} else {
// At maximum arity, we cannot afford an extra mtype argument,
// so build a fully customized (non-cached) invoker form.
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform);
}
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
assert(checkInvoker(invoker));
invoker = makeExactOrGeneralInvoker(true);
exactInvoker = invoker;
return invoker;
}
......@@ -96,43 +83,56 @@ class Invokers {
/*non-public*/ MethodHandle generalInvoker() {
MethodHandle invoker = generalInvoker;
if (invoker != null) return invoker;
invoker = makeExactOrGeneralInvoker(false);
generalInvoker = invoker;
return invoker;
}
private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
MethodType mtype = targetType;
MethodType invokerType = mtype.invokerType();
LambdaForm lform;
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED);
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) {
prepareForGenericCall(mtype);
lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
} else {
// At maximum arity, we cannot afford an extra mtype argument,
// so build a fully customized (non-cached) invoker form.
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform);
}
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
LambdaForm lform = invokeHandleForm(mtype, false, which);
MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
String whichName = (isExact ? "invokeExact" : "invoke");
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype));
assert(checkInvoker(invoker));
generalInvoker = invoker;
maybeCompileToBytecode(invoker);
return invoker;
}
/*non-public*/ MethodHandle makeBasicInvoker() {
MethodHandle invoker = DirectMethodHandle.make(invokeBasicMethod(targetType));
assert(targetType == targetType.basicType());
// Note: This is not cached here. It is cached by the calling MethodTypeForm.
/** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */
private void maybeCompileToBytecode(MethodHandle invoker) {
final int EAGER_COMPILE_ARITY_LIMIT = 10;
if (targetType == targetType.erase() &&
targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) {
invoker.form.compileToBytecode();
}
}
/*non-public*/ MethodHandle basicInvoker() {
MethodHandle invoker = basicInvoker;
if (invoker != null) return invoker;
MethodType basicType = targetType.basicType();
if (basicType != targetType) {
// double cache; not used significantly
return basicInvoker = basicType.invokers().basicInvoker();
}
MemberName method = invokeBasicMethod(basicType);
invoker = DirectMethodHandle.make(method);
assert(checkInvoker(invoker));
basicInvoker = invoker;
return invoker;
}
static MemberName invokeBasicMethod(MethodType type) {
type = type.basicType();
String name = "invokeBasic";
// This next one is called from LambdaForm.NamedFunction.<init>.
/*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
assert(basicType == basicType.basicType());
try {
//Lookup.findVirtual(MethodHandle.class, name, type);
return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type);
return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
} catch (ReflectiveOperationException ex) {
throw newInternalError("JVM cannot find invoker for "+type, ex);
throw newInternalError("JVM cannot find invoker for "+basicType, ex);
}
}
......@@ -184,6 +184,7 @@ class Invokers {
vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
}
assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
maybeCompileToBytecode(vaInvoker);
spreadInvokers[leadingArgCount] = vaInvoker;
return vaInvoker;
}
......@@ -231,32 +232,38 @@ class Invokers {
return "Invokers"+targetType;
}
static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) {
LambdaForm lform;
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) {
lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
appendixResult[0] = mtype;
} else {
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
static MemberName methodHandleInvokeLinkerMethod(String name,
MethodType mtype,
Object[] appendixResult) {
int which;
switch (name) {
case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break;
case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break;
default: throw new InternalError("not invoker: "+name);
}
return lform.vmentry;
}
static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) {
LambdaForm lform;
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) {
lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
lform = invokeHandleForm(mtype, false, which);
appendixResult[0] = mtype;
prepareForGenericCall(mtype);
} else {
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
lform = invokeHandleForm(mtype, true, which);
}
return lform.vmentry;
}
private static LambdaForm invokeForm(MethodType mtype, boolean customized, int which) {
// argument count to account for trailing "appendix value" (typically the mtype)
private static final int MH_LINKER_ARG_APPENDED = 1;
/** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker.
* If !customized, caller is responsible for supplying, during adapter execution,
* a copy of the exact mtype. This is because the adapter might be generalized to
* a basic type.
* @param mtype the caller's method type (either basic or full-custom)
* @param customized whether to use a trailing appendix argument (to carry the mtype)
* @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker");
* 0x02 whether it is for invokeExact or generic invoke
*/
private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
boolean isCached;
if (!customized) {
mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
......@@ -301,41 +308,24 @@ class Invokers {
: Arrays.asList(mtype, customized, which, nameCursor, names.length);
if (MTYPE_ARG >= INARG_LIMIT) {
assert(names[MTYPE_ARG] == null);
names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
// else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
}
// Make the final call. If isGeneric, then prepend the result of type checking.
MethodType outCallType;
Object[] outArgs;
MethodType outCallType = mtype.basicType();
Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
if (!isGeneric) {
names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
// mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
outCallType = mtype;
} else if (customized) {
names[CHECK_TYPE] = new Name(NF_asType, names[CALL_MH], mtypeArg);
// mh.invokeGeneric(a*):R =>
// let mt=TYPEOF(a*:R), tmh=asType(mh, mt);
// tmh.invokeBasic(a*)
outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
outCallType = mtype;
} else {
names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
// mh.invokeGeneric(a*):R =>
// let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt);
// gamh.invokeBasic(mt, mh, a*)
final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2;
assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT);
outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
// prepend arguments:
System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
outArgs[PREPEND_GAMH] = names[CHECK_TYPE];
outArgs[PREPEND_MT] = mtypeArg;
outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class);
// mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
outArgs[0] = names[CHECK_TYPE];
}
names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs);
names[LINKER_CALL] = new Name(outCallType, outArgs);
lform = new LambdaForm(debugName, INARG_LIMIT, names);
if (isLinker)
lform.compileToBytecode(); // JVM needs a real methodOop
......@@ -343,7 +333,6 @@ class Invokers {
lform = mtype.form().setCachedLambdaForm(which, lform);
return lform;
}
private static final int GENERIC_INVOKER_SLOP = 2; // used elsewhere to avoid arity problems
/*non-public*/ static
WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
......@@ -362,47 +351,53 @@ class Invokers {
throw newWrongMethodTypeException(expected, actual);
}
/** Static definition of MethodHandle.invokeGeneric checking code. */
/** Static definition of MethodHandle.invokeGeneric checking code.
* Directly returns the type-adjusted MH to invoke, as follows:
* {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
*/
/*non-public*/ static
@ForceInline
Object checkGenericType(Object mhObj, Object expectedObj) {
MethodHandle mh = (MethodHandle) mhObj;
MethodType expected = (MethodType) expectedObj;
//MethodType actual = mh.type();
MethodHandle gamh = expected.form().genericInvoker;
if (gamh != null) return gamh;
return prepareForGenericCall(expected);
if (mh.type() == expected) return mh;
MethodHandle atc = mh.asTypeCache;
if (atc != null && atc.type() == expected) return atc;
return mh.asType(expected);
/* Maybe add more paths here. Possible optimizations:
* for (R)MH.invoke(a*),
* let MT0 = TYPEOF(a*:R), MT1 = MH.type
*
* if MT0==MT1 or MT1 can be safely called by MT0
* => MH.invokeBasic(a*)
* if MT1 can be safely called by MT0[R := Object]
* => MH.invokeBasic(a*) & checkcast(R)
* if MT1 can be safely called by MT0[* := Object]
* => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
* if a big adapter BA can be pulled out of (MT0,MT1)
* => BA.invokeBasic(MT0,MH,a*)
* if a local adapter LA can cached on static CS0 = new GICS(MT0)
* => CS0.LA.invokeBasic(MH,a*)
* else
* => MH.asType(MT0).invokeBasic(A*)
*/
}
/**
* Returns an adapter GA for invoking a MH with type adjustments.
* The MethodType of the generic invocation site is prepended to MH
* and its arguments as follows:
* {@code (R)MH.invoke(A*) => GA.invokeBasic(TYPEOF<A*,R>, MH, A*)}
*/
/*non-public*/ static MethodHandle prepareForGenericCall(MethodType mtype) {
// force any needed adapters to be preconstructed
MethodTypeForm form = mtype.form();
MethodHandle gamh = form.genericInvoker;
if (gamh != null) return gamh;
try {
// Trigger adapter creation.
gamh = InvokeGeneric.generalInvokerOf(form.erasedType);
form.genericInvoker = gamh;
return gamh;
} catch (Exception ex) {
throw newInternalError("Exception while resolving inexact invoke", ex);
}
static MemberName linkToCallSiteMethod(MethodType mtype) {
LambdaForm lform = callSiteForm(mtype, false);
return lform.vmentry;
}
static MemberName linkToCallSiteMethod(MethodType mtype) {
LambdaForm lform = callSiteForm(mtype);
static MemberName linkToTargetMethod(MethodType mtype) {
LambdaForm lform = callSiteForm(mtype, true);
return lform.vmentry;
}
private static LambdaForm callSiteForm(MethodType mtype) {
// skipCallSite is true if we are optimizing a ConstantCallSite
private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER);
final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
LambdaForm lform = mtype.form().cachedLambdaForm(which);
if (lform != null) return lform;
// exactInvokerForm (Object,Object)Object
// link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
......@@ -410,24 +405,26 @@ class Invokers {
final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
final int INARG_LIMIT = OUTARG_LIMIT + 1;
int nameCursor = OUTARG_LIMIT;
final int CSITE_ARG = nameCursor++; // the last in-argument
final int CALL_MH = nameCursor++; // result of getTarget
final int APPENDIX_ARG = nameCursor++; // the last in-argument
final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG;
final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget
final int LINKER_CALL = nameCursor++;
MethodType invokerFormType = mtype.appendParameterTypes(CallSite.class);
MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
assert(names.length == nameCursor);
assert(names[CSITE_ARG] != null);
names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
assert(names[APPENDIX_ARG] != null);
if (!skipCallSite)
names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
// (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
final int PREPEND_MH = 0, PREPEND_COUNT = 1;
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
// prepend MH argument:
System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
outArgs[PREPEND_MH] = names[CALL_MH];
names[LINKER_CALL] = new Name(invokeBasicMethod(mtype), outArgs);
lform = new LambdaForm("linkToCallSite", INARG_LIMIT, names);
names[LINKER_CALL] = new Name(mtype, outArgs);
lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
lform.compileToBytecode(); // JVM needs a real methodOop
lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform);
lform = mtype.form().setCachedLambdaForm(which, lform);
return lform;
}
......
......@@ -50,7 +50,7 @@ import java.util.Objects;
* The result of the lambda is defined as one of the names, often the last one.
* <p>
* Here is an approximate grammar:
* <pre>
* <blockquote><pre>{@code
* LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
* ArgName = "a" N ":" T
* TempName = "t" N ":" T "=" Function "(" Argument* ");"
......@@ -60,7 +60,7 @@ import java.util.Objects;
* NameRef = "a" N | "t" N
* N = (any whole number)
* T = "L" | "I" | "J" | "F" | "D" | "V"
* </pre>
* }</pre></blockquote>
* Names are numbered consecutively from left to right starting at zero.
* (The letters are merely a taste of syntax sugar.)
* Thus, the first temporary (if any) is always numbered N (where N=arity).
......@@ -69,7 +69,7 @@ import java.util.Objects;
* A lambda has a void result if and only if its result index is -1.
* If a temporary has the type "V", it cannot be the subject of a NameRef,
* even though possesses a number.
* Note that all reference types are erased to "L", which stands for {@code Object).
* Note that all reference types are erased to "L", which stands for {@code Object}.
* All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}.
* The other types stand for the usual primitive types.
* <p>
......@@ -89,7 +89,7 @@ import java.util.Objects;
* encoded by using temporary expressions which call type-transformed identity functions.
* <p>
* Examples:
* <pre>
* <blockquote><pre>{@code
* (a0:J)=>{ a0 }
* == identity(long)
* (a0:I)=>{ t1:V = System.out#println(a0); void }
......@@ -113,14 +113,14 @@ import java.util.Objects;
* (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
* t3:L = Class#cast(t2,a1); t3 }
* == invoker for identity method handle which performs cast
* </pre>
* }</pre></blockquote>
* <p>
* @author John Rose, JSR 292 EG
*/
class LambdaForm {
final int arity;
final int result;
final Name[] names;
@Stable final Name[] names;
final String debugName;
MemberName vmentry; // low-level behavior, or null if not yet prepared
private boolean isCompiled;
......@@ -457,7 +457,7 @@ class LambdaForm {
isCompiled = true;
return vmentry;
} catch (Error | Exception ex) {
throw newInternalError(this.toString(), ex);
throw newInternalError("compileToBytecode", ex);
}
}
......@@ -683,8 +683,9 @@ class LambdaForm {
*/
static void traceInterpreter(String event, Object obj, Object... args) {
if (!TRACE_INTERPRETER) return;
System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
if (TRACE_INTERPRETER) {
System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
}
}
static void traceInterpreter(String event, Object obj) {
traceInterpreter(event, obj, (Object[])null);
......@@ -971,8 +972,8 @@ class LambdaForm {
static class NamedFunction {
final MemberName member;
MethodHandle resolvedHandle;
MethodHandle invoker;
@Stable MethodHandle resolvedHandle;
@Stable MethodHandle invoker;
NamedFunction(MethodHandle resolvedHandle) {
this(resolvedHandle.internalMemberName(), resolvedHandle);
......@@ -982,6 +983,16 @@ class LambdaForm {
//resolvedHandle = eraseSubwordTypes(resolvedHandle);
this.resolvedHandle = resolvedHandle;
}
NamedFunction(MethodType basicInvokerType) {
assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
this.member = resolvedHandle.internalMemberName();
} else {
// necessary to pass BigArityTest
this.member = Invokers.invokeBasicMethod(basicInvokerType);
}
}
// The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
// Any LambdaForm containing such a member is not interpretable.
......@@ -1229,7 +1240,7 @@ class LambdaForm {
}
public String toString() {
if (member == null) return resolvedHandle.toString();
if (member == null) return String.valueOf(resolvedHandle);
return member.getDeclaringClass().getSimpleName()+"."+member.getName();
}
}
......@@ -1267,7 +1278,7 @@ class LambdaForm {
final char type;
private short index;
final NamedFunction function;
final Object[] arguments;
@Stable final Object[] arguments;
private Name(int index, char type, NamedFunction function, Object[] arguments) {
this.index = (short)index;
......@@ -1279,6 +1290,10 @@ class LambdaForm {
Name(MethodHandle function, Object... arguments) {
this(new NamedFunction(function), arguments);
}
Name(MethodType functionType, Object... arguments) {
this(new NamedFunction(functionType), arguments);
assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
}
Name(MemberName function, Object... arguments) {
this(new NamedFunction(function), arguments);
}
......@@ -1426,8 +1441,6 @@ class LambdaForm {
* Does this Name precede the given binding node in some canonical order?
* This predicate is used to order data bindings (via insertion sort)
* with some stability.
* @param binding
* @return
*/
boolean isSiblingBindingBefore(Name binding) {
assert(!binding.isParam());
......@@ -1622,4 +1635,12 @@ class LambdaForm {
*/
static { NamedFunction.initializeInvokers(); }
// The following hack is necessary in order to suppress TRACE_INTERPRETER
// during execution of the static initializes of this class.
// Turning on TRACE_INTERPRETER too early will cause
// stack overflows and other misbehavior during attempts to trace events
// that occur during LambdaForm.<clinit>.
// Therefore, do not move this line higher in this file, and do not remove.
private static final boolean TRACE_INTERPRETER = MethodHandleStatics.TRACE_INTERPRETER;
}
......@@ -70,13 +70,13 @@ import java.util.Objects;
* @author jrose
*/
/*non-public*/ final class MemberName implements Member, Cloneable {
private Class<?> clazz; // class in which the method is defined
private String name; // may be null if not yet materialized
private Object type; // may be null if not yet materialized
private int flags; // modifier bits; see reflect.Modifier
private Class<?> clazz; // class in which the method is defined
private String name; // may be null if not yet materialized
private Object type; // may be null if not yet materialized
private int flags; // modifier bits; see reflect.Modifier
//@Injected JVM_Method* vmtarget;
//@Injected int vmindex;
private Object resolution; // if null, this guy is resolved
private Object resolution; // if null, this guy is resolved
/** Return the declaring class of this member.
* In the case of a bare name and type, the declaring class will be null.
......@@ -98,7 +98,9 @@ import java.util.Objects;
public String getName() {
if (name == null) {
expandFromVM();
if (name == null) return null;
if (name == null) {
return null;
}
}
return name;
}
......@@ -119,28 +121,39 @@ import java.util.Objects;
public MethodType getMethodType() {
if (type == null) {
expandFromVM();
if (type == null) return null;
if (type == null) {
return null;
}
}
if (!isInvocable())
if (!isInvocable()) {
throw newIllegalArgumentException("not invocable, no method type");
if (type instanceof MethodType) {
return (MethodType) type;
}
if (type instanceof String) {
String sig = (String) type;
MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
this.type = res;
return res;
{
// Get a snapshot of type which doesn't get changed by racing threads.
final Object type = this.type;
if (type instanceof MethodType) {
return (MethodType) type;
}
}
if (type instanceof Object[]) {
Object[] typeInfo = (Object[]) type;
Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
Class<?> rtype = (Class<?>) typeInfo[0];
MethodType res = MethodType.methodType(rtype, ptypes);
this.type = res;
return res;
// type is not a MethodType yet. Convert it thread-safely.
synchronized (this) {
if (type instanceof String) {
String sig = (String) type;
MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
type = res;
} else if (type instanceof Object[]) {
Object[] typeInfo = (Object[]) type;
Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
Class<?> rtype = (Class<?>) typeInfo[0];
MethodType res = MethodType.methodType(rtype, ptypes);
type = res;
}
// Make sure type is a MethodType for racing threads.
assert type instanceof MethodType : "bad method type " + type;
}
throw new InternalError("bad method type "+type);
return (MethodType) type;
}
/** Return the actual type under which this method or constructor must be invoked.
......@@ -173,21 +186,34 @@ import java.util.Objects;
public Class<?> getFieldType() {
if (type == null) {
expandFromVM();
if (type == null) return null;
if (type == null) {
return null;
}
}
if (isInvocable())
if (isInvocable()) {
throw newIllegalArgumentException("not a field or nested class, no simple type");
if (type instanceof Class<?>) {
return (Class<?>) type;
}
if (type instanceof String) {
String sig = (String) type;
MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
Class<?> res = mtype.returnType();
this.type = res;
return res;
{
// Get a snapshot of type which doesn't get changed by racing threads.
final Object type = this.type;
if (type instanceof Class<?>) {
return (Class<?>) type;
}
}
throw new InternalError("bad field type "+type);
// type is not a Class yet. Convert it thread-safely.
synchronized (this) {
if (type instanceof String) {
String sig = (String) type;
MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
Class<?> res = mtype.returnType();
type = res;
}
// Make sure type is a Class for racing threads.
assert type instanceof Class<?> : "bad field type " + type;
}
return (Class<?>) type;
}
/** Utility method to produce either the method type or field type of this member. */
......@@ -201,10 +227,10 @@ import java.util.Objects;
public String getSignature() {
if (type == null) {
expandFromVM();
if (type == null) return null;
if (type == null) {
return null;
}
}
if (type instanceof String)
return (String) type;
if (isInvocable())
return BytecodeDescriptor.unparse(getMethodType());
else
......@@ -463,10 +489,17 @@ import java.util.Objects;
//assert(referenceKindIsConsistent()); // do this after resolution
}
/**
* Calls down to the VM to fill in the fields. This method is
* synchronized to avoid racing calls.
*/
private void expandFromVM() {
if (!isResolved()) return;
if (type instanceof Object[])
type = null; // don't saddle JVM w/ typeInfo
if (type != null) {
return;
}
if (!isResolved()) {
return;
}
MethodHandleNatives.expand(this);
}
......@@ -523,6 +556,9 @@ import java.util.Objects;
}
throw new IllegalArgumentException(this.toString());
}
/** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind.
* In that case it must already be REF_invokeSpecial.
*/
public MemberName asConstructor() {
switch (getReferenceKind()) {
case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
......@@ -530,6 +566,32 @@ import java.util.Objects;
}
throw new IllegalArgumentException(this.toString());
}
/** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind
* REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface.
* The end result is to get a fully virtualized version of the MN.
* (Note that resolving in the JVM will sometimes devirtualize, changing
* REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface
* in some corner cases to either of the previous two; this transform
* undoes that change under the assumption that it occurred.)
*/
public MemberName asNormalOriginal() {
byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
byte refKind = getReferenceKind();
byte newRefKind = refKind;
MemberName result = this;
switch (refKind) {
case REF_invokeInterface:
case REF_invokeVirtual:
case REF_invokeSpecial:
newRefKind = normalVirtual;
break;
}
if (newRefKind == refKind)
return this;
result = clone().changeReferenceKind(newRefKind, refKind);
assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
return result;
}
/** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
@SuppressWarnings("LeakingThisInConstructor")
public MemberName(Constructor<?> ctor) {
......@@ -627,7 +689,7 @@ import java.util.Objects;
@Override
public int hashCode() {
return Objects.hash(clazz, flags, name, getType());
return Objects.hash(clazz, getReferenceKind(), name, getType());
}
@Override
public boolean equals(Object that) {
......@@ -643,13 +705,14 @@ import java.util.Objects;
if (this == that) return true;
if (that == null) return false;
return this.clazz == that.clazz
&& this.flags == that.flags
&& this.getReferenceKind() == that.getReferenceKind()
&& Objects.equals(this.name, that.name)
&& Objects.equals(this.getType(), that.getType());
}
// Construction from symbolic parts, for queries:
/** Create a field or type name from the given components: Declaring class, name, type, reference kind.
/** Create a field or type name from the given components:
* Declaring class, name, type, reference kind.
* The declaring class may be supplied as null if this is to be a bare name and type.
* The resulting name will in an unresolved state.
*/
......@@ -673,21 +736,34 @@ import java.util.Objects;
* The resulting name will in an unresolved state.
*/
public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
@SuppressWarnings("LocalVariableHidesMemberVariable")
int flags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
init(defClass, name, type, flagsMods(flags, 0, refKind));
int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
init(defClass, name, type, flagsMods(initFlags, 0, refKind));
initResolved(false);
}
/** Create a method, constructor, or field name from the given components:
* Reference kind, declaring class, name, type.
*/
public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
int kindFlags;
if (MethodHandleNatives.refKindIsField(refKind)) {
kindFlags = IS_FIELD;
if (!(type instanceof Class))
throw newIllegalArgumentException("not a field type");
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
kindFlags = IS_METHOD;
if (!(type instanceof MethodType))
throw newIllegalArgumentException("not a method type");
} else if (refKind == REF_newInvokeSpecial) {
kindFlags = IS_CONSTRUCTOR;
if (!(type instanceof MethodType) ||
!CONSTRUCTOR_NAME.equals(name))
throw newIllegalArgumentException("not a constructor type or name");
} else {
throw newIllegalArgumentException("bad reference kind "+refKind);
}
init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
initResolved(false);
}
// /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
// * It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
// * The declaring class may be supplied as null if this is to be a bare name and type.
// * The modifier flags default to zero.
// * The resulting name will in an unresolved state.
// */
// public MemberName(Class<?> defClass, String name, MethodType type, Void unused) {
// this(defClass, name, type, REF_NONE);
// }
/** Query whether this member name is resolved to a non-static, non-final method.
*/
public boolean hasReceiverTypeDispatch() {
......
......@@ -292,7 +292,7 @@ mh.invokeExact(System.out, "Hello, world.");
* generates a single invokevirtual instruction with
* the symbolic type descriptor indicated in the following comment.
* In these examples, the helper method {@code assertEquals} is assumed to
* be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals }
* be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals}
* on its arguments, and asserts that the result is true.
*
* <h1>Exceptions</h1>
......@@ -392,7 +392,7 @@ mh.invokeExact(System.out, "Hello, world.");
* Java types.
* <ul>
* <li>Method types range over all possible arities,
* from no arguments to up to 255 of arguments (a limit imposed by the JVM).
* from no arguments to up to the <a href="MethodHandle.html#maxarity">maximum number</a> of allowed arguments.
* Generics are not variadic, and so cannot represent this.</li>
* <li>Method types can specify arguments of primitive types,
* which Java generic types cannot range over.</li>
......@@ -402,6 +402,22 @@ mh.invokeExact(System.out, "Hello, world.");
* genericity with a Java type parameter.</li>
* </ul>
*
* <h1><a name="maxarity"></a>Arity limits</h1>
* The JVM imposes on all methods and constructors of any kind an absolute
* limit of 255 stacked arguments. This limit can appear more restrictive
* in certain cases:
* <ul>
* <li>A {@code long} or {@code double} argument counts (for purposes of arity limits) as two argument slots.
* <li>A non-static method consumes an extra argument for the object on which the method is called.
* <li>A constructor consumes an extra argument for the object which is being constructed.
* <li>Since a method handle&rsquo;s {@code invoke} method (or other signature-polymorphic method) is non-virtual,
* it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object.
* </ul>
* These limits imply that certain method handles cannot be created, solely because of the JVM limit on stacked arguments.
* For example, if a static JVM method accepts exactly 255 arguments, a method handle cannot be created for it.
* Attempts to create method handles with impossible method types lead to an {@link IllegalArgumentException}.
* In particular, a method handle&rsquo;s type must not have an arity of the exact maximum 255.
*
* @see MethodType
* @see MethodHandles
* @author John Rose, JSR 292 EG
......@@ -420,6 +436,8 @@ public abstract class MethodHandle {
private final MethodType type;
/*private*/ final LambdaForm form;
// form is not private so that invokers can easily fetch it
/*private*/ MethodHandle asTypeCache;
// asTypeCache is not private so that invokers can easily fetch it
/**
* Reports the type of this method handle.
......@@ -557,10 +575,10 @@ public abstract class MethodHandle {
/*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
/**
* Performs a variable arity invocation, passing the arguments in the given array
* Performs a variable arity invocation, passing the arguments in the given list
* to the method handle, as if via an inexact {@link #invoke invoke} from a call site
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
* of the argument list.
* <p>
* Specifically, execution proceeds as if by the following steps,
* although the methods are not guaranteed to be called if the JVM
......@@ -590,10 +608,10 @@ public abstract class MethodHandle {
* or forced to null if the return type is void.
* <p>
* This call is equivalent to the following code:
* <p><blockquote><pre>
* <p><blockquote><pre>{@code
* MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
* Object result = invoker.invokeExact(this, arguments);
* </pre></blockquote>
* }</pre></blockquote>
* <p>
* Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
* {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
......@@ -626,7 +644,7 @@ public abstract class MethodHandle {
* <p>
* This method is also equivalent to the following code:
* <p><blockquote><pre>
* {@link #invokeWithArguments(Object...) invokeWithArguments}(arguments.toArray())
* {@link #invokeWithArguments(Object...) invokeWithArguments}{@code(arguments.toArray())}
* </pre></blockquote>
*
* @param arguments the arguments to pass to the target
......@@ -739,10 +757,24 @@ public abstract class MethodHandle {
* @see MethodHandles#explicitCastArguments
*/
public MethodHandle asType(MethodType newType) {
if (!type.isConvertibleTo(newType)) {
throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
// Fast path alternative to a heavyweight {@code asType} call.
// Return 'this' if the conversion will be a no-op.
if (newType == type) {
return this;
}
// Return 'this.asTypeCache' if the conversion is already memoized.
MethodHandle atc = asTypeCache;
if (atc != null && newType == atc.type) {
return atc;
}
return convertArguments(newType);
return asTypeUncached(newType);
}
/** Override this to change asType behavior. */
/*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
if (!type.isConvertibleTo(newType))
throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
return asTypeCache = convertArguments(newType);
}
/**
......@@ -772,6 +804,10 @@ public abstract class MethodHandle {
* to the target method handle.
* (The array may also be null when zero elements are required.)
* <p>
* If, when the adapter is called, the supplied array argument does
* not have the correct number of elements, the adapter will throw
* an {@link IllegalArgumentException} instead of invoking the target.
* <p>
* Here are some simple examples of array-spreading method handles:
* <blockquote><pre>{@code
MethodHandle equals = publicLookup()
......@@ -782,6 +818,12 @@ assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
// try to spread from anything but a 2-array:
for (int n = 0; n <= 10; n++) {
Object[] badArityArgs = (n == 2 ? null : new Object[n]);
try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
catch (IllegalArgumentException ex) { } // OK
}
// spread both arguments from a String array:
MethodHandle eq2s = equals.asSpreader(String[].class, 2);
assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
......@@ -815,10 +857,12 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
* @return a new method handle which spreads its final array argument,
* before calling the original method handle
* @throws NullPointerException if {@code arrayType} is a null reference
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* @throws IllegalArgumentException if target does not have at least
* @throws IllegalArgumentException if {@code arrayType} is not an array type,
* or if target does not have at least
* {@code arrayLength} parameter types,
* or if {@code arrayLength} is negative
* or if {@code arrayLength} is negative,
* or if the resulting method handle's type would have
* <a href="MethodHandle.html#maxarity">too many parameters</a>
* @throws WrongMethodTypeException if the implied {@code asType} call fails
* @see #asCollector
*/
......@@ -931,7 +975,9 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
* @throws NullPointerException if {@code arrayType} is a null reference
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* or {@code arrayType} is not assignable to this method handle's trailing parameter type,
* or {@code arrayLength} is not a legal array size
* or {@code arrayLength} is not a legal array size,
* or the resulting method handle's type would have
* <a href="MethodHandle.html#maxarity">too many parameters</a>
* @throws WrongMethodTypeException if the implied {@code asType} call fails
* @see #asSpreader
* @see #asVarargsCollector
......@@ -1226,9 +1272,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
* starting with the string {@code "MethodHandle"} and
* ending with the string representation of the method handle's type.
* In other words, this method returns a string equal to the value of:
* <blockquote><pre>
* <blockquote><pre>{@code
* "MethodHandle" + type().toString()
* </pre></blockquote>
* }</pre></blockquote>
* <p>
* (<em>Note:</em> Future releases of this API may add further information
* to the string representation.
......@@ -1284,6 +1330,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
return null; // DMH returns DMH.member
}
/*non-public*/
Class<?> internalCallerClass() {
return null; // caller-bound MH for @CallerSensitive method returns caller
}
/*non-public*/
MethodHandle withInternalMemberName(MemberName member) {
if (member != null) {
......@@ -1434,7 +1485,6 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
* Threads may continue running the old form indefinitely,
* but it is likely that the new one will be preferred for new executions.
* Use with discretion.
* @param newForm
*/
/*non-public*/
void updateForm(LambdaForm newForm) {
......
......@@ -314,13 +314,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static class AsVarargsCollector extends MethodHandle {
private final MethodHandle target;
private final Class<?> arrayType;
private MethodHandle cache;
private /*@Stable*/ MethodHandle asCollectorCache;
AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
super(type, reinvokerForm(target));
this.target = target;
this.arrayType = arrayType;
this.cache = target.asCollector(arrayType, 0);
this.asCollectorCache = target.asCollector(arrayType, 0);
}
@Override MethodHandle reinvokerTarget() { return target; }
......@@ -336,18 +336,19 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
@Override
public MethodHandle asType(MethodType newType) {
public MethodHandle asTypeUncached(MethodType newType) {
MethodType type = this.type();
int collectArg = type.parameterCount() - 1;
int newArity = newType.parameterCount();
if (newArity == collectArg+1 &&
type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
// if arity and trailing parameter are compatible, do normal thing
return asFixedArity().asType(newType);
return asTypeCache = asFixedArity().asType(newType);
}
// check cache
if (cache.type().parameterCount() == newArity)
return cache.asType(newType);
MethodHandle acc = asCollectorCache;
if (acc != null && acc.type().parameterCount() == newArity)
return asTypeCache = acc.asType(newType);
// build and cache a collector
int arrayLength = newArity - collectArg;
MethodHandle collector;
......@@ -357,8 +358,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} catch (IllegalArgumentException ex) {
throw new WrongMethodTypeException("cannot build collector", ex);
}
cache = collector;
return collector.asType(newType);
asCollectorCache = collector;
return asTypeCache = collector.asType(newType);
}
@Override
......@@ -380,6 +381,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MemberName internalMemberName() {
return asFixedArity().internalMemberName();
}
@Override
Class<?> internalCallerClass() {
return asFixedArity().internalCallerClass();
}
/*non-public*/
@Override
......@@ -435,7 +440,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// Spread the array.
MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
Name array = names[argIndex];
names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
for (int j = 0; j < spreadArgCount; i++, j++) {
indexes[i] = nameCursor;
names[nameCursor++] = new Name(aload, array, j);
......@@ -459,14 +464,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
static void checkSpreadArgument(Object av, int n) {
// FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE
// but the actual exception raised by an arity mismatch should be WMTE
final boolean RAISE_RANDOM_EXCEPTIONS = true; // FIXME: delete in JSR 292 M1
if (av == null) {
if (n == 0) return;
int len;
if (RAISE_RANDOM_EXCEPTIONS)
len = ((Object[])av).length; // throw NPE; but delete this after tests are fixed
} else if (av instanceof Object[]) {
int len = ((Object[])av).length;
if (len == n) return;
......@@ -475,19 +474,23 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if (len == n) return;
}
// fall through to error:
if (RAISE_RANDOM_EXCEPTIONS)
throw newIllegalArgumentException("Array is not of length "+n);
throw new WrongMethodTypeException("Array is not of length "+n);
throw newIllegalArgumentException("array is not of length "+n);
}
private static final NamedFunction NF_checkSpreadArgument;
static {
try {
NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
NF_checkSpreadArgument.resolve();
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
/**
* Pre-initialized NamedFunctions for bootstrapping purposes.
* Factored in an inner class to delay initialization until first usage.
*/
private static class Lazy {
static final NamedFunction NF_checkSpreadArgument;
static {
try {
NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
NF_checkSpreadArgument.resolve();
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
}
......@@ -832,7 +835,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle vamh = prepareForInvoker(mh);
// Cache the result of makeInjectedInvoker once per argument class.
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
}
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
......@@ -887,10 +890,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
// Undo the adapter effect of prepareForInvoker:
private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
MemberName member,
Class<?> hostClass) {
MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
mh = mh.asType(type);
mh = mh.withInternalMemberName(member);
mh = new WrappedMember(mh, type, member, hostClass);
return mh;
}
......@@ -959,11 +964,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static class WrappedMember extends MethodHandle {
private final MethodHandle target;
private final MemberName member;
private final Class<?> callerClass;
private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
super(type, reinvokerForm(target));
this.target = target;
this.member = member;
this.callerClass = callerClass;
}
@Override
......@@ -971,23 +978,33 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return target;
}
@Override
public MethodHandle asTypeUncached(MethodType newType) {
// This MH is an alias for target, except for the MemberName
// Drop the MemberName if there is any conversion.
return asTypeCache = target.asType(newType);
}
@Override
MemberName internalMemberName() {
return member;
}
@Override
Class<?> internalCallerClass() {
return callerClass;
}
@Override
boolean isInvokeSpecial() {
return target.isInvokeSpecial();
}
@Override
MethodHandle viewAsType(MethodType newType) {
return new WrappedMember(target, newType, member);
return new WrappedMember(target, newType, member, callerClass);
}
}
static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
if (member.equals(target.internalMemberName()))
return target;
return new WrappedMember(target, target.type(), member);
return new WrappedMember(target, target.type(), member, null);
}
}
......@@ -32,9 +32,10 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts.
* A symbolic reference obtained by cracking a direct method handle
* into its consitutent symbolic parts.
* To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
* <p>
* <h1><a name="directmh"></a>Direct Method Handles</h1>
* A <em>direct method handle</em> represents a method, constructor, or field without
* any intervening argument bindings or other transformations.
* The method, constructor, or field referred to by a direct method handle is called
......@@ -56,11 +57,25 @@ import static java.lang.invoke.MethodHandleStatics.*;
* or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
* to convert a {@link Field} into a method handle.
* </ul>
* In all of these cases, it is possible to crack the resulting direct method handle
*
* <h1>Restrictions on Cracking</h1>
* Given a suitable {@code Lookup} object, it is possible to crack any direct method handle
* to recover a symbolic reference for the underlying method, constructor, or field.
* Cracking must be done via a {@code Lookup} object equivalent to that which created
* the target method handle, or which has enough access permissions to recreate
* an equivalent method handle.
* <p>
* If the underlying method is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>,
* the direct method handle will have been "bound" to a particular caller class, the
* {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
* of the lookup object used to create it.
* Cracking this method handle with a different lookup class will fail
* even if the underlying method is public (like {@code Class.forName}).
* <p>
* The requirement of lookup object matching provides a "fast fail" behavior
* for programs which may otherwise trust erroneous revelation of a method
* handle with symbolic information (or caller binding) from an unexpected scope.
* Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
*
* <h1><a name="refkinds"></a>Reference kinds</h1>
* The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
......@@ -190,7 +205,7 @@ interface MethodHandleInfo {
* @return the Java language modifiers for underlying member,
* or -1 if the member cannot be accessed
* @see Modifier
* @see reflectAs
* @see #reflectAs
*/
public int getModifiers();
......
/*
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 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
......@@ -233,20 +233,19 @@ class MethodHandleNatives {
}
static String refKindName(byte refKind) {
assert(refKindIsValid(refKind));
return REFERENCE_KIND_NAME[refKind];
switch (refKind) {
case REF_getField: return "getField";
case REF_getStatic: return "getStatic";
case REF_putField: return "putField";
case REF_putStatic: return "putStatic";
case REF_invokeVirtual: return "invokeVirtual";
case REF_invokeStatic: return "invokeStatic";
case REF_invokeSpecial: return "invokeSpecial";
case REF_newInvokeSpecial: return "newInvokeSpecial";
case REF_invokeInterface: return "invokeInterface";
default: return "REF_???";
}
}
private static String[] REFERENCE_KIND_NAME = {
null,
"getField",
"getStatic",
"putField",
"putStatic",
"invokeVirtual",
"invokeStatic",
"invokeSpecial",
"newInvokeSpecial",
"invokeInterface"
};
private static native int getNamedCon(int which, Object[] name);
static boolean verifyConstants() {
......@@ -294,12 +293,18 @@ class MethodHandleNatives {
Class<?> caller = (Class<?>)callerObj;
String name = nameObj.toString().intern();
MethodType type = (MethodType)typeObj;
appendixResult[0] = CallSite.makeSite(bootstrapMethod,
CallSite callSite = CallSite.makeSite(bootstrapMethod,
name,
type,
staticArguments,
caller);
return Invokers.linkToCallSiteMethod(type);
if (callSite instanceof ConstantCallSite) {
appendixResult[0] = callSite.dynamicInvoker();
return Invokers.linkToTargetMethod(type);
} else {
appendixResult[0] = callSite;
return Invokers.linkToCallSiteMethod(type);
}
}
/**
......@@ -388,12 +393,7 @@ class MethodHandleNatives {
Object[] appendixResult) {
try {
if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
switch (name) {
case "invoke":
return Invokers.genericInvokerMethod(fixMethodType(callerClass, type), appendixResult);
case "invokeExact":
return Invokers.exactInvokerMethod(fixMethodType(callerClass, type), appendixResult);
}
return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
}
} catch (Throwable ex) {
if (ex instanceof LinkageError)
......@@ -440,13 +440,33 @@ class MethodHandleNatives {
Lookup lookup = IMPL_LOOKUP.in(callerClass);
assert(refKindIsValid(refKind));
return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type);
} catch (IllegalAccessException ex) {
Error err = new IllegalAccessError(ex.getMessage());
throw initCauseFrom(err, ex);
} catch (NoSuchMethodException ex) {
Error err = new NoSuchMethodError(ex.getMessage());
throw initCauseFrom(err, ex);
} catch (NoSuchFieldException ex) {
Error err = new NoSuchFieldError(ex.getMessage());
throw initCauseFrom(err, ex);
} catch (ReflectiveOperationException ex) {
Error err = new IncompatibleClassChangeError();
err.initCause(ex);
throw err;
throw initCauseFrom(err, ex);
}
}
/**
* Use best possible cause for err.initCause(), substituting the
* cause for err itself if the cause has the same (or better) type.
*/
static private Error initCauseFrom(Error err, Exception ex) {
Throwable th = ex.getCause();
if (err.getClass().isInstance(th))
return (Error) th;
err.initCause(th == null ? ex : th);
return err;
}
/**
* Is this method a caller-sensitive method?
* I.e., does it call Reflection.getCallerClass or a similer method
......
......@@ -107,6 +107,11 @@ public class MethodHandleProxies {
* such as abstract classes with single abstract methods.
* Future versions of this API may also equip wrapper instances
* with one or more additional public "marker" interfaces.
* <p>
* If a security manager is installed, this method is caller sensitive.
* During any invocation of the target method handle via the returned wrapper,
* the original creator of the wrapper (the caller) will be visible
* to context checks requested by the security manager.
*
* @param <T> the desired type of the wrapper, a single-method interface
* @param intfc a class object representing {@code T}
......
......@@ -77,7 +77,8 @@ import sun.invoke.util.VerifyType;
* A method type may be loaded by an {@code ldc} instruction which refers
* to a suitable {@code CONSTANT_MethodType} constant pool entry.
* The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
* For more details, see the <a href="package-summary.html#mtcon">package summary</a>.
* (For full details on method type constants,
* see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
* <p>
* When the JVM materializes a {@code MethodType} from a descriptor string,
* all classes named in the descriptor must be accessible, and will be loaded.
......@@ -94,9 +95,9 @@ class MethodType implements java.io.Serializable {
private final Class<?>[] ptypes;
// The remaining fields are caches of various sorts:
private MethodTypeForm form; // erased form, plus cached data about primitives
private MethodType wrapAlt; // alternative wrapped/unwrapped version
private Invokers invokers; // cache of handy higher-order adapters
private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
private @Stable Invokers invokers; // cache of handy higher-order adapters
/**
* Check the given parameters for validity and store them into the final fields.
......@@ -940,10 +941,10 @@ class MethodType implements java.io.Serializable {
* Instead, the return type and parameter type arrays are written directly
* from the {@code writeObject} method, using two calls to {@code s.writeObject}
* as follows:
* <blockquote><pre>
* <blockquote><pre>{@code
s.writeObject(this.returnType());
s.writeObject(this.parameterArray());
* </pre></blockquote>
* }</pre></blockquote>
* <p>
* The deserialized field values are checked as if they were
* provided to the factory method {@link #methodType(Class,Class[]) methodType}.
......
......@@ -28,6 +28,7 @@ package java.lang.invoke;
import sun.invoke.util.Wrapper;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Shared information for a group of method types, which differ
......@@ -51,12 +52,13 @@ final class MethodTypeForm {
final MethodType basicType; // the canonical erasure, with primitives simplified
// Cached adapter information:
/*lazy*/ MethodHandle genericInvoker; // JVM hook for inexact invoke
/*lazy*/ MethodHandle basicInvoker; // cached instance of MH.invokeBasic
/*lazy*/ MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
@Stable String typeString; // argument type signature characters
@Stable MethodHandle genericInvoker; // JVM hook for inexact invoke
@Stable MethodHandle basicInvoker; // cached instance of MH.invokeBasic
@Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
// Cached lambda form information, for basic types only:
final LambdaForm[] lambdaForms;
final @Stable LambdaForm[] lambdaForms;
// Indexes into lambdaForms:
static final int
LF_INVVIRTUAL = 0, // DMH invokeVirtual
......@@ -73,7 +75,8 @@ final class MethodTypeForm {
LF_GEN_LINKER = 11,
LF_GEN_INVOKER = 12,
LF_CS_LINKER = 13, // linkToCallSite_CS
LF_LIMIT = 14;
LF_MH_LINKER = 14, // linkToCallSite_MH
LF_LIMIT = 15;
public MethodType erasedType() {
return erasedType;
......@@ -96,11 +99,24 @@ final class MethodTypeForm {
assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType; // primitives must be flattened also
MethodHandle invoker = basicInvoker;
if (invoker != null) return invoker;
invoker = basicType.invokers().makeBasicInvoker();
invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
basicInvoker = invoker;
return invoker;
}
// This next one is called from LambdaForm.NamedFunction.<init>.
/*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
assert(basicType == basicType.basicType());
try {
// Do approximately the same as this public API call:
// Lookup.findVirtual(MethodHandle.class, name, type);
// But bypass access and corner case checks, since we know exactly what we need.
return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
} catch (ReflectiveOperationException ex) {
throw newInternalError("JVM cannot find invoker for "+basicType, ex);
}
}
/**
* Build an MTF for a given type, which must have all references erased to Object.
* This MTF will stand for that type and all un-erased variations.
......
......@@ -38,7 +38,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
* <!-- JavaDocExamplesTest.testMutableCallSite -->
* <blockquote><pre>
* <blockquote><pre>{@code
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str1 = MethodType.methodType(String.class);
......@@ -50,10 +50,10 @@ assertEquals("ROCKY", (String) worker1.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Fred"));
assertEquals("FRED", (String) worker1.invokeExact());
// (mutation can be continued indefinitely)
* </pre></blockquote>
* }</pre></blockquote>
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
* <blockquote><pre>{@code
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
......@@ -63,7 +63,7 @@ assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
assertEquals("WILMA", (String) worker1.invokeExact());
assertEquals("Wilma, dear?", (String) worker2.invokeExact());
* </pre></blockquote>
* }</pre></blockquote>
* <p>
* <em>Non-synchronization of target values:</em>
* A write to a mutable call site's target does not force other threads
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.invoke;
import java.lang.annotation.*;
/**
* A field may be annotated as stable if all of its component variables
* changes value at most once.
* A field's value counts as its component value.
* If the field is typed as an array, then all the non-null components
* of the array, of depth up to the rank of the field's array type,
* also count as component values.
* By extension, any variable (either array or field) which has annotated
* as stable is called a stable variable, and its non-null or non-zero
* value is called a stable value.
* <p>
* Since all fields begin with a default value of null for references
* (resp., zero for primitives), it follows that this annotation indicates
* that the first non-null (resp., non-zero) value stored in the field
* will never be changed.
* <p>
* If the field is not of an array type, there are no array elements,
* then the value indicated as stable is simply the value of the field.
* If the dynamic type of the field value is an array but the static type
* is not, the components of the array are <em>not</em> regarded as stable.
* <p>
* If the field is an array type, then both the field value and
* all the components of the field value (if the field value is non-null)
* are indicated to be stable.
* If the field type is an array type with rank {@code N &gt; 1},
* then each component of the field value (if the field value is non-null),
* is regarded as a stable array of rank {@code N-1}.
* <p>
* Fields which are declared {@code final} may also be annotated as stable.
* Since final fields already behave as stable values, such an annotation
* indicates no additional information, unless the type of the field is
* an array type.
* <p>
* It is (currently) undefined what happens if a field annotated as stable
* is given a third value. In practice, if the JVM relies on this annotation
* to promote a field reference to a constant, it may be that the Java memory
* model would appear to be broken, if such a constant (the second value of the field)
* is used as the value of the field even after the field value has changed.
*/
/* package-private */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Stable {
}
......@@ -55,7 +55,7 @@ package java.lang.invoke;
* At that point {@code guardWithTest} may ignore {@code T} and return {@code F}.
* <p>
* Here is an example of a switch point in action:
* <blockquote><pre>
* <blockquote><pre>{@code
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
SwitchPoint spt = new SwitchPoint();
......@@ -68,7 +68,7 @@ assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(spt.hasBeenInvalidated());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote>
* }</pre></blockquote>
* <p style="font-size:smaller;">
* <em>Discussion:</em>
* Switch points are useful without subclassing. They may also be subclassed.
......@@ -82,7 +82,7 @@ assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* <em>Implementation Note:</em>
* A switch point behaves as if implemented on top of {@link MutableCallSite},
* approximately as follows:
* <blockquote><pre>
* <blockquote><pre>{@code
public class SwitchPoint {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
......@@ -106,7 +106,7 @@ public class SwitchPoint {
MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
}
}
* </pre></blockquote>
* }</pre></blockquote>
* @author Remi Forax, JSR 292 EG
*/
public class SwitchPoint {
......
......@@ -27,17 +27,18 @@ package java.lang.reflect;
/**
* AnnotatedArrayType represents the use of an array type, whose component
* type may itself represent the annotated use of a type.
* {@code AnnotatedArrayType} represents the potentially annotated use of an
* array type, whose component type may itself represent the annotated use of a
* type.
*
* @since 1.8
*/
public interface AnnotatedArrayType extends AnnotatedType {
/**
* Returns the annotated generic component type of this array type.
* Returns the potentially annotated generic component type of this array type.
*
* @return the annotated generic component type of this array type
* @return the potentially annotated generic component type of this array type
*/
AnnotatedType getAnnotatedGenericComponentType();
}
......@@ -26,17 +26,18 @@
package java.lang.reflect;
/**
* AnnotatedParameterizedType represents the use of a parameterized type,
* whose type arguments may themselves represent annotated uses of types.
* {@code AnnotatedParameterizedType} represents the potentially annotated use
* of a parameterized type, whose type arguments may themselves represent
* annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedParameterizedType extends AnnotatedType {
/**
* Returns the annotated actual type arguments of this parameterized type.
* Returns the potentially annotated actual type arguments of this parameterized type.
*
* @return the annotated actual type arguments of this parameterized type
* @return the potentially annotated actual type arguments of this parameterized type
*/
AnnotatedType[] getAnnotatedActualTypeArguments();
}
......@@ -26,10 +26,10 @@
package java.lang.reflect;
/**
* AnnotatedType represents the annotated use of a type in the program
* currently running in this VM. The use may be of any type in the Java
* programming language, including an array type, a parameterized type, a type
* variable, or a wildcard type.
* {@code AnnotatedType} represents the potentially annotated use of a type in
* the program currently running in this VM. The use may be of any type in the
* Java programming language, including an array type, a parameterized type, a
* type variable, or a wildcard type.
*
* @since 1.8
*/
......
......@@ -26,18 +26,18 @@
package java.lang.reflect;
/**
* AnnotatedTypeVariable represents the use of a type variable, whose
* declaration may have bounds which themselves represent annotated uses of
* types.
* {@code AnnotatedTypeVariable} represents the potentially annotated use of a
* type variable, whose declaration may have bounds which themselves represent
* annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedTypeVariable extends AnnotatedType {
/**
* Returns the annotated bounds of this type variable.
* Returns the potentially annotated bounds of this type variable.
*
* @return the annotated bounds of this type variable
* @return the potentially annotated bounds of this type variable
*/
AnnotatedType[] getAnnotatedBounds();
}
......@@ -26,24 +26,25 @@
package java.lang.reflect;
/**
* AnnotatedWildcardType represents the use of a wildcard type argument, whose
* upper or lower bounds may themselves represent annotated uses of types.
* {@code AnnotatedWildcardType} represents the potentially annotated use of a
* wildcard type argument, whose upper or lower bounds may themselves represent
* annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedWildcardType extends AnnotatedType {
/**
* Returns the annotated lower bounds of this wildcard type.
* Returns the potentially annotated lower bounds of this wildcard type.
*
* @return the annotated lower bounds of this wildcard type
* @return the potentially annotated lower bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedLowerBounds();
/**
* Returns the annotated upper bounds of this wildcard type.
* Returns the potentially annotated upper bounds of this wildcard type.
*
* @return the annotated upper bounds of this wildcard type
* @return the potentially annotated upper bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedUpperBounds();
}
......@@ -67,8 +67,6 @@ public final class Constructor<T> extends Executable {
private transient ConstructorRepository genericInfo;
private byte[] annotations;
private byte[] parameterAnnotations;
// This is set by the vm at Constructor creation
private byte[] typeAnnotations;
// Generics infrastructure
// Accessor for factory
......@@ -141,8 +139,6 @@ public final class Constructor<T> extends Executable {
res.root = this;
// Might as well eagerly propagate this if already present
res.constructorAccessor = constructorAccessor;
res.typeAnnotations = typeAnnotations;
return res;
}
......@@ -155,10 +151,6 @@ public final class Constructor<T> extends Executable {
byte[] getAnnotationBytes() {
return annotations;
}
@Override
byte[] getTypeAnnotationBytes() {
return typeAnnotations;
}
/**
* {@inheritDoc}
......
......@@ -51,7 +51,6 @@ public abstract class Executable extends AccessibleObject
* Accessor method to allow code sharing
*/
abstract byte[] getAnnotationBytes();
abstract byte[] getTypeAnnotationBytes();
/**
* Does the Executable have generic information.
......@@ -287,12 +286,14 @@ public abstract class Executable extends AccessibleObject
* this object. Returns an array of length 0 if the executable
* has no parameters.
*
* The parameters of the underlying executable do not necessarily
* <p>The parameters of the underlying executable do not necessarily
* have unique names, or names that are legal identifiers in the
* Java programming language (JLS 3.8).
*
* @throws MalformedParametersException if the class file contains
* a MethodParameters attribute that is improperly formatted.
* @return an array of {@code Parameter} objects representing all
* the parameters to the executable this object represents
* the parameters to the executable this object represents.
*/
public Parameter[] getParameters() {
// TODO: This may eventually need to be guarded by security
......@@ -316,6 +317,30 @@ public abstract class Executable extends AccessibleObject
return out;
}
private void verifyParameters(final Parameter[] parameters) {
final int mask = Modifier.FINAL | Modifier.SYNTHETIC | Modifier.MANDATED;
if (getParameterTypes().length != parameters.length)
throw new MalformedParametersException("Wrong number of parameters in MethodParameters attribute");
for (Parameter parameter : parameters) {
final String name = parameter.getRealName();
final int mods = parameter.getModifiers();
if (name != null) {
if (name.isEmpty() || name.indexOf('.') != -1 ||
name.indexOf(';') != -1 || name.indexOf('[') != -1 ||
name.indexOf('/') != -1) {
throw new MalformedParametersException("Invalid parameter name \"" + name + "\"");
}
}
if (mods != (mods & mask)) {
throw new MalformedParametersException("Invalid parameter modifiers");
}
}
}
private Parameter[] privateGetParameters() {
// Use tmp to avoid multiple writes to a volatile.
Parameter[] tmp = parameters;
......@@ -323,7 +348,12 @@ public abstract class Executable extends AccessibleObject
if (tmp == null) {
// Otherwise, go to the JVM to get them
tmp = getParameters0();
try {
tmp = getParameters0();
} catch(IllegalArgumentException e) {
// Rethrow ClassFormatErrors
throw new MalformedParametersException("Invalid constant pool index");
}
// If we get back nothing, then synthesize parameters
if (tmp == null) {
......@@ -331,6 +361,7 @@ public abstract class Executable extends AccessibleObject
tmp = synthesizeAllParams();
} else {
hasRealParameterData = true;
verifyParameters(tmp);
}
parameters = tmp;
......@@ -352,6 +383,12 @@ public abstract class Executable extends AccessibleObject
private transient volatile Parameter[] parameters;
private native Parameter[] getParameters0();
private native byte[] getTypeAnnotationBytes0();
// Needed by reflectaccess
byte[] getTypeAnnotationBytes() {
return getTypeAnnotationBytes0();
}
/**
* Returns an array of {@code Class} objects that represent the
......@@ -514,18 +551,20 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an AnnotatedType object that represents the use of a type to
* Returns an {@code AnnotatedType} object that represents the use of a type to
* specify the return type of the method/constructor represented by this
* Executable.
*
* If this Executable represents a constructor, the AnnotatedType object
* represents the type of the constructed object.
* If this {@code Executable} object represents a constructor, the {@code
* AnnotatedType} object represents the type of the constructed object.
*
* If this Executable represents a method, the AnnotatedType object
* represents the use of a type to specify the return type of the method.
* If this {@code Executable} object represents a method, the {@code
* AnnotatedType} object represents the use of a type to specify the return
* type of the method.
*
* @return an object representing the return type of the method
* or constructor represented by this {@code Executable}
*
* @return an object representing the return type of this method
* or constructor
* @since 1.8
*/
public abstract AnnotatedType getAnnotatedReturnType();
......@@ -539,7 +578,7 @@ public abstract class Executable extends AccessibleObject
* @since 1.8
*/
AnnotatedType getAnnotatedReturnType0(Type returnType) {
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
......@@ -549,25 +588,30 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an AnnotatedType object that represents the use of a type to
* specify the receiver type of the method/constructor represented by this
* Executable. The receiver type of a method/constructor is available only
* if the method/constructor declares a formal parameter called 'this'.
* Returns an {@code AnnotatedType} object that represents the use of a
* type to specify the receiver type of the method/constructor represented
* by this Executable object. The receiver type of a method/constructor is
* available only if the method/constructor has a <em>receiver
* parameter</em> (JLS 8.4.1).
*
* Returns null if this Executable represents a constructor or instance
* method that either declares no formal parameter called 'this', or
* declares a formal parameter called 'this' with no annotations on its
* type.
* If this {@code Executable} object represents a constructor or instance
* method that does not have a receiver parameter, or has a receiver
* parameter with no annotations on its type, then the return value is an
* {@code AnnotatedType} object representing an element with no
* annotations.
*
* Returns null if this Executable represents a static method.
* If this {@code Executable} object represents a static method, then the
* return value is null.
*
* @return an object representing the receiver type of the
* method or constructor represented by this Executable
* @return an object representing the receiver type of the method or
* constructor represented by this {@code Executable}
*
* @since 1.8
*/
public AnnotatedType getAnnotatedReceiverType() {
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
if (Modifier.isStatic(this.getModifiers()))
return null;
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
......@@ -577,8 +621,8 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to specify formal parameter types of the method/constructor
* Returns an array of {@code AnnotatedType} objects that represent the use
* of types to specify formal parameter types of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the formal parameter types in the
* declaration of the method/constructor.
......@@ -587,12 +631,13 @@ public abstract class Executable extends AccessibleObject
* parameters.
*
* @return an array of objects representing the types of the
* formal parameters of this method or constructor
* formal parameters of the method or constructor represented by this
* {@code Executable}
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedParameterTypes() {
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(),
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
......@@ -602,8 +647,8 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to specify the declared exceptions of the method/constructor
* Returns an array of {@code AnnotatedType} objects that represent the use
* of types to specify the declared exceptions of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the exception types in the declaration of
* the method/constructor.
......@@ -612,12 +657,13 @@ public abstract class Executable extends AccessibleObject
* exceptions.
*
* @return an array of objects representing the declared
* exceptions of this method or constructor
* exceptions of the method or constructor represented by this {@code
* Executable}
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedExceptionTypes() {
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(),
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
......
......@@ -82,8 +82,6 @@ class Field extends AccessibleObject implements Member {
// currently only two levels deep (i.e., one root Field and
// potentially many Field objects pointing to it.)
private Field root;
// This is set by the vm at Field creation
private byte[] typeAnnotations;
// Generics infrastructure
......@@ -149,7 +147,6 @@ class Field extends AccessibleObject implements Member {
res.fieldAccessor = fieldAccessor;
res.overrideFieldAccessor = overrideFieldAccessor;
res.typeAnnotations = typeAnnotations;
return res;
}
......@@ -1148,6 +1145,8 @@ class Field extends AccessibleObject implements Member {
return declaredAnnotations;
}
private native byte[] getTypeAnnotationBytes0();
/**
* Returns an AnnotatedType object that represents the use of a type to specify
* the declared type of the field represented by this Field.
......@@ -1157,7 +1156,7 @@ class Field extends AccessibleObject implements Member {
* @since 1.8
*/
public AnnotatedType getAnnotatedType() {
return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.reflect;
/**
* Thrown when {@link java.lang.reflect.Executable#getParameters the
* java.lang.reflect package} attempts to read method parameters from
* a class file and determines that one or more parameters are
* malformed.
*
* <p>The following is a list of conditions under which this exception
* can be thrown:
* <ul>
* <li> The number of parameters (parameter_count) is wrong for the method
* <li> A constant pool index is out of bounds.
* <li> A constant pool index does not refer to a UTF-8 entry
* <li> A parameter's name is "", or contains an illegal character
* <li> The flags field contains an illegal flag (something other than
* FINAL, SYNTHETIC, or MANDATED)
* </ul>
*
* See {@link java.lang.reflect.Executable#getParameters} for more
* information.
*
* @see java.lang.reflect.Executable#getParameters
* @since 1.8
*/
public class MalformedParametersException extends RuntimeException {
private static final long serialVersionUID = 20130919L;
public MalformedParametersException() {}
public MalformedParametersException(String reason) {
super(reason);
}
}
......@@ -80,8 +80,6 @@ public final class Method extends Executable {
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
private Method root;
// This is set by the vm at Method creation
private byte[] typeAnnotations;
// Generics infrastructure
private String getGenericSignature() {return signature;}
......@@ -152,8 +150,6 @@ public final class Method extends Executable {
res.root = this;
// Might as well eagerly propagate this if already present
res.methodAccessor = methodAccessor;
res.typeAnnotations = typeAnnotations;
return res;
}
......@@ -166,10 +162,6 @@ public final class Method extends Executable {
byte[] getAnnotationBytes() {
return annotations;
}
@Override
byte[] getTypeAnnotationBytes() {
return typeAnnotations;
}
/**
* {@inheritDoc}
......
......@@ -104,7 +104,7 @@ public final class Parameter implements AnnotatedElement {
* to the class file.
*/
public boolean isNamePresent() {
return executable.hasRealParameterData();
return executable.hasRealParameterData() && name != null;
}
/**
......@@ -182,6 +182,11 @@ public final class Parameter implements AnnotatedElement {
return name;
}
// Package-private accessor to the real name field.
String getRealName() {
return name;
}
/**
* Returns a {@code Type} object that identifies the parameterized
* type for the parameter represented by this {@code Parameter}
......
......@@ -2128,7 +2128,7 @@ public final class Files {
/**
* Tests whether a file is a symbolic link.
*
* <p> Where is it required to distinguish an I/O exception from the case
* <p> Where it is required to distinguish an I/O exception from the case
* that the file is not a symbolic link then the file attributes can be
* read with the {@link #readAttributes(Path,Class,LinkOption[])
* readAttributes} method and the file type tested with the {@link
......@@ -2164,7 +2164,7 @@ public final class Files {
* of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
* NOFOLLOW_LINKS} is present then symbolic links are not followed.
*
* <p> Where is it required to distinguish an I/O exception from the case
* <p> Where it is required to distinguish an I/O exception from the case
* that the file is not a directory then the file attributes can be
* read with the {@link #readAttributes(Path,Class,LinkOption[])
* readAttributes} method and the file type tested with the {@link
......@@ -2201,7 +2201,7 @@ public final class Files {
* of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
* NOFOLLOW_LINKS} is present then symbolic links are not followed.
*
* <p> Where is it required to distinguish an I/O exception from the case
* <p> Where it is required to distinguish an I/O exception from the case
* that the file is not a regular file then the file attributes can be
* read with the {@link #readAttributes(Path,Class,LinkOption[])
* readAttributes} method and the file type tested with the {@link
......@@ -3082,13 +3082,13 @@ public final class Files {
* method is invoked to check read access to the file.
*/
public static byte[] readAllBytes(Path path) throws IOException {
try (FileChannel fc = FileChannel.open(path);
InputStream is = Channels.newInputStream(fc)) {
long size = fc.size();
try (SeekableByteChannel sbc = Files.newByteChannel(path);
InputStream in = Channels.newInputStream(sbc)) {
long size = sbc.size();
if (size > (long)MAX_BUFFER_SIZE)
throw new OutOfMemoryError("Required array size too large");
return read(is, (int)size);
return read(in, (int)size);
}
}
......
......@@ -315,7 +315,7 @@ public interface Path
* and parent directory. In such file systems all occurrences of "{@code .}"
* are considered redundant. If a "{@code ..}" is preceded by a
* non-"{@code ..}" name then both names are considered redundant (the
* process to identify such names is repeated until is it no longer
* process to identify such names is repeated until it is no longer
* applicable).
*
* <p> This method does not access the file system; the path may not locate
......
......@@ -578,39 +578,30 @@ public class SecureRandom extends java.util.Random {
/**
* Returns a {@code SecureRandom} object that was selected by using
* the algorithms/providers specified in the {@code
* securerandom.strongAlgorithms} Security property.
* securerandom.strongAlgorithms} {@link Security} property.
* <p>
* Some situations require strong random values, such as when
* creating high-value/long-lived secrets like RSA public/private
* keys. To help guide applications in selecting a suitable strong
* {@code SecureRandom} implementation, Java distributions should
* {@code SecureRandom} implementation, Java distributions
* include a list of known strong {@code SecureRandom}
* implementations in the {@code securerandom.strongAlgorithms}
* Security property.
*
* <pre>
* SecureRandom sr = SecureRandom.getStrongSecureRandom();
*
* if (sr == null) {
* // Decide if this is a problem, and whether to recover.
* sr = new SecureRandom();
* if (!goodEnough(sr)) {
* return;
* }
* }
*
* keyPairGenerator.initialize(2048, sr);
* </pre>
* <p>
* Every implementation of the Java platform is required to
* support at least one strong {@code SecureRandom} implementation.
*
* @return a strong {@code SecureRandom} implementation as indicated
* by the {@code securerandom.strongAlgorithms} Security property, or
* null if none are available.
* by the {@code securerandom.strongAlgorithms} Security property
*
* @throws NoSuchAlgorithmException if no algorithm is available
*
* @see Security#getProperty(String)
*
* @since 1.8
*/
public static SecureRandom getStrongSecureRandom() {
public static SecureRandom getInstanceStrong()
throws NoSuchAlgorithmException {
String property = AccessController.doPrivileged(
new PrivilegedAction<String>() {
......@@ -622,7 +613,8 @@ public class SecureRandom extends java.util.Random {
});
if ((property == null) || (property.length() == 0)) {
return null;
throw new NoSuchAlgorithmException(
"Null/empty securerandom.strongAlgorithms Security Property");
}
String remainder = property;
......@@ -649,7 +641,8 @@ public class SecureRandom extends java.util.Random {
}
}
return null;
throw new NoSuchAlgorithmException(
"No strong SecureRandom impls available: " + property);
}
// Declare serialVersionUID to be compatible with JDK1.1
......
......@@ -441,9 +441,13 @@ public final class Duration
//-----------------------------------------------------------------------
/**
* Obtains a {@code Duration} representing the duration between two instants.
* Obtains a {@code Duration} representing the duration between two temporal objects.
* <p>
* This calculates the duration between two temporal objects. If the objects
* are of different types, then the duration is calculated based on the type
* of the first object. For example, if the first argument is a {@code LocalTime}
* then the second argument is converted to a {@code LocalTime}.
* <p>
* This calculates the duration between two temporal objects of the same type.
* The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit.
* For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the
* {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
......
......@@ -362,6 +362,10 @@ public final class Instant
* @throws DateTimeException if unable to convert to an {@code Instant}
*/
public static Instant from(TemporalAccessor temporal) {
if (temporal instanceof Instant) {
return (Instant) temporal;
}
Objects.requireNonNull(temporal, "temporal");
long instantSecs = temporal.getLong(INSTANT_SECONDS);
int nanoOfSecond = temporal.get(NANO_OF_SECOND);
return Instant.ofEpochSecond(instantSecs, nanoOfSecond);
......@@ -370,7 +374,7 @@ public final class Instant
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Instant} from a text string such as
* {@code 2007-12-03T10:15:30:00}.
* {@code 2007-12-03T10:15:30.00Z}.
* <p>
* The string must represent a valid instant in UTC and is parsed using
* {@link DateTimeFormatter#ISO_INSTANT}.
......@@ -1091,7 +1095,8 @@ public final class Instant
* The result will be negative if the end is before the start.
* The calculation returns a whole number, representing the number of
* complete units between the two instants.
* The {@code Temporal} passed to this method must be an {@code Instant}.
* The {@code Temporal} passed to this method is converted to a
* {@code Instant} using {@link #from(TemporalAccessor)}.
* For example, the amount in days between two dates can be calculated
* using {@code startInstant.until(endInstant, SECONDS)}.
* <p>
......@@ -1112,25 +1117,22 @@ public final class Instant
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
* passing {@code this} as the first argument and the input temporal as
* the second argument.
* passing {@code this} as the first argument and the converted input temporal
* as the second argument.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param endInstant the end date, which must be an {@code Instant}, not null
* @param endExclusive the end date, exclusive, which is converted to an {@code Instant}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this instant and the end instant
* @throws DateTimeException if the amount cannot be calculated
* @throws DateTimeException if the amount cannot be calculated, or the end
* temporal cannot be converted to an {@code Instant}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long until(Temporal endInstant, TemporalUnit unit) {
if (endInstant instanceof Instant == false) {
Objects.requireNonNull(endInstant, "endInstant");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
}
Instant end = (Instant) endInstant;
public long until(Temporal endExclusive, TemporalUnit unit) {
Instant end = Instant.from(endExclusive);
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
switch (f) {
......@@ -1145,7 +1147,7 @@ public final class Instant
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endInstant);
return unit.between(this, end);
}
private long nanosUntil(Instant end) {
......
......@@ -246,7 +246,8 @@ public final class MonthDay
* <p>
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
* {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
* The extraction is only permitted if the date-time has an ISO chronology.
* The extraction is only permitted if the temporal object has an ISO
* chronology, or can be converted to a {@code LocalDate}.
* <p>
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used in queries via method reference, {@code MonthDay::from}.
......
......@@ -333,6 +333,7 @@ public final class ZoneOffset
* @throws DateTimeException if unable to convert to an {@code ZoneOffset}
*/
public static ZoneOffset from(TemporalAccessor temporal) {
Objects.requireNonNull(temporal, "temporal");
ZoneOffset offset = temporal.query(TemporalQuery.offset());
if (offset == null) {
throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass());
......
此差异已折叠。
......@@ -268,8 +268,8 @@ public enum ChronoUnit implements TemporalUnit {
//-----------------------------------------------------------------------
@Override
public long between(Temporal temporal1, Temporal temporal2) {
return temporal1.until(temporal2, this);
public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) {
return temporal1Inclusive.until(temporal2Exclusive, this);
}
//-----------------------------------------------------------------------
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册