提交 3d06a5e4 编写于 作者: L lana

Merge

...@@ -118,3 +118,6 @@ d80954a89b49fda47c0c5cace65a17f5a758b8bd jdk7-b139 ...@@ -118,3 +118,6 @@ d80954a89b49fda47c0c5cace65a17f5a758b8bd jdk7-b139
63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141 63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141
312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142 312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142
efbf75c24b0f31847c9c403f6dc07dc80551908d jdk7-b143 efbf75c24b0f31847c9c403f6dc07dc80551908d jdk7-b143
23bdcede4e3945894574892e80b848bd9f15b5f3 jdk7-b144
1e04b38b3824a4a1d197ef681a302e6813e53f8b jdk7-b145
539e576793a8e64aaf160e0d6ab0b9723cd0bef0 jdk7-b146
因为 它太大了无法显示 source diff 。你可以改为 查看blob
...@@ -48,6 +48,9 @@ include Exportedfiles.gmk ...@@ -48,6 +48,9 @@ include Exportedfiles.gmk
ifeq ($(PLATFORM), solaris) ifeq ($(PLATFORM), solaris)
OTHER_LDLIBS += -ldoor OTHER_LDLIBS += -ldoor
endif endif
ifeq ($(PLATFORM), windows)
EXTRA_LIBS += psapi.lib
endif
vpath %.c $(PLATFORM_SRC)/native/sun/tools/attach vpath %.c $(PLATFORM_SRC)/native/sun/tools/attach
......
...@@ -49,5 +49,16 @@ RUNTIME_NAME = $(PRODUCT_NAME) $(PRODUCT_SUFFIX) ...@@ -49,5 +49,16 @@ RUNTIME_NAME = $(PRODUCT_NAME) $(PRODUCT_SUFFIX)
JRE_REDUCED_HEADLESS_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-headless-image JRE_REDUCED_HEADLESS_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-headless-image
JRE_REDUCED_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-image JRE_REDUCED_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-image
# Override on linux to further reduce binary/lib sizes in product build
ifeq ($(PLATFORM), linux)
ifeq ($(VARIANT), OPT)
ifneq ($(NO_STRIP), true)
ifneq ($(DEBUG_BINARIES), true)
POST_STRIP_PROCESS = $(STRIP) --strip-unneeded
endif
endif
endif
endif
endif # JAVASE_EMBEDDED endif # JAVASE_EMBEDDED
...@@ -53,25 +53,30 @@ $(NOT_HEADLESS_RT_JAR_LIST): $(NOT_RT_JAR_LIST) ...@@ -53,25 +53,30 @@ $(NOT_HEADLESS_RT_JAR_LIST): $(NOT_RT_JAR_LIST)
$(RM) $(HEADLESS_CLASSLIST) $(RM) $(HEADLESS_CLASSLIST)
$(RM) $(NOT_HEADLESS_RT_JAR_LIST) $(RM) $(NOT_HEADLESS_RT_JAR_LIST)
$(CP) $(NOT_RT_JAR_LIST) $(NOT_HEADLESS_RT_JAR_LIST) $(CP) $(NOT_RT_JAR_LIST) $(NOT_HEADLESS_RT_JAR_LIST)
# List all the packages to be excluded
$(ECHO) "sun/awt/motif/" >> $@ $(ECHO) "sun/awt/motif/" >> $@
$(ECHO) "sun/awt/X11/" >> $@ $(ECHO) "sun/awt/X11/" >> $@
$(ECHO) "sun/applet/" >> $@ $(ECHO) "sun/applet/" >> $@
$(ECHO) "sun/java2d/opengl/" >> $@ $(ECHO) "sun/java2d/opengl/" >> $@
$(ECHO) "com/sun/java/swing/plaf/" >> $@ $(ECHO) "com/sun/java/swing/plaf/" >> $@
$(ECHO) "sun/awt/motif/MFontConfiguration" >$(HEADLESS_CLASSLIST) # List all the individual classes to be included
$(ECHO) "sun/applet/AppContextCreator" >>$(HEADLESS_CLASSLIST) $(ECHO) "sun/awt/motif/MFontConfiguration.class" >$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppletAudioClip" >>$(HEADLESS_CLASSLIST) $(ECHO) "sun/applet/AppContextCreator.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData" >>$(HEADLESS_CLASSLIST) $(ECHO) "sun/applet/AppletAudioClip.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData"\$$"GLXOffScreenSurfaceData" >>$(HEADLESS_CLASSLIST) $(ECHO) "sun/java2d/opengl/GLXSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXVolatileSurfaceManager" >>$(HEADLESS_CLASSLIST) $(ECHO) "sun/java2d/opengl/GLXSurfaceData"\$$"GLXOffScreenSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/OGLSurfaceData" >>$(HEADLESS_CLASSLIST) $(ECHO) "sun/java2d/opengl/GLXVolatileSurfaceManager.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/OGLSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(TOTAL_HEADLESS_JAR_FILELIST): $(JARREORDER_JARFILE) $(NOT_HEADLESS_RT_JAR_LIST) $(TOTAL_HEADLESS_JAR_FILELIST): $(JARREORDER_JARFILE) $(NOT_HEADLESS_RT_JAR_LIST)
$(prep-target) $(prep-target)
$(RM) $@.temp $(RM) $@.temp
$(CD) $(CLASSBINDIR) ; \ $(CD) $(CLASSBINDIR) ; \
$(BOOT_JAVA_CMD) -jar $(JARREORDER_JARFILE) \ $(BOOT_JAVA_CMD) -jar $(JARREORDER_JARFILE) \
-o $@.temp $(HEADLESS_CLASSLIST) $(NOT_HEADLESS_RT_JAR_LIST) . -o $@.temp - $(NOT_HEADLESS_RT_JAR_LIST) .
# Add on the explicitly included class files from the otherwise excluded packages
$(CAT) $(HEADLESS_CLASSLIST) >> $@.temp
$(MV) $@.temp $@ $(MV) $@.temp $@
@$(CD) $(CLASSBINDIR); $(java-vm-cleanup) @$(CD) $(CLASSBINDIR); $(java-vm-cleanup)
...@@ -124,13 +129,9 @@ NOT_REDUCEDJRE_LIB = \ ...@@ -124,13 +129,9 @@ NOT_REDUCEDJRE_LIB = \
$(LIBARCH)/libjavaplugin_nscp.so \ $(LIBARCH)/libjavaplugin_nscp.so \
$(LIBARCH)/libjavaplugin_oji.so $(LIBARCH)/libjavaplugin_oji.so
# JRE docs that don't get included in reduced jre image top directory
ifeq ($(PLATFORM), linux) NOT_REDUCEDJRE_DOC = \
STRIP_OPTS = --strip-unneeded Welcome.html
else
STRIP_OPTS = -x
endif
reduced-image-jre:: reduced-image-jre::
@$(ECHO) Starting to Produce Reduced JRE @$(ECHO) Starting to Produce Reduced JRE
...@@ -142,12 +143,6 @@ reduced-image-jre:: ...@@ -142,12 +143,6 @@ reduced-image-jre::
$(CD) $(JRE_IMAGE_DIR); \ $(CD) $(JRE_IMAGE_DIR); \
$(TAR) cf - . | ($(CD) $(JRE_REDUCED_IMAGE_DIR); $(TAR) xf - ); $(TAR) cf - . | ($(CD) $(JRE_REDUCED_IMAGE_DIR); $(TAR) xf - );
@# strip the main .so files
$(STRIP) $(STRIP_OPTS) $(JRE_REDUCED_IMAGE_DIR)/lib/$(LIBARCH)/client/libjvm.so
ifndef BUILD_CLIENT_ONLY
$(STRIP) $(STRIP_OPTS) $(JRE_REDUCED_IMAGE_DIR)/lib/$(LIBARCH)/server/libjvm.so
endif
@# @#
@# Remove all of the files that are not needed for the @# Remove all of the files that are not needed for the
@# reduced JRE @# reduced JRE
...@@ -158,6 +153,9 @@ endif ...@@ -158,6 +153,9 @@ endif
for l in $(NOT_REDUCEDJRE_LIB) ; do \ for l in $(NOT_REDUCEDJRE_LIB) ; do \
$(RM) $(JRE_REDUCED_IMAGE_DIR)/lib/$$l ; \ $(RM) $(JRE_REDUCED_IMAGE_DIR)/lib/$$l ; \
done done
for l in $(NOT_REDUCEDJRE_DOC) ; do \
$(RM) $(JRE_REDUCED_IMAGE_DIR)/$$l ; \
done
@# Remove misc. other files @# Remove misc. other files
$(RM) -r $(JRE_REDUCED_IMAGE_DIR)/man $(RM) -r $(JRE_REDUCED_IMAGE_DIR)/man
......
...@@ -900,8 +900,10 @@ initial-image-jdk-db: $(DB_ZIP_LIST) ...@@ -900,8 +900,10 @@ initial-image-jdk-db: $(DB_ZIP_LIST)
for d in $(DB_ZIP_LIST); do \ for d in $(DB_ZIP_LIST); do \
($(CD) $(JDK_IMAGE_DIR)/db && $(UNZIP) -o $$d); \ ($(CD) $(JDK_IMAGE_DIR)/db && $(UNZIP) -o $$d); \
done done
$(CP) $(ABS_DB_PATH)/README-JDK.html $(JDK_IMAGE_DIR)/db
$(RM) -rf $(DEMODIR)/db $(RM) -rf $(DEMODIR)/db
$(MV) $(JDK_IMAGE_DIR)/db/demo $(DEMODIR)/db $(MV) $(JDK_IMAGE_DIR)/db/demo $(DEMODIR)/db
$(CP) $(ABS_DB_PATH)/README-JDK-DEMOS.html $(DEMODIR)/db/
$(RM) $(JDK_IMAGE_DIR)/db/index.html $(JDK_IMAGE_DIR)/db/register.html $(RM) $(JDK_IMAGE_DIR)/db/index.html $(JDK_IMAGE_DIR)/db/register.html
endif endif
......
...@@ -370,8 +370,7 @@ $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar: \ ...@@ -370,8 +370,7 @@ $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar: \
CLOSED_DIR = $(BUILDDIR)/closed/javax/crypto CLOSED_DIR = $(BUILDDIR)/closed/javax/crypto
release: $(SIGNED_DIR)/jce.jar sign-policy $(CLOSED_DIR)/doc/COPYRIGHT.html \ release: $(SIGNED_DIR)/jce.jar sign-policy $(CLOSED_DIR)/doc/README.txt
$(CLOSED_DIR)/doc/README.txt
$(RM) -r \ $(RM) -r \
$(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy \ $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy \
$(JCE_BUILD_DIR)/release/jce.jar \ $(JCE_BUILD_DIR)/release/jce.jar \
...@@ -387,7 +386,6 @@ release: $(SIGNED_DIR)/jce.jar sign-policy $(CLOSED_DIR)/doc/COPYRIGHT.html \ ...@@ -387,7 +386,6 @@ release: $(SIGNED_DIR)/jce.jar sign-policy $(CLOSED_DIR)/doc/COPYRIGHT.html \
$(CP) \ $(CP) \
$(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar \ $(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar \
$(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar \ $(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar \
$(CLOSED_DIR)/doc/COPYRIGHT.html \
$(CLOSED_DIR)/doc/README.txt \ $(CLOSED_DIR)/doc/README.txt \
$(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy
cd $(JCE_BUILD_DIR)/release ; \ cd $(JCE_BUILD_DIR)/release ; \
......
...@@ -147,7 +147,7 @@ OTHER_INCLUDES += \ ...@@ -147,7 +147,7 @@ OTHER_INCLUDES += \
# Rules # Rules
# #
CLASSDESTDIR = $(TEMPDIR)/classes CLASSDESTDIR = $(TEMPDIR)/classes
JAVAHFLAGS += -classpath $(CLASSDESTDIR) JAVAHFLAGS += -Xbootclasspath/p:$(CLASSDESTDIR)
include $(BUILDDIR)/common/Mapfile-vers.gmk include $(BUILDDIR)/common/Mapfile-vers.gmk
......
." Copyright (c) 1998-2011 keytool tool, Oracle and/or its affiliates. All rights reserved. ." Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
." DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ." DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
." ."
." This code is free software; you can redistribute it and/or modify it ." This code is free software; you can redistribute it and/or modify it
......
." Copyright (c) 1998-2011 keytool tool, Oracle and/or its affiliates. All rights reserved. ." Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
." DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ." DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
." ."
." This code is free software; you can redistribute it and/or modify it ." This code is free software; you can redistribute it and/or modify it
......
...@@ -174,8 +174,11 @@ class GTKFileChooserUI extends SynthFileChooserUI { ...@@ -174,8 +174,11 @@ class GTKFileChooserUI extends SynthFileChooserUI {
// construct the resulting string // construct the resulting string
for (int i=0; i<len; i++) { for (int i=0; i<len; i++) {
if (i > 0) {
buf.append(" ");
}
if (len > 1) { if (len > 1) {
buf.append(" \""); buf.append("\"");
} }
buf.append(result.get(i)); buf.append(result.get(i));
if (len > 1) { if (len > 1) {
......
...@@ -56,9 +56,9 @@ FileChooser.deleteFileButtonMnemonic=76 ...@@ -56,9 +56,9 @@ FileChooser.deleteFileButtonMnemonic=76
FileChooser.renameFileButtonText=Rename File FileChooser.renameFileButtonText=Rename File
FileChooser.renameFileButtonMnemonic=82 FileChooser.renameFileButtonMnemonic=82
FileChooser.cancelButtonText=Cancel FileChooser.cancelButtonText=Cancel
#FileChooser.cancelButtonMnemonic=67 FileChooser.cancelButtonMnemonic=67
FileChooser.saveButtonText=OK FileChooser.saveButtonText=OK
#FileChooser.saveButtonMnemonic=79 FileChooser.saveButtonMnemonic=79
FileChooser.openButtonText=OK FileChooser.openButtonText=OK
FileChooser.openButtonMnemonic=79 FileChooser.openButtonMnemonic=79
FileChooser.saveDialogTitleText=Save FileChooser.saveDialogTitleText=Save
...@@ -79,5 +79,5 @@ FileChooser.renameFileDialogText=Rename file "{0}" to ...@@ -79,5 +79,5 @@ FileChooser.renameFileDialogText=Rename file "{0}" to
FileChooser.renameFileErrorTitle=Error FileChooser.renameFileErrorTitle=Error
FileChooser.renameFileErrorText=Error renaming file "{0}" to "{1}" FileChooser.renameFileErrorText=Error renaming file "{0}" to "{1}"
#OptionPane.okButtonMnemonic=79 OptionPane.okButtonMnemonic=79
#OptionPane.cancelButtonMnemonic=67 OptionPane.cancelButtonMnemonic=67
...@@ -1856,11 +1856,9 @@ public abstract class Toolkit { ...@@ -1856,11 +1856,9 @@ public abstract class Toolkit {
} }
/** /**
* Adds the specified property change listener for the named * Adds the specified property change listener for the named desktop
* desktop property. When a {@link * property. When a {@link java.beans.PropertyChangeListenerProxy} object is added,
* java.beans.PropertyChangeListenerProxy * its property name is ignored, and the wrapped listener is added.
* PropertyChangeListenerProxy} object is added, its property name
* is ignored, and the wrapped listener is added.
* If {@code name} is {@code null} or {@code pcl} is {@code null}, * If {@code name} is {@code null} or {@code pcl} is {@code null},
* no exception is thrown and no action is performed. * no exception is thrown and no action is performed.
* *
...@@ -1876,10 +1874,9 @@ public abstract class Toolkit { ...@@ -1876,10 +1874,9 @@ public abstract class Toolkit {
/** /**
* Removes the specified property change listener for the named * Removes the specified property change listener for the named
* desktop property. When a {@link * desktop property. When a {@link java.beans.PropertyChangeListenerProxy} object
* java.beans.PropertyChangeListenerProxy * is removed, its property name is ignored, and
* PropertyChangeListenerProxy} object is removed, its property * the wrapped listener is removed.
* name is ignored, and the wrapped listener is removed.
* If {@code name} is {@code null} or {@code pcl} is {@code null}, * If {@code name} is {@code null} or {@code pcl} is {@code null},
* no exception is thrown and no action is performed. * no exception is thrown and no action is performed.
* *
...@@ -1896,11 +1893,11 @@ public abstract class Toolkit { ...@@ -1896,11 +1893,11 @@ public abstract class Toolkit {
/** /**
* Returns an array of all the property change listeners * Returns an array of all the property change listeners
* registered on this toolkit. The returned array * registered on this toolkit. The returned array
* contains {@code PropertyChangeListenerProxy} objects * contains {@link java.beans.PropertyChangeListenerProxy} objects
* that associate listeners with the names of desktop properties. * that associate listeners with the names of desktop properties.
* *
* @return all of this toolkit's {@code PropertyChangeListener} * @return all of this toolkit's {@link PropertyChangeListener}
* objects wrapped in {@code PropertyChangeListenerProxy} objects * objects wrapped in {@code java.beans.PropertyChangeListenerProxy} objects
* or an empty array if no listeners are added * or an empty array if no listeners are added
* *
* @see PropertyChangeSupport#getPropertyChangeListeners() * @see PropertyChangeSupport#getPropertyChangeListeners()
......
...@@ -1382,13 +1382,19 @@ public class ICC_Profile implements Serializable { ...@@ -1382,13 +1382,19 @@ public class ICC_Profile implements Serializable {
/** /**
* Sets a particular tagged data element in the profile from * Sets a particular tagged data element in the profile from
* a byte array. This method is useful * a byte array. The array should contain data in a format, corresponded
* for advanced applets or applications which need to access * to the {@code tagSignature} as defined in the ICC specification, section 10.
* profile data directly. * This method is useful for advanced applets or applications which need to
* access profile data directly.
* *
* @param tagSignature The ICC tag signature for the data element * @param tagSignature The ICC tag signature for the data element
* you want to set. * you want to set.
* @param tagData the data to set for the specified tag signature * @param tagData the data to set for the specified tag signature
* @throws IllegalArgumentException if {@code tagSignature} is not a signature
* as defined in the ICC specification.
* @throws IllegalArgumentException if a content of the {@code tagData}
* array can not be interpreted as valid tag data, corresponding
* to the {@code tagSignature}.
* @see #getData * @see #getData
*/ */
public void setData(int tagSignature, byte[] tagData) { public void setData(int tagSignature, byte[] tagData) {
......
/* /*
* %W% %E% * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/ */
......
...@@ -39,14 +39,14 @@ public class BootstrapMethodError extends LinkageError { ...@@ -39,14 +39,14 @@ public class BootstrapMethodError extends LinkageError {
private static final long serialVersionUID = 292L; private static final long serialVersionUID = 292L;
/** /**
* Constructs an {@code BootstrapMethodError} with no detail message. * Constructs a {@code BootstrapMethodError} with no detail message.
*/ */
public BootstrapMethodError() { public BootstrapMethodError() {
super(); super();
} }
/** /**
* Constructs an {@code BootstrapMethodError} with the specified * Constructs a {@code BootstrapMethodError} with the specified
* detail message. * detail message.
* *
* @param s the detail message. * @param s the detail message.
......
...@@ -38,6 +38,13 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -38,6 +38,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* @since 1.7 * @since 1.7
*/ */
public abstract class ClassValue<T> { public abstract class ClassValue<T> {
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected ClassValue() {
}
/** /**
* Computes the given class's derived value for this {@code ClassValue}. * Computes the given class's derived value for this {@code ClassValue}.
* <p> * <p>
...@@ -100,7 +107,7 @@ public abstract class ClassValue<T> { ...@@ -100,7 +107,7 @@ public abstract class ClassValue<T> {
* If this value is subsequently {@linkplain #get read} for the same class, * If this value is subsequently {@linkplain #get read} for the same class,
* its value will be reinitialized by invoking its {@link #computeValue computeValue} method. * its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
* This may result in an additional invocation of the * This may result in an additional invocation of the
* {@code computeValue computeValue} method for the given class. * {@code computeValue} method for the given class.
* <p> * <p>
* In order to explain the interaction between {@code get} and {@code remove} calls, * In order to explain the interaction between {@code get} and {@code remove} calls,
* we must model the state transitions of a class value to take into account * we must model the state transitions of a class value to take into account
...@@ -193,6 +200,7 @@ public abstract class ClassValue<T> { ...@@ -193,6 +200,7 @@ public abstract class ClassValue<T> {
= new WeakHashMap<Class<?>, ClassValueMap>(); = new WeakHashMap<Class<?>, ClassValueMap>();
private static ClassValueMap getMap(Class<?> type) { private static ClassValueMap getMap(Class<?> type) {
type.getClass(); // test for null
return ROOT.get(type); return ROOT.get(type);
} }
......
...@@ -29,6 +29,8 @@ import sun.invoke.util.VerifyType; ...@@ -29,6 +29,8 @@ import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import sun.invoke.util.ValueConversions; import sun.invoke.util.ValueConversions;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
...@@ -62,7 +64,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -62,7 +64,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// the target and change its type, instead of adding another layer. // the target and change its type, instead of adding another layer.
/** Can a JVM-level adapter directly implement the proposed /** Can a JVM-level adapter directly implement the proposed
* argument conversions, as if by MethodHandles.convertArguments? * argument conversions, as if by fixed-arity MethodHandle.asType?
*/ */
static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) { static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) {
// same number of args, of course // same number of args, of course
...@@ -92,7 +94,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -92,7 +94,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
} }
/** Can a JVM-level adapter directly implement the proposed /** Can a JVM-level adapter directly implement the proposed
* argument conversion, as if by MethodHandles.convertArguments? * argument conversion, as if by fixed-arity MethodHandle.asType?
*/ */
static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) { static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) {
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
...@@ -403,13 +405,13 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -403,13 +405,13 @@ class AdapterMethodHandle extends BoundMethodHandle {
insertStackMove(stackMove) insertStackMove(stackMove)
); );
} }
private static long makeSwapConv(int convOp, int srcArg, byte type, int destSlot) { private static long makeSwapConv(int convOp, int srcArg, byte srcType, int destSlot, byte destType) {
// more complex argument motion, requiring two slots to specify // more complex argument motion, requiring two slots to specify
assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS); assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS);
return ((long) srcArg << 32 | return ((long) srcArg << 32 |
(long) convOp << CONV_OP_SHIFT | (long) convOp << CONV_OP_SHIFT |
(int) type << CONV_SRC_TYPE_SHIFT | (int) srcType << CONV_SRC_TYPE_SHIFT |
(int) type << CONV_DEST_TYPE_SHIFT | (int) destType << CONV_DEST_TYPE_SHIFT |
(int) destSlot << CONV_VMINFO_SHIFT (int) destSlot << CONV_VMINFO_SHIFT
); );
} }
...@@ -550,6 +552,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -550,6 +552,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
int last = type.parameterCount() - 1; int last = type.parameterCount() - 1;
if (type.parameterType(last) != arrayType) if (type.parameterType(last) != arrayType)
target = target.asType(type.changeParameterType(last, arrayType)); target = target.asType(type.changeParameterType(last, arrayType));
target = target.asFixedArity(); // make sure this attribute is turned off
return new AsVarargsCollector(target, arrayType); return new AsVarargsCollector(target, arrayType);
} }
...@@ -570,6 +573,11 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -570,6 +573,11 @@ class AdapterMethodHandle extends BoundMethodHandle {
return true; return true;
} }
@Override
public MethodHandle asFixedArity() {
return target;
}
@Override @Override
public MethodHandle asType(MethodType newType) { public MethodHandle asType(MethodType newType) {
MethodType type = this.type(); MethodType type = this.type();
...@@ -594,14 +602,6 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -594,14 +602,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
cache = collector; cache = collector;
return collector.asType(newType); return collector.asType(newType);
} }
@Override
public MethodHandle asVarargsCollector(Class<?> arrayType) {
MethodType type = this.type();
if (type.parameterType(type.parameterCount()-1) == arrayType)
return this;
return super.asVarargsCollector(arrayType);
}
} }
/** Can a checkcast adapter validly convert the target to newType? /** Can a checkcast adapter validly convert the target to newType?
...@@ -747,8 +747,31 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -747,8 +747,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
if (!canUnboxArgument(newType, oldType, arg, convType, level)) if (!canUnboxArgument(newType, oldType, arg, convType, level))
return null; return null;
MethodType castDone = newType; MethodType castDone = newType;
if (!VerifyType.isNullConversion(src, boxType)) if (!VerifyType.isNullConversion(src, boxType)) {
// Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
if (level != 0) {
// must include additional conversions
if (src == Object.class || !Wrapper.isWrapperType(src)) {
// src must be examined at runtime, to detect Byte, Character, etc.
MethodHandle unboxMethod = (level == 1
? ValueConversions.unbox(dst)
: ValueConversions.unboxCast(dst));
long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
return new AdapterMethodHandle(target, newType, conv, unboxMethod);
}
// Example: Byte->int
// Do this by reformulating the problem to Byte->byte.
Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
MethodType midType = newType.changeParameterType(arg, srcPrim);
MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0);
if (canPrimCast(midType, oldType, arg, dst))
fixPrim = makePrimCast(midType, target, arg, dst);
else
fixPrim = target;
return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0);
}
castDone = newType.changeParameterType(arg, boxType); castDone = newType.changeParameterType(arg, boxType);
}
long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType)); long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
if (castDone == newType) if (castDone == newType)
...@@ -917,13 +940,30 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -917,13 +940,30 @@ class AdapterMethodHandle extends BoundMethodHandle {
if (swapArg1 == swapArg2) if (swapArg1 == swapArg2)
return target; return target;
if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
if (type2size(newType.parameterType(swapArg1)) !=
type2size(newType.parameterType(swapArg2))) {
// turn a swap into a pair of rotates:
// [x a b c y] rot2(-1,argc=5) => [a b c y x] rot1(+1,argc=4) => target[y a b c x]
int argc = swapArg2 - swapArg1 + 1;
final int ROT = 1;
ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList());
Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT);
MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params);
MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT);
assert(rot1 != null);
if (argc == 2) return rot1;
MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
assert(rot2 != null);
return rot2;
}
if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
return null; return null;
Class<?> swapType = newType.parameterType(swapArg1); Class<?> type1 = newType.parameterType(swapArg1);
Class<?> type2 = newType.parameterType(swapArg2);
// in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ] // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
// out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ] // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1); int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1);
long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2); long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(type1), swapSlot2, basicType(type2));
return new AdapterMethodHandle(target, newType, conv); return new AdapterMethodHandle(target, newType, conv);
} }
...@@ -946,7 +986,6 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -946,7 +986,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
static boolean canRotateArguments(MethodType newType, MethodType targetType, static boolean canRotateArguments(MethodType newType, MethodType targetType,
int firstArg, int argCount, int rotateBy) { int firstArg, int argCount, int rotateBy) {
if (!convOpSupported(OP_ROT_ARGS)) return false; if (!convOpSupported(OP_ROT_ARGS)) return false;
if (argCount <= 2) return false; // must be a swap, not a rotate
rotateBy = positiveRotation(argCount, rotateBy); rotateBy = positiveRotation(argCount, rotateBy);
if (rotateBy == 0) return false; // no rotation if (rotateBy == 0) return false; // no rotation
if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
...@@ -992,26 +1031,30 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -992,26 +1031,30 @@ class AdapterMethodHandle extends BoundMethodHandle {
// From here on out, it assumes a single-argument shift. // From here on out, it assumes a single-argument shift.
assert(MAX_ARG_ROTATION == 1); assert(MAX_ARG_ROTATION == 1);
int srcArg, dstArg; int srcArg, dstArg;
byte basicType; int dstSlot;
if (chunk2Slots <= chunk1Slots) { int moveChunk;
if (rotateBy == 1) {
// Rotate right/down N (rotateBy = +N, N small, c2 small): // Rotate right/down N (rotateBy = +N, N small, c2 small):
// in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ] // in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ]
// out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ] // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
srcArg = limit-1; srcArg = limit-1;
dstArg = firstArg; dstArg = firstArg;
basicType = basicType(newType.parameterType(srcArg)); //dstSlot = depth0 - chunk2Slots; //chunk2Slots is not relevant
assert(chunk2Slots == type2size(basicType)); dstSlot = depth0 + MethodHandleNatives.OP_ROT_ARGS_DOWN_LIMIT_BIAS;
moveChunk = chunk2Slots;
} else { } else {
// Rotate left/up N (rotateBy = -N, N small, c1 small): // Rotate left/up N (rotateBy = -N, N small, c1 small):
// in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ] // in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ]
// out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ] // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
srcArg = firstArg; srcArg = firstArg;
dstArg = limit-1; dstArg = limit-1;
basicType = basicType(newType.parameterType(srcArg)); dstSlot = depth2;
assert(chunk1Slots == type2size(basicType)); moveChunk = chunk1Slots;
} }
int dstSlot = newType.parameterSlotDepth(dstArg + 1); byte srcType = basicType(newType.parameterType(srcArg));
long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot); byte dstType = basicType(newType.parameterType(dstArg));
assert(moveChunk == type2size(srcType));
long conv = makeSwapConv(OP_ROT_ARGS, srcArg, srcType, dstSlot, dstType);
return new AdapterMethodHandle(target, newType, conv); return new AdapterMethodHandle(target, newType, conv);
} }
......
...@@ -151,7 +151,7 @@ class BoundMethodHandle extends MethodHandle { ...@@ -151,7 +151,7 @@ class BoundMethodHandle extends MethodHandle {
final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) { final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
String atype = (argument == null) ? "null" : argument.getClass().toString(); String atype = (argument == null) ? "null" : argument.getClass().toString();
return new WrongMethodTypeException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type()); return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
} }
@Override @Override
......
...@@ -111,7 +111,7 @@ public class CallSite { ...@@ -111,7 +111,7 @@ public class CallSite {
} }
/** /**
* Make a blank call site object, possibly equipped with an initial target method handle. * Make a call site object equipped with an initial target method handle.
* @param target the method handle which will be the initial target of the call site * @param target the method handle which will be the initial target of the call site
* @throws NullPointerException if the proposed target is null * @throws NullPointerException if the proposed target is null
*/ */
...@@ -121,6 +121,25 @@ public class CallSite { ...@@ -121,6 +121,25 @@ public class CallSite {
this.target = target; this.target = target;
} }
/**
* Make a call site object equipped with an initial target method handle.
* @param targetType the desired type of the call site
* @param createTargetHook a hook which will bind the call site to the target method handle
* @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
* or if the target returned by the hook is not of the given {@code targetType}
* @throws NullPointerException if the hook returns a null value
* @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
* @throws Throwable anything else thrown by the the hook function
*/
/*package-private*/
CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
this(targetType);
ConstantCallSite selfCCS = (ConstantCallSite) this;
MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
checkTargetChange(this.target, boundTarget);
this.target = boundTarget;
}
/** /**
* Returns the type of this call site's target. * Returns the type of this call site's target.
* Although targets may change, any call site's type is permanent, and can never change to an unequal type. * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
...@@ -129,6 +148,7 @@ public class CallSite { ...@@ -129,6 +148,7 @@ public class CallSite {
* @return the type of the current target, which is also the type of any future target * @return the type of the current target, which is also the type of any future target
*/ */
public MethodType type() { public MethodType type() {
// warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
return target.type(); return target.type();
} }
...@@ -294,8 +314,8 @@ public class CallSite { ...@@ -294,8 +314,8 @@ public class CallSite {
} else { } else {
throw new ClassCastException("bootstrap method failed to produce a CallSite"); throw new ClassCastException("bootstrap method failed to produce a CallSite");
} }
assert(site.getTarget() != null); if (!site.getTarget().type().equals(type))
assert(site.getTarget().type().equals(type)); throw new WrongMethodTypeException("wrong type: "+site.getTarget());
} catch (Throwable ex) { } catch (Throwable ex) {
BootstrapMethodError bex; BootstrapMethodError bex;
if (ex instanceof BootstrapMethodError) if (ex instanceof BootstrapMethodError)
......
...@@ -32,6 +32,8 @@ package java.lang.invoke; ...@@ -32,6 +32,8 @@ package java.lang.invoke;
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
*/ */
public class ConstantCallSite extends CallSite { public class ConstantCallSite extends CallSite {
private final boolean isFrozen;
/** /**
* Creates a call site with a permanent target. * Creates a call site with a permanent target.
* @param target the target to be permanently associated with this call site * @param target the target to be permanently associated with this call site
...@@ -39,6 +41,45 @@ public class ConstantCallSite extends CallSite { ...@@ -39,6 +41,45 @@ public class ConstantCallSite extends CallSite {
*/ */
public ConstantCallSite(MethodHandle target) { public ConstantCallSite(MethodHandle target) {
super(target); super(target);
isFrozen = true;
}
/**
* Creates a call site with a permanent target, possibly bound to the call site itself.
* <p>
* During construction of the call site, the {@code createTargetHook} is invoked to
* produce the actual target, as if by a call of the form
* {@code (MethodHandle) createTargetHook.invoke(this)}.
* <p>
* Note that user code cannot perform such an action directly in a subclass constructor,
* since the target must be fixed before the {@code ConstantCallSite} constructor returns.
* <p>
* The hook is said to bind the call site to a target method handle,
* and a typical action would be {@code someTarget.bindTo(this)}.
* However, the hook is free to take any action whatever,
* including ignoring the call site and returning a constant target.
* <p>
* The result returned by the hook must be a method handle of exactly
* the same type as the call site.
* <p>
* While the hook is being called, the new {@code ConstantCallSite}
* object is in a partially constructed state.
* In this state,
* a call to {@code getTarget}, or any other attempt to use the target,
* will result in an {@code IllegalStateException}.
* It is legal at all times to obtain the call site's type using the {@code type} method.
*
* @param targetType the type of the method handle to be permanently associated with this call site
* @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
* @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
* or if the target returned by the hook is not of the given {@code targetType}
* @throws NullPointerException if the hook returns a null value
* @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
* @throws Throwable anything else thrown by the the hook function
*/
protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
super(targetType, createTargetHook);
isFrozen = true;
} }
/** /**
...@@ -48,9 +89,10 @@ public class ConstantCallSite extends CallSite { ...@@ -48,9 +89,10 @@ public class ConstantCallSite extends CallSite {
* to the constructor call which created this instance. * to the constructor call which created this instance.
* *
* @return the immutable linkage state of this call site, a constant method handle * @return the immutable linkage state of this call site, a constant method handle
* @throws UnsupportedOperationException because this kind of call site cannot change its target * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/ */
@Override public final MethodHandle getTarget() { @Override public final MethodHandle getTarget() {
if (!isFrozen) throw new IllegalStateException();
return target; return target;
} }
...@@ -61,7 +103,7 @@ public class ConstantCallSite extends CallSite { ...@@ -61,7 +103,7 @@ public class ConstantCallSite extends CallSite {
* @throws UnsupportedOperationException because this kind of call site cannot change its target * @throws UnsupportedOperationException because this kind of call site cannot change its target
*/ */
@Override public final void setTarget(MethodHandle ignore) { @Override public final void setTarget(MethodHandle ignore) {
throw new UnsupportedOperationException("ConstantCallSite"); throw new UnsupportedOperationException();
} }
/** /**
...@@ -69,6 +111,7 @@ public class ConstantCallSite extends CallSite { ...@@ -69,6 +111,7 @@ public class ConstantCallSite extends CallSite {
* Since that target will never change, this is a correct implementation * Since that target will never change, this is a correct implementation
* of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}. * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
* @return the immutable linkage state of this call site, a constant method handle * @return the immutable linkage state of this call site, a constant method handle
* @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/ */
@Override @Override
public final MethodHandle dynamicInvoker() { public final MethodHandle dynamicInvoker() {
......
...@@ -46,7 +46,10 @@ class Invokers { ...@@ -46,7 +46,10 @@ class Invokers {
// general invoker for the outgoing call // general invoker for the outgoing call
private /*lazy*/ MethodHandle generalInvoker; private /*lazy*/ MethodHandle generalInvoker;
// general invoker for the outgoing call; accepts a single Object[] // general invoker for the outgoing call, uses varargs
private /*lazy*/ MethodHandle varargsInvoker;
// general invoker for the outgoing call; accepts a trailing Object[]
private final /*lazy*/ MethodHandle[] spreadInvokers; private final /*lazy*/ MethodHandle[] spreadInvokers;
// invoker for an unbound callsite // invoker for an unbound callsite
...@@ -67,45 +70,56 @@ class Invokers { ...@@ -67,45 +70,56 @@ class Invokers {
/*non-public*/ MethodHandle exactInvoker() { /*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker; MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker; if (invoker != null) return invoker;
try { invoker = lookupInvoker("invokeExact");
invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
} catch (ReflectiveOperationException ex) {
throw new InternalError("JVM cannot find invoker for "+targetType);
}
assert(invokerType(targetType) == invoker.type());
exactInvoker = invoker; exactInvoker = invoker;
return invoker; return invoker;
} }
/*non-public*/ MethodHandle generalInvoker() { /*non-public*/ MethodHandle generalInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = generalInvoker; MethodHandle invoker = generalInvoker;
if (invoker != null) return invoker; if (invoker != null) return invoker;
MethodType generalType = targetType.generic(); invoker = lookupInvoker("invoke");
invoker = invoker1.asType(invokerType(generalType));
generalInvoker = invoker; generalInvoker = invoker;
return invoker; return invoker;
} }
private MethodHandle lookupInvoker(String name) {
MethodHandle invoker;
try {
invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, name, targetType);
} catch (ReflectiveOperationException ex) {
throw new InternalError("JVM cannot find invoker for "+targetType);
}
assert(invokerType(targetType) == invoker.type());
assert(!invoker.isVarargsCollector());
return invoker;
}
/*non-public*/ MethodHandle erasedInvoker() { /*non-public*/ MethodHandle erasedInvoker() {
MethodHandle invoker1 = exactInvoker(); MethodHandle xinvoker = exactInvoker();
MethodHandle invoker = erasedInvoker; MethodHandle invoker = erasedInvoker;
if (invoker != null) return invoker; if (invoker != null) return invoker;
MethodType erasedType = targetType.erase(); MethodType erasedType = targetType.erase();
if (erasedType == targetType.generic()) invoker = xinvoker.asType(invokerType(erasedType));
invoker = generalInvoker();
else
invoker = invoker1.asType(invokerType(erasedType));
erasedInvoker = invoker; erasedInvoker = invoker;
return invoker; return invoker;
} }
/*non-public*/ MethodHandle spreadInvoker(int objectArgCount) { /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
MethodHandle vaInvoker = spreadInvokers[objectArgCount]; MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
if (vaInvoker != null) return vaInvoker; if (vaInvoker != null) return vaInvoker;
MethodHandle gInvoker = generalInvoker(); MethodHandle gInvoker = generalInvoker();
vaInvoker = gInvoker.asSpreader(Object[].class, targetType.parameterCount() - objectArgCount); int spreadArgCount = targetType.parameterCount() - leadingArgCount;
spreadInvokers[objectArgCount] = vaInvoker; vaInvoker = gInvoker.asSpreader(Object[].class, spreadArgCount);
spreadInvokers[leadingArgCount] = vaInvoker;
return vaInvoker;
}
/*non-public*/ MethodHandle varargsInvoker() {
MethodHandle vaInvoker = varargsInvoker;
if (vaInvoker != null) return vaInvoker;
vaInvoker = spreadInvoker(0).asType(invokerType(MethodType.genericMethodType(0, true)));
varargsInvoker = vaInvoker;
return vaInvoker; return vaInvoker;
} }
......
...@@ -506,8 +506,18 @@ import static java.lang.invoke.MethodHandleStatics.*; ...@@ -506,8 +506,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
if (from != null) message += ", from " + from; if (from != null) message += ", from " + from;
return new IllegalAccessException(message); return new IllegalAccessException(message);
} }
public ReflectiveOperationException makeAccessException(String message) { private String message() {
message = message + ": "+ toString(); if (isResolved())
return "no access";
else if (isConstructor())
return "no such constructor";
else if (isMethod())
return "no such method";
else
return "no such field";
}
public ReflectiveOperationException makeAccessException() {
String message = message() + ": "+ toString();
if (isResolved()) if (isResolved())
return new IllegalAccessException(message); return new IllegalAccessException(message);
else if (isConstructor()) else if (isConstructor())
...@@ -641,7 +651,7 @@ import static java.lang.invoke.MethodHandleStatics.*; ...@@ -641,7 +651,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
MemberName result = resolveOrNull(m, searchSupers, lookupClass); MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null) if (result != null)
return result; return result;
ReflectiveOperationException ex = m.makeAccessException("no access"); ReflectiveOperationException ex = m.makeAccessException();
if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex; if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
throw nsmClass.cast(ex); throw nsmClass.cast(ex);
} }
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
package java.lang.invoke; package java.lang.invoke;
import sun.invoke.util.VerifyType; import sun.invoke.util.VerifyType;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
...@@ -82,12 +84,17 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -82,12 +84,17 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass); DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
if (!mh.isValid()) if (!mh.isValid())
throw method.makeAccessException("no access", lookupClass); throw method.makeAccessException("no direct method handle", lookupClass);
assert(mh.type() == mtype); assert(mh.type() == mtype);
if (!method.isVarargs()) if (!method.isVarargs())
return mh; return mh;
else int argc = mtype.parameterCount();
return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1)); if (argc != 0) {
Class<?> arrayType = mtype.parameterType(argc-1);
if (arrayType.isArray())
return AdapterMethodHandle.makeVarargsCollector(mh, arrayType);
}
throw method.makeAccessException("cannot make variable arity", null);
} }
static static
...@@ -331,18 +338,20 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -331,18 +338,20 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); } void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
// cast (V) is OK here, since we wrap convertArguments around the MH. // cast (V) is OK here, since we wrap convertArguments around the MH.
static Object staticBase(MemberName field) { static Object staticBase(final MemberName field) {
if (!field.isStatic()) return null; if (!field.isStatic()) return null;
Class c = field.getDeclaringClass(); return AccessController.doPrivileged(new PrivilegedAction<Object>() {
java.lang.reflect.Field f; public Object run() {
try { try {
// FIXME: Should not have to create 'f' to get this value. Class c = field.getDeclaringClass();
f = c.getDeclaredField(field.getName()); // FIXME: Should not have to create 'f' to get this value.
// Note: Previous line might invalidly throw SecurityException (7042829) java.lang.reflect.Field f = c.getDeclaredField(field.getName());
return unsafe.staticFieldBase(f); return unsafe.staticFieldBase(f);
} catch (NoSuchFieldException ee) { } catch (NoSuchFieldException ee) {
throw uncaughtException(ee); throw uncaughtException(ee);
} }
}
});
} }
int getStaticI() { return unsafe.getInt(base, offset); } int getStaticI() { return unsafe.getInt(base, offset); }
...@@ -485,14 +494,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -485,14 +494,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
*/ */
static static
MethodHandle bindReceiver(MethodHandle target, Object receiver) { MethodHandle bindReceiver(MethodHandle target, Object receiver) {
if (receiver == null) return null;
if (target instanceof AdapterMethodHandle && if (target instanceof AdapterMethodHandle &&
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
) { ) {
Object info = MethodHandleNatives.getTargetInfo(target); Object info = MethodHandleNatives.getTargetInfo(target);
if (info instanceof DirectMethodHandle) { if (info instanceof DirectMethodHandle) {
DirectMethodHandle dmh = (DirectMethodHandle) info; DirectMethodHandle dmh = (DirectMethodHandle) info;
if (receiver == null || if (dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0); MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
MethodType newType = target.type().dropParameterTypes(0, 1); MethodType newType = target.type().dropParameterTypes(0, 1);
return convertArguments(bmh, newType, bmh.type(), 0); return convertArguments(bmh, newType, bmh.type(), 0);
...@@ -698,7 +707,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -698,7 +707,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if (target == null) throw newIllegalArgumentException("cannot drop"); if (target == null) throw newIllegalArgumentException("cannot drop");
oldType = target.type(); oldType = target.type();
} }
return convertArguments(target, newType, oldType, 0); target = convertArguments(target, newType, oldType, 0);
assert(target != null);
return target;
} }
/*non-public*/ static /*non-public*/ static
...@@ -777,6 +788,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -777,6 +788,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
.insertParameterTypes(keepPosArgs, arrayType); .insertParameterTypes(keepPosArgs, arrayType);
return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength); return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
} }
// called internally only
static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) { static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
int arrayLength = target.type().parameterCount() - spreadArgPos; int arrayLength = target.type().parameterCount() - spreadArgPos;
return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength); return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
...@@ -838,6 +850,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -838,6 +850,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodType ttype = target.type(); MethodType ttype = target.type();
MethodType ftype = filter.type(); MethodType ftype = filter.type();
assert(ftype.parameterCount() == 1); assert(ftype.parameterCount() == 1);
MethodHandle result = null;
if (AdapterMethodHandle.canCollectArguments(ttype, ftype, pos, false)) {
result = AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
if (result != null) return result;
}
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodType rtype = ttype.changeParameterType(pos, ftype.parameterType(0)); MethodType rtype = ttype.changeParameterType(pos, ftype.parameterType(0));
MethodType gttype = ttype.generic(); MethodType gttype = ttype.generic();
if (ttype != gttype) { if (ttype != gttype) {
...@@ -849,18 +867,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -849,18 +867,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
filter = convertArguments(filter, gftype, ftype, 0); filter = convertArguments(filter, gftype, ftype, 0);
ftype = gftype; ftype = gftype;
} }
MethodHandle result = null; if (ftype == ttype) {
if (AdapterMethodHandle.canCollectArguments(ttype, ftype, pos, false)) {
result = AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
}
if (result == null) {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
if (ftype == ttype) {
// simple unary case // simple unary case
result = FilterOneArgument.make(filter, target); result = FilterOneArgument.make(filter, target);
} else { } else {
result = FilterGeneric.makeArgumentFilter(pos, filter, target); result = FilterGeneric.makeArgumentFilter(pos, filter, target);
}
} }
if (result.type() != rtype) if (result.type() != rtype)
result = result.asType(rtype); result = result.asType(rtype);
...@@ -907,24 +918,28 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -907,24 +918,28 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.test = test; this.test = test;
this.target = target; this.target = target;
this.fallback = fallback; this.fallback = fallback;
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
} }
// FIXME: Build the control flow out of foldArguments. static boolean preferRicochetFrame(MethodType type) {
return true; // always use RF if available
}
static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) { static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodType type = target.type(); MethodType type = target.type();
int nargs = type.parameterCount(); int nargs = type.parameterCount();
if (nargs < INVOKES.length) { if (nargs < INVOKES.length) {
if (preferRicochetFrame(type))
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodHandle invoke = INVOKES[nargs]; MethodHandle invoke = INVOKES[nargs];
MethodType gtype = type.generic(); MethodType gtype = type.generic();
assert(invoke.type().dropParameterTypes(0,1) == gtype); assert(invoke.type().dropParameterTypes(0,1) == gtype);
MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), 0); // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
MethodHandle gtarget = convertArguments(target, gtype, type, 0); MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), 2);
MethodHandle gfallback = convertArguments(fallback, gtype, type, 0); MethodHandle gtarget = convertArguments(target, gtype, type, 2);
MethodHandle gfallback = convertArguments(fallback, gtype, type, 2);
if (gtest == null || gtarget == null || gfallback == null) return null; if (gtest == null || gtarget == null || gfallback == null) return null;
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback); MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
return convertArguments(gguard, type, gtype, 0); return convertArguments(gguard, type, gtype, 2);
} else { } else {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodHandle invoke = VARARGS_INVOKE; MethodHandle invoke = VARARGS_INVOKE;
MethodType gtype = MethodType.genericMethodType(1); MethodType gtype = MethodType.genericMethodType(1);
assert(invoke.type().dropParameterTypes(0,1) == gtype); assert(invoke.type().dropParameterTypes(0,1) == gtype);
...@@ -1048,8 +1063,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1048,8 +1063,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// where select(z) = select(z, t, f).bindTo(t, f) => z ? t f // where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
// [tailcall]=> tf(arg...) // [tailcall]=> tf(arg...)
assert(test.type().returnType() == boolean.class); assert(test.type().returnType() == boolean.class);
MethodType foldTargetType = target.type().insertParameterTypes(0, boolean.class); MethodType targetType = target.type();
if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)) { MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)
&& GuardWithTest.preferRicochetFrame(targetType)) {
// working backwards, as usual: // working backwards, as usual:
assert(target.type().equals(fallback.type())); assert(target.type().equals(fallback.type()));
MethodHandle tailcall = MethodHandles.exactInvoker(target.type()); MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
...@@ -1062,7 +1079,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1062,7 +1079,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test); MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
return fold; return fold;
} }
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
return GuardWithTest.make(test, target, fallback); return GuardWithTest.make(test, target, fallback);
} }
...@@ -1206,11 +1222,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1206,11 +1222,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if (nargs < GuardWithCatch.INVOKES.length) { if (nargs < GuardWithCatch.INVOKES.length) {
MethodType gtype = type.generic(); MethodType gtype = type.generic();
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
MethodHandle gtarget = convertArguments(target, gtype, type, 0); // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 0); MethodHandle gtarget = convertArguments(target, gtype, type, 2);
MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 2);
MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher); MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null; if (gtarget == null || gcatcher == null || gguard == null) return null;
return convertArguments(gguard, type, gtype, 0); return convertArguments(gguard, type, gtype, 2);
} else { } else {
MethodType gtype = MethodType.genericMethodType(0, true); MethodType gtype = MethodType.genericMethodType(0, true);
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
......
...@@ -118,32 +118,20 @@ class MethodHandleNatives { ...@@ -118,32 +118,20 @@ class MethodHandleNatives {
/** Derived mode flag. Only false on some old JVM implementations. */ /** Derived mode flag. Only false on some old JVM implementations. */
static final boolean HAVE_RICOCHET_FRAMES; static final boolean HAVE_RICOCHET_FRAMES;
static final int OP_ROT_ARGS_DOWN_LIMIT_BIAS;
private static native void registerNatives(); private static native void registerNatives();
static { static {
int JVM_PUSH_LIMIT_; registerNatives();
int JVM_STACK_MOVE_UNIT_; int k;
int CONV_OP_IMPLEMENTED_MASK_; JVM_PUSH_LIMIT = getConstant(Constants.GC_JVM_PUSH_LIMIT);
try { JVM_STACK_MOVE_UNIT = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
registerNatives(); k = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK);
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT); CONV_OP_IMPLEMENTED_MASK = (k != 0) ? k : DEFAULT_CONV_OP_IMPLEMENTED_MASK;
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT); k = getConstant(Constants.GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS);
CONV_OP_IMPLEMENTED_MASK_ = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK); OP_ROT_ARGS_DOWN_LIMIT_BIAS = (k != 0) ? (byte)k : -1;
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); HAVE_RICOCHET_FRAMES = (CONV_OP_IMPLEMENTED_MASK & (1<<OP_COLLECT_ARGS)) != 0;
} catch (UnsatisfiedLinkError ee) { //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
// ignore; if we use init() methods later we'll see linkage errors
JVM_PUSH_LIMIT_ = 3; // arbitrary
JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
CONV_OP_IMPLEMENTED_MASK_ = 0;
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
throw ee; // just die; hopeless to try to run with an older JVM
}
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
if (CONV_OP_IMPLEMENTED_MASK_ == 0)
CONV_OP_IMPLEMENTED_MASK_ = DEFAULT_CONV_OP_IMPLEMENTED_MASK;
CONV_OP_IMPLEMENTED_MASK = CONV_OP_IMPLEMENTED_MASK_;
HAVE_RICOCHET_FRAMES = (CONV_OP_IMPLEMENTED_MASK & (1<<OP_COLLECT_ARGS)) != 0;
} }
// All compile-time constants go here. // All compile-time constants go here.
...@@ -154,7 +142,8 @@ class MethodHandleNatives { ...@@ -154,7 +142,8 @@ class MethodHandleNatives {
static final int // for getConstant static final int // for getConstant
GC_JVM_PUSH_LIMIT = 0, GC_JVM_PUSH_LIMIT = 0,
GC_JVM_STACK_MOVE_UNIT = 1, GC_JVM_STACK_MOVE_UNIT = 1,
GC_CONV_OP_IMPLEMENTED_MASK = 2; GC_CONV_OP_IMPLEMENTED_MASK = 2,
GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS = 3;
static final int static final int
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
...@@ -359,6 +348,12 @@ class MethodHandleNatives { ...@@ -359,6 +348,12 @@ class MethodHandleNatives {
required = Object[].class; // should have been an array required = Object[].class; // should have been an array
code = 192; // checkcast code = 192; // checkcast
break; break;
case 191: // athrow
// JVM is asking us to wrap an exception which happened during resolving
if (required == BootstrapMethodError.class) {
throw new BootstrapMethodError((Throwable) actual);
}
break;
} }
// disregard the identity of the actual object, if it is not a class: // disregard the identity of the actual object, if it is not a class:
if (message == null) { if (message == null) {
...@@ -389,18 +384,7 @@ class MethodHandleNatives { ...@@ -389,18 +384,7 @@ class MethodHandleNatives {
Class<?> defc, String name, Object type) { Class<?> defc, String name, Object type) {
try { try {
Lookup lookup = IMPL_LOOKUP.in(callerClass); Lookup lookup = IMPL_LOOKUP.in(callerClass);
switch (refKind) { return lookup.linkMethodHandleConstant(refKind, defc, name, type);
case REF_getField: return lookup.findGetter( defc, name, (Class<?>) type );
case REF_getStatic: return lookup.findStaticGetter( defc, name, (Class<?>) type );
case REF_putField: return lookup.findSetter( defc, name, (Class<?>) type );
case REF_putStatic: return lookup.findStaticSetter( defc, name, (Class<?>) type );
case REF_invokeVirtual: return lookup.findVirtual( defc, name, (MethodType) type );
case REF_invokeStatic: return lookup.findStatic( defc, name, (MethodType) type );
case REF_invokeSpecial: return lookup.findSpecial( defc, name, (MethodType) type, callerClass );
case REF_newInvokeSpecial: return lookup.findConstructor( defc, (MethodType) type );
case REF_invokeInterface: return lookup.findVirtual( defc, name, (MethodType) type );
}
throw new IllegalArgumentException("bad MethodHandle constant "+name+" : "+type);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
Error err = new IncompatibleClassChangeError(); Error err = new IncompatibleClassChangeError();
err.initCause(ex); err.initCause(ex);
......
/*
* Copyright (c) 2008, 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 java.lang.reflect.*;
import sun.invoke.WrapperInstance;
/**
* This class consists exclusively of static methods that help adapt
* method handles to other JVM types, such as interfaces.
*/
public class MethodHandleProxies {
private MethodHandleProxies() { } // do not instantiate
/**
* Produces an instance of the given single-method interface which redirects
* its calls to the given method handle.
* <p>
* A single-method interface is an interface which declares a uniquely named method.
* When determining the uniquely named method of a single-method interface,
* the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
* are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
* even though it re-declares the {@code Object.equals} method.
* <p>
* The interface must be public. No additional access checks are performed.
* <p>
* The resulting instance of the required type will respond to
* invocation of the type's uniquely named method by calling
* the given target on the incoming arguments,
* and returning or throwing whatever the target
* returns or throws. The invocation will be as if by
* {@code target.invoke}.
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
* <p>
* The uniquely named method is allowed to be multiply declared,
* with distinct type descriptors. (E.g., it can be overloaded,
* or can possess bridge methods.) All such declarations are
* connected directly to the target method handle.
* Argument and return types are adjusted by {@code asType}
* for each individual declaration.
* <p>
* The wrapper instance will implement the requested interface
* and its super-types, but no other single-method interfaces.
* This means that the instance will not unexpectedly
* pass an {@code instanceof} test for any unrequested type.
* <p style="font-size:smaller;">
* <em>Implementation Note:</em>
* Therefore, each instance must implement a unique single-method interface.
* Implementations may not bundle together
* multiple single-method interfaces onto single implementation classes
* in the style of {@link java.awt.AWTEventMulticaster}.
* <p>
* The method handle may throw an <em>undeclared exception</em>,
* which means any checked exception (or other checked throwable)
* not declared by the requested type's single abstract method.
* If this happens, the throwable will be wrapped in an instance of
* {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
* and thrown in that wrapped form.
* <p>
* Like {@link java.lang.Integer#valueOf Integer.valueOf},
* {@code asInterfaceInstance} is a factory method whose results are defined
* by their behavior.
* It is not guaranteed to return a new instance for every call.
* <p>
* Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
* and other corner cases, the interface may also have several abstract methods
* with the same name but having distinct descriptors (types of returns and parameters).
* In this case, all the methods are bound in common to the one given target.
* The type check and effective {@code asType} conversion is applied to each
* method type descriptor, and all abstract methods are bound to the target in common.
* Beyond this type check, no further checks are made to determine that the
* abstract methods are related in any way.
* <p>
* Future versions of this API may accept additional types,
* 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.
*
* @param target the method handle to invoke from the wrapper
* @param intfc the desired type of the wrapper, a single-method interface
* @return a correctly-typed wrapper for the given target
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the {@code intfc} is not a
* valid argument to this method
* @throws WrongMethodTypeException if the target cannot
* be converted to the type required by the requested interface
*/
// Other notes to implementors:
// <p>
// No stable mapping is promised between the single-method interface and
// the implementation class C. Over time, several implementation
// classes might be used for the same type.
// <p>
// If the implementation is able
// to prove that a wrapper of the required type
// has already been created for a given
// method handle, or for another method handle with the
// same behavior, the implementation may return that wrapper in place of
// a new wrapper.
// <p>
// This method is designed to apply to common use cases
// where a single method handle must interoperate with
// an interface that implements a function-like
// API. Additional variations, such as single-abstract-method classes with
// private constructors, or interfaces with multiple but related
// entry points, must be covered by hand-written or automatically
// generated adapter classes.
//
public static
<T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
// POC implementation only; violates the above contract several ways
final Method sm = getSingleMethod(intfc);
if (sm == null)
throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
MethodHandle checkTarget = target.asType(smMT); // make throw WMT
checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
return intfc.cast(Proxy.newProxyInstance(
intfc.getClassLoader(),
new Class[]{ intfc, WrapperInstance.class },
new InvocationHandler() {
private Object getArg(String name) {
if ((Object)name == "getWrapperInstanceTarget") return target;
if ((Object)name == "getWrapperInstanceType") return intfc;
throw new AssertionError();
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == WrapperInstance.class)
return getArg(method.getName());
if (method.equals(sm))
return vaTarget.invokeExact(args);
if (isObjectMethod(method))
return callObjectMethod(this, method, args);
throw new InternalError();
}
}));
}
/**
* Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* @param x any reference
* @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
*/
public static
boolean isWrapperInstance(Object x) {
return x instanceof WrapperInstance;
}
private static WrapperInstance asWrapperInstance(Object x) {
try {
if (x != null)
return (WrapperInstance) x;
} catch (ClassCastException ex) {
}
throw new IllegalArgumentException("not a wrapper instance");
}
/**
* Produces or recovers a target method handle which is behaviorally
* equivalent to the unique method of this wrapper instance.
* The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return a method handle implementing the unique method
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public static
MethodHandle wrapperInstanceTarget(Object x) {
return asWrapperInstance(x).getWrapperInstanceTarget();
}
/**
* Recovers the unique single-method interface type for which this wrapper instance was created.
* The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return the single-method interface type for which the wrapper was created
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public static
Class<?> wrapperInstanceType(Object x) {
return asWrapperInstance(x).getWrapperInstanceType();
}
private static
boolean isObjectMethod(Method m) {
switch (m.getName()) {
case "toString":
return (m.getReturnType() == String.class
&& m.getParameterTypes().length == 0);
case "hashCode":
return (m.getReturnType() == int.class
&& m.getParameterTypes().length == 0);
case "equals":
return (m.getReturnType() == boolean.class
&& m.getParameterTypes().length == 1
&& m.getParameterTypes()[0] == Object.class);
}
return false;
}
private static
Object callObjectMethod(Object self, Method m, Object[] args) {
assert(isObjectMethod(m)) : m;
switch (m.getName()) {
case "toString":
return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
case "hashCode":
return System.identityHashCode(self);
case "equals":
return (self == args[0]);
}
return null;
}
private static
Method getSingleMethod(Class<?> intfc) {
if (!intfc.isInterface()) return null;
Method sm = null;
for (Method m : intfc.getMethods()) {
int mod = m.getModifiers();
if (Modifier.isAbstract(mod)) {
if (sm != null && !isObjectMethod(sm))
return null; // too many abstract methods
sm = m;
}
}
return sm;
}
}
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
package java.lang.invoke; package java.lang.invoke;
import java.security.AccessController;
import java.security.PrivilegedAction;
/** /**
* This class consists exclusively of static names internal to the * This class consists exclusively of static names internal to the
* method handle implementation. * method handle implementation.
...@@ -35,7 +38,17 @@ package java.lang.invoke; ...@@ -35,7 +38,17 @@ package java.lang.invoke;
private MethodHandleStatics() { } // do not instantiate private MethodHandleStatics() { } // do not instantiate
static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); static final boolean DEBUG_METHOD_HANDLE_NAMES;
static {
final Object[] values = { false };
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
return null;
}
});
DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0];
}
/*non-public*/ static String getNameString(MethodHandle target, MethodType type) { /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
if (type == null) if (type == null)
......
...@@ -273,7 +273,7 @@ class MethodType implements java.io.Serializable { ...@@ -273,7 +273,7 @@ class MethodType implements java.io.Serializable {
* @param objectArgCount number of parameters (excluding the final array parameter if any) * @param objectArgCount number of parameters (excluding the final array parameter if any)
* @param finalArray whether there will be a trailing array parameter, of type {@code Object[]} * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
* @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
* @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray}) * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
* @see #genericMethodType(int) * @see #genericMethodType(int)
*/ */
public static public static
...@@ -455,7 +455,8 @@ class MethodType implements java.io.Serializable { ...@@ -455,7 +455,8 @@ class MethodType implements java.io.Serializable {
/** /**
* Reports if this type contains a wrapper argument or return value. * Reports if this type contains a wrapper argument or return value.
* Wrappers are types which box primitive values, such as {@link Integer}. * Wrappers are types which box primitive values, such as {@link Integer}.
* The reference type {@code java.lang.Void} counts as a wrapper. * The reference type {@code java.lang.Void} counts as a wrapper,
* if it occurs as a return type.
* @return true if any of the types are wrappers * @return true if any of the types are wrappers
*/ */
public boolean hasWrappers() { public boolean hasWrappers() {
...@@ -649,13 +650,55 @@ class MethodType implements java.io.Serializable { ...@@ -649,13 +650,55 @@ class MethodType implements java.io.Serializable {
} }
/*non-public*/ /*non-public*/
static boolean canConvert(Class<?> src, Class<?> dst) { static boolean canConvert(Class<?> src, Class<?> dst) {
if (src == dst || dst == void.class) return true; // short-circuit a few cases:
if (src.isPrimitive() && dst.isPrimitive()) { if (src == dst || dst == Object.class) return true;
if (!Wrapper.forPrimitiveType(dst) // the remainder of this logic is documented in MethodHandle.asType
.isConvertibleFrom(Wrapper.forPrimitiveType(src))) if (src.isPrimitive()) {
// can force void to an explicit null, a la reflect.Method.invoke
// can also force void to a primitive zero, by analogy
if (src == void.class) return true; //or !dst.isPrimitive()?
Wrapper sw = Wrapper.forPrimitiveType(src);
if (dst.isPrimitive()) {
// P->P must widen
return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
} else {
// P->R must box and widen
return dst.isAssignableFrom(sw.wrapperType());
}
} else if (dst.isPrimitive()) {
// any value can be dropped
if (dst == void.class) return true;
Wrapper dw = Wrapper.forPrimitiveType(dst);
// R->P must be able to unbox (from a dynamically chosen type) and widen
// For example:
// Byte/Number/Comparable/Object -> dw:Byte -> byte.
// Character/Comparable/Object -> dw:Character -> char
// Boolean/Comparable/Object -> dw:Boolean -> boolean
// This means that dw must be cast-compatible with src.
if (src.isAssignableFrom(dw.wrapperType())) {
return true;
}
// The above does not work if the source reference is strongly typed
// to a wrapper whose primitive must be widened. For example:
// Byte -> unbox:byte -> short/int/long/float/double
// Character -> unbox:char -> int/long/float/double
if (Wrapper.isWrapperType(src) &&
dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
// can unbox from src and then widen to dst
return true;
}
// We have already covered cases which arise due to runtime unboxing
// of a reference type which covers several wrapper types:
// Object -> cast:Integer -> unbox:int -> long/float/double
// Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
// An marginal case is Number -> dw:Character -> char, which would be OK if there were a
// subclass of Number which wraps a value that can convert to char.
// Since there is none, we don't need an extra check here to cover char or boolean.
return false; return false;
} else {
// R->R always works, since null is always valid dynamically
return true;
} }
return true;
} }
/// Queries which have to do with the bytecode architecture /// Queries which have to do with the bytecode architecture
...@@ -740,6 +783,7 @@ class MethodType implements java.io.Serializable { ...@@ -740,6 +783,7 @@ class MethodType implements java.io.Serializable {
* @param descriptor a bytecode-level type descriptor string "(T...)T" * @param descriptor a bytecode-level type descriptor string "(T...)T"
* @param loader the class loader in which to look up the types * @param loader the class loader in which to look up the types
* @return a method type matching the bytecode-level type descriptor * @return a method type matching the bytecode-level type descriptor
* @throws NullPointerException if the string is null
* @throws IllegalArgumentException if the string is not well-formed * @throws IllegalArgumentException if the string is not well-formed
* @throws TypeNotPresentException if a named type cannot be found * @throws TypeNotPresentException if a named type cannot be found
*/ */
......
...@@ -37,12 +37,13 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -37,12 +37,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p> * <p>
* Here is an example of a mutable call site which introduces a * Here is an example of a mutable call site which introduces a
* state variable into a method handle chain. * state variable into a method handle chain.
* <!-- JavaDocExamplesTest.testMutableCallSite -->
* <blockquote><pre> * <blockquote><pre>
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class)); MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker(); MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str2 = MethodType.methodType(String.class, String.class); MethodType MT_str1 = MethodType.methodType(String.class);
MethodHandle MH_upcase = MethodHandles.lookup() MethodHandle MH_upcase = MethodHandles.lookup()
.findVirtual(String.class, "toUpperCase", MT_str2); .findVirtual(String.class, "toUpperCase", MT_str1);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase); MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky")); name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact()); assertEquals("ROCKY", (String) worker1.invokeExact());
...@@ -53,8 +54,10 @@ assertEquals("FRED", (String) worker1.invokeExact()); ...@@ -53,8 +54,10 @@ assertEquals("FRED", (String) worker1.invokeExact());
* <p> * <p>
* The same call site may be used in several places at once. * The same call site may be used in several places at once.
* <blockquote><pre> * <blockquote><pre>
MethodHandle MH_dear = MethodHandles.lookup() MethodType MT_str2 = MethodType.methodType(String.class, String.class);
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?"); MethodHandle MH_cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear); MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
assertEquals("Fred, dear?", (String) worker2.invokeExact()); assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma")); name.setTarget(MethodHandles.constant(String.class, "Wilma"));
......
...@@ -56,16 +56,17 @@ package java.lang.invoke; ...@@ -56,16 +56,17 @@ package java.lang.invoke;
* <p> * <p>
* Here is an example of a switch point in action: * Here is an example of a switch point in action:
* <blockquote><pre> * <blockquote><pre>
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_strcat = MethodHandles.lookup() MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2); .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
SwitchPoint spt = new SwitchPoint(); SwitchPoint spt = new SwitchPoint();
assert(!spt.hasBeenInvalidated());
// the following steps may be repeated to re-use the same switch point: // the following steps may be repeated to re-use the same switch point:
MethodHandle worker1 = strcat; MethodHandle worker1 = MH_strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0); MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
MethodHandle worker = spt.guardWithTest(worker1, worker2); MethodHandle worker = spt.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod")); assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt }); SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(spt.hasBeenInvalidated());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod")); assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote> * </pre></blockquote>
* <p style="font-size:smaller;"> * <p style="font-size:smaller;">
...@@ -124,6 +125,33 @@ public class SwitchPoint { ...@@ -124,6 +125,33 @@ public class SwitchPoint {
this.mcsInvoker = mcs.dynamicInvoker(); this.mcsInvoker = mcs.dynamicInvoker();
} }
/**
* Determines if this switch point has been invalidated yet.
*
* <p style="font-size:smaller;">
* <em>Discussion:</em>
* Because of the one-way nature of invalidation, once a switch point begins
* to return true for {@code hasBeenInvalidated},
* it will always do so in the future.
* On the other hand, a valid switch point visible to other threads may
* be invalidated at any moment, due to a request by another thread.
* <p style="font-size:smaller;">
* Since invalidation is a global and immediate operation,
* the execution of this query, on a valid switchpoint,
* must be internally sequenced with any
* other threads that could cause invalidation.
* This query may therefore be expensive.
* The recommended way to build a boolean-valued method handle
* which queries the invalidation state of a switch point {@code s} is
* to call {@code s.guardWithTest} on
* {@link MethodHandles#constant constant} true and false method handles.
*
* @return true if this switch point has been invalidated
*/
public boolean hasBeenInvalidated() {
return (mcs.getTarget() != K_true);
}
/** /**
* Returns a method handle which always delegates either to the target or the fallback. * Returns a method handle which always delegates either to the target or the fallback.
* The method handle will delegate to the target exactly as long as the switch point is valid. * The method handle will delegate to the target exactly as long as the switch point is valid.
...@@ -136,6 +164,7 @@ public class SwitchPoint { ...@@ -136,6 +164,7 @@ public class SwitchPoint {
* @param fallback the method handle selected by the switch point after it is invalidated * @param fallback the method handle selected by the switch point after it is invalidated
* @return a combined method handle which always calls either the target or fallback * @return a combined method handle which always calls either the target or fallback
* @throws NullPointerException if either argument is null * @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the two method types do not match
* @see MethodHandles#guardWithTest * @see MethodHandles#guardWithTest
*/ */
public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) { public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
......
...@@ -1013,6 +1013,12 @@ class InetAddress implements java.io.Serializable { ...@@ -1013,6 +1013,12 @@ class InetAddress implements java.io.Serializable {
return InetAddress.getAllByName(host)[0]; return InetAddress.getAllByName(host)[0];
} }
// called from deployment cache manager
private static InetAddress getByName(String host, InetAddress reqAddr)
throws UnknownHostException {
return InetAddress.getAllByName(host, reqAddr)[0];
}
/** /**
* Given the name of a host, returns an array of its IP addresses, * Given the name of a host, returns an array of its IP addresses,
* based on the configured name service on the system. * based on the configured name service on the system.
...@@ -1054,6 +1060,11 @@ class InetAddress implements java.io.Serializable { ...@@ -1054,6 +1060,11 @@ class InetAddress implements java.io.Serializable {
*/ */
public static InetAddress[] getAllByName(String host) public static InetAddress[] getAllByName(String host)
throws UnknownHostException { throws UnknownHostException {
return getAllByName(host, null);
}
private static InetAddress[] getAllByName(String host, InetAddress reqAddr)
throws UnknownHostException {
if (host == null || host.length() == 0) { if (host == null || host.length() == 0) {
InetAddress[] ret = new InetAddress[1]; InetAddress[] ret = new InetAddress[1];
...@@ -1113,7 +1124,7 @@ class InetAddress implements java.io.Serializable { ...@@ -1113,7 +1124,7 @@ class InetAddress implements java.io.Serializable {
// We were expecting an IPv6 Litteral, but got something else // We were expecting an IPv6 Litteral, but got something else
throw new UnknownHostException("["+host+"]"); throw new UnknownHostException("["+host+"]");
} }
return getAllByName0(host); return getAllByName0(host, reqAddr, true);
} }
/** /**
...@@ -1174,6 +1185,12 @@ class InetAddress implements java.io.Serializable { ...@@ -1174,6 +1185,12 @@ class InetAddress implements java.io.Serializable {
*/ */
static InetAddress[] getAllByName0 (String host, boolean check) static InetAddress[] getAllByName0 (String host, boolean check)
throws UnknownHostException { throws UnknownHostException {
return getAllByName0 (host, null, check);
}
private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)
throws UnknownHostException {
/* If it gets here it is presumed to be a hostname */ /* If it gets here it is presumed to be a hostname */
/* Cache.get can return: null, unknownAddress, or InetAddress[] */ /* Cache.get can return: null, unknownAddress, or InetAddress[] */
...@@ -1191,7 +1208,7 @@ class InetAddress implements java.io.Serializable { ...@@ -1191,7 +1208,7 @@ class InetAddress implements java.io.Serializable {
/* If no entry in cache, then do the host lookup */ /* If no entry in cache, then do the host lookup */
if (addresses == null) { if (addresses == null) {
addresses = getAddressesFromNameService(host); addresses = getAddressesFromNameService(host, reqAddr);
} }
if (addresses == unknown_array) if (addresses == unknown_array)
...@@ -1200,7 +1217,7 @@ class InetAddress implements java.io.Serializable { ...@@ -1200,7 +1217,7 @@ class InetAddress implements java.io.Serializable {
return addresses.clone(); return addresses.clone();
} }
private static InetAddress[] getAddressesFromNameService(String host) private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
throws UnknownHostException throws UnknownHostException
{ {
InetAddress[] addresses = null; InetAddress[] addresses = null;
...@@ -1256,10 +1273,32 @@ class InetAddress implements java.io.Serializable { ...@@ -1256,10 +1273,32 @@ class InetAddress implements java.io.Serializable {
} }
} }
// Cache the addresses. // More to do?
if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
// Find it?
int i = 1;
for (; i < addresses.length; i++) {
if (addresses[i].equals(reqAddr)) {
break;
}
}
// Rotate
if (i < addresses.length) {
InetAddress tmp, tmp2 = reqAddr;
for (int j = 0; j < i; j++) {
tmp = addresses[j];
addresses[j] = tmp2;
tmp2 = tmp;
}
addresses[i] = tmp2;
}
}
// Cache the address.
cacheAddresses(host, addresses, success); cacheAddresses(host, addresses, success);
if (!success && ex != null) if (!success && ex != null)
throw ex; throw ex;
} finally { } finally {
// Delete host from the lookupTable and notify // Delete host from the lookupTable and notify
// all threads waiting on the lookupTable monitor. // all threads waiting on the lookupTable monitor.
...@@ -1393,7 +1432,7 @@ class InetAddress implements java.io.Serializable { ...@@ -1393,7 +1432,7 @@ class InetAddress implements java.io.Serializable {
InetAddress[] localAddrs; InetAddress[] localAddrs;
try { try {
localAddrs = localAddrs =
InetAddress.getAddressesFromNameService(local); InetAddress.getAddressesFromNameService(local, null);
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
// Rethrow with a more informative error message. // Rethrow with a more informative error message.
UnknownHostException uhe2 = UnknownHostException uhe2 =
......
...@@ -547,13 +547,8 @@ public final class NetworkInterface { ...@@ -547,13 +547,8 @@ public final class NetworkInterface {
if (displayName != null) { if (displayName != null) {
result += " (" + displayName + ")"; result += " (" + displayName + ")";
} }
result += " index: "+index+" addresses:\n";
for (Enumeration e = getInetAddresses(); e.hasMoreElements(); ) {
InetAddress addr = (InetAddress)e.nextElement();
result += addr+";\n";
}
return result; return result;
} }
private static native void init();
private static native void init();
} }
...@@ -127,11 +127,12 @@ class Socket implements java.io.Closeable { ...@@ -127,11 +127,12 @@ class Socket implements java.io.Closeable {
} }
if (security != null) { if (security != null) {
if (epoint.isUnresolved()) if (epoint.isUnresolved())
security.checkConnect(epoint.getHostName(), epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort());
epoint.getPort()); if (epoint.isUnresolved())
security.checkConnect(epoint.getHostName(), epoint.getPort());
else else
security.checkConnect(epoint.getAddress().getHostAddress(), security.checkConnect(epoint.getAddress().getHostAddress(),
epoint.getPort()); epoint.getPort());
} }
impl = new SocksSocketImpl(p); impl = new SocksSocketImpl(p);
impl.setSocket(this); impl.setSocket(this);
......
...@@ -40,7 +40,9 @@ import java.io.ObjectOutputStream; ...@@ -40,7 +40,9 @@ import java.io.ObjectOutputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.IOException; import java.io.IOException;
import sun.net.util.IPAddressUtil; import sun.net.util.IPAddressUtil;
import sun.net.RegisteredDomain;
import sun.security.util.SecurityConstants; import sun.security.util.SecurityConstants;
import sun.security.util.Debug;
/** /**
...@@ -211,13 +213,32 @@ implements java.io.Serializable ...@@ -211,13 +213,32 @@ implements java.io.Serializable
// port range on host // port range on host
private transient int[] portrange; private transient int[] portrange;
// true if the trustProxy system property is set private transient boolean defaultDeny = false;
private static boolean trustProxy;
// true if this SocketPermission represents a hostname
// that failed our reverse mapping heuristic test
private transient boolean untrusted;
private transient boolean trusted;
// true if the sun.net.trustNameService system property is set
private static boolean trustNameService;
private static Debug debug = null;
private static boolean debugInit = false;
static { static {
Boolean tmp = java.security.AccessController.doPrivileged( Boolean tmp = java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction("trustProxy")); new sun.security.action.GetBooleanAction("sun.net.trustNameService"));
trustProxy = tmp.booleanValue(); trustNameService = tmp.booleanValue();
}
private static synchronized Debug getDebug()
{
if (!debugInit) {
debug = Debug.getInstance("access");
debugInit = true;
}
return debug;
} }
/** /**
...@@ -263,6 +284,10 @@ implements java.io.Serializable ...@@ -263,6 +284,10 @@ implements java.io.Serializable
init(getName(), mask); init(getName(), mask);
} }
private void setDeny() {
defaultDeny = true;
}
private static String getHost(String host) private static String getHost(String host)
{ {
if (host.equals("")) { if (host.equals("")) {
...@@ -560,6 +585,37 @@ implements java.io.Serializable ...@@ -560,6 +585,37 @@ implements java.io.Serializable
return mask; return mask;
} }
private boolean isUntrusted()
throws UnknownHostException
{
if (trusted) return false;
if (invalid || untrusted) return true;
try {
if (!trustNameService && (defaultDeny ||
sun.net.www.URLConnection.isProxiedHost(hostname))) {
if (this.cname == null) {
this.getCanonName();
}
if (!match(cname, hostname)) {
// Last chance
if (!authorized(hostname, addresses[0].getAddress())) {
untrusted = true;
Debug debug = getDebug();
if (debug != null && Debug.isOn("failure")) {
debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup");
}
return true;
}
}
trusted = true;
}
} catch (UnknownHostException uhe) {
invalid = true;
throw uhe;
}
return false;
}
/** /**
* attempt to get the fully qualified domain name * attempt to get the fully qualified domain name
* *
...@@ -567,7 +623,7 @@ implements java.io.Serializable ...@@ -567,7 +623,7 @@ implements java.io.Serializable
void getCanonName() void getCanonName()
throws UnknownHostException throws UnknownHostException
{ {
if (cname != null || invalid) return; if (cname != null || invalid || untrusted) return;
// attempt to get the canonical name // attempt to get the canonical name
...@@ -593,6 +649,96 @@ implements java.io.Serializable ...@@ -593,6 +649,96 @@ implements java.io.Serializable
} }
} }
private transient String cdomain, hdomain;
private boolean match(String cname, String hname) {
String a = cname.toLowerCase();
String b = hname.toLowerCase();
if (a.startsWith(b) &&
((a.length() == b.length()) || (a.charAt(b.length()) == '.')))
return true;
if (cdomain == null) {
cdomain = RegisteredDomain.getRegisteredDomain(a);
}
if (hdomain == null) {
hdomain = RegisteredDomain.getRegisteredDomain(b);
}
return cdomain.length() != 0 && hdomain.length() != 0
&& cdomain.equals(hdomain);
}
private boolean authorized(String cname, byte[] addr) {
if (addr.length == 4)
return authorizedIPv4(cname, addr);
else if (addr.length == 16)
return authorizedIPv6(cname, addr);
else
return false;
}
private boolean authorizedIPv4(String cname, byte[] addr) {
String authHost = "";
InetAddress auth;
try {
authHost = "auth." +
(addr[3] & 0xff) + "." + (addr[2] & 0xff) + "." +
(addr[1] & 0xff) + "." + (addr[0] & 0xff) +
".in-addr.arpa";
// Following check seems unnecessary
// auth = InetAddress.getAllByName0(authHost, false)[0];
authHost = hostname + '.' + authHost;
auth = InetAddress.getAllByName0(authHost, false)[0];
if (auth.equals(InetAddress.getByAddress(addr))) {
return true;
}
Debug debug = getDebug();
if (debug != null && Debug.isOn("failure")) {
debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
}
} catch (UnknownHostException uhe) {
Debug debug = getDebug();
if (debug != null && Debug.isOn("failure")) {
debug.println("socket access restriction: forward lookup failed for " + authHost);
}
}
return false;
}
private boolean authorizedIPv6(String cname, byte[] addr) {
String authHost = "";
InetAddress auth;
try {
StringBuffer sb = new StringBuffer(39);
for (int i = 15; i >= 0; i--) {
sb.append(Integer.toHexString(((addr[i]) & 0x0f)));
sb.append('.');
sb.append(Integer.toHexString(((addr[i] >> 4) & 0x0f)));
sb.append('.');
}
authHost = "auth." + sb.toString() + "IP6.ARPA";
//auth = InetAddress.getAllByName0(authHost, false)[0];
authHost = hostname + '.' + authHost;
auth = InetAddress.getAllByName0(authHost, false)[0];
if (auth.equals(InetAddress.getByAddress(addr)))
return true;
Debug debug = getDebug();
if (debug != null && Debug.isOn("failure")) {
debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
}
} catch (UnknownHostException uhe) {
Debug debug = getDebug();
if (debug != null && Debug.isOn("failure")) {
debug.println("socket access restriction: forward lookup failed for " + authHost);
}
}
return false;
}
/** /**
* get IP addresses. Sets invalid to true if we can't get them. * get IP addresses. Sets invalid to true if we can't get them.
* *
...@@ -720,12 +866,7 @@ implements java.io.Serializable ...@@ -720,12 +866,7 @@ implements java.io.Serializable
// return if either one of these NetPerm objects are invalid... // return if either one of these NetPerm objects are invalid...
if (this.invalid || that.invalid) { if (this.invalid || that.invalid) {
return (trustProxy ? inProxyWeTrust(that) : false); return compareHostnames(that);
}
if (this.getName().equalsIgnoreCase(that.getName())) {
return true;
} }
try { try {
...@@ -778,28 +919,29 @@ implements java.io.Serializable ...@@ -778,28 +919,29 @@ implements java.io.Serializable
that.getIP(); that.getIP();
} }
for (j = 0; j < this.addresses.length; j++) { if (!(that.init_with_ip && this.isUntrusted())) {
for (i=0; i < that.addresses.length; i++) { for (j = 0; j < this.addresses.length; j++) {
if (this.addresses[j].equals(that.addresses[i])) for (i=0; i < that.addresses.length; i++) {
return true; if (this.addresses[j].equals(that.addresses[i]))
return true;
}
} }
}
// XXX: if all else fails, compare hostnames? // XXX: if all else fails, compare hostnames?
// Do we really want this? // Do we really want this?
if (this.cname == null) { if (this.cname == null) {
this.getCanonName(); this.getCanonName();
} }
if (that.cname == null) { if (that.cname == null) {
that.getCanonName(); that.getCanonName();
} }
return (this.cname.equalsIgnoreCase(that.cname)); return (this.cname.equalsIgnoreCase(that.cname));
}
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
if (trustProxy) return compareHostnames(that);
return inProxyWeTrust(that);
} }
// make sure the first thing that is done here is to return // make sure the first thing that is done here is to return
...@@ -808,9 +950,8 @@ implements java.io.Serializable ...@@ -808,9 +950,8 @@ implements java.io.Serializable
return false; return false;
} }
private boolean inProxyWeTrust(SocketPermission that) { private boolean compareHostnames(SocketPermission that) {
// if we trust the proxy, we see if the original names/IPs passed // we see if the original names/IPs passed in were equal.
// in were equal.
String thisHost = hostname; String thisHost = hostname;
String thatHost = that.hostname; String thatHost = that.hostname;
...@@ -819,8 +960,8 @@ implements java.io.Serializable ...@@ -819,8 +960,8 @@ implements java.io.Serializable
return false; return false;
else else
return thisHost.equalsIgnoreCase(thatHost); return thisHost.equalsIgnoreCase(thatHost);
} }
/** /**
* Checks two SocketPermission objects for equality. * Checks two SocketPermission objects for equality.
* <P> * <P>
......
...@@ -460,15 +460,13 @@ public interface Path ...@@ -460,15 +460,13 @@ public interface Path
/** /**
* Returns a URI to represent this path. * Returns a URI to represent this path.
* *
* <p> This method constructs a hierarchical {@link URI} that is absolute * <p> This method constructs an absolute {@link URI} with a {@link
* with a non-empty path component. Its {@link URI#getScheme() scheme} is * URI#getScheme() scheme} equal to the URI scheme that identifies the
* equal to the URI scheme that identifies the provider. The exact form of * provider. The exact form of the scheme specific part is highly provider
* the other URI components is highly provider dependent. In particular, it * dependent.
* is implementation dependent if its query, fragment, and authority *
* components are defined or undefined. * <p> In the case of the default provider, the URI is hierarchical with
* * a {@link URI#getPath() path} component that is absolute. The query and
* <p> For the default provider the {@link URI#getPath() path} component
* will represent the {@link #toAbsolutePath absolute} path; the query,
* fragment components are undefined. Whether the authority component is * fragment components are undefined. Whether the authority component is
* defined or not is implementation dependent. There is no guarantee that * defined or not is implementation dependent. There is no guarantee that
* the {@code URI} may be used to construct a {@link java.io.File java.io.File}. * the {@code URI} may be used to construct a {@link java.io.File java.io.File}.
...@@ -497,7 +495,7 @@ public interface Path ...@@ -497,7 +495,7 @@ public interface Path
* A format for compound URIs is not defined in this release; such a scheme * A format for compound URIs is not defined in this release; such a scheme
* may be added in a future release. * may be added in a future release.
* *
* @return an absolute, hierarchical URI with a non-empty path component * @return the URI representing this path
* *
* @throws java.io.IOError * @throws java.io.IOError
* if an I/O error occurs obtaining the absolute path, or where a * if an I/O error occurs obtaining the absolute path, or where a
......
/* /*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -249,10 +249,10 @@ public final class SignedObject implements Serializable { ...@@ -249,10 +249,10 @@ public final class SignedObject implements Serializable {
* a stream. * a stream.
*/ */
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException throws java.io.IOException, ClassNotFoundException {
{ java.io.ObjectInputStream.GetField fields = s.readFields();
s.defaultReadObject(); content = ((byte[])fields.get("content", null)).clone();
content = content.clone(); signature = ((byte[])fields.get("signature", null)).clone();
signature = signature.clone(); thealgorithm = (String)fields.get("thealgorithm", null);
} }
} }
...@@ -79,7 +79,8 @@ public class BatchUpdateException extends SQLException { ...@@ -79,7 +79,8 @@ public class BatchUpdateException extends SQLException {
*/ */
public BatchUpdateException( String reason, String SQLState, int vendorCode, public BatchUpdateException( String reason, String SQLState, int vendorCode,
int[] updateCounts ) { int[] updateCounts ) {
this(reason, SQLState, vendorCode, updateCounts, null); super(reason, SQLState, vendorCode);
this.updateCounts = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
} }
/** /**
...@@ -106,7 +107,7 @@ public class BatchUpdateException extends SQLException { ...@@ -106,7 +107,7 @@ public class BatchUpdateException extends SQLException {
*/ */
public BatchUpdateException(String reason, String SQLState, public BatchUpdateException(String reason, String SQLState,
int[] updateCounts) { int[] updateCounts) {
this(reason, SQLState, 0, updateCounts, null); this(reason, SQLState, 0, updateCounts);
} }
/** /**
...@@ -132,7 +133,7 @@ public class BatchUpdateException extends SQLException { ...@@ -132,7 +133,7 @@ public class BatchUpdateException extends SQLException {
* @since 1.2 * @since 1.2
*/ */
public BatchUpdateException(String reason, int[] updateCounts) { public BatchUpdateException(String reason, int[] updateCounts) {
this(reason, null, 0, updateCounts, null); this(reason, null, 0, updateCounts);
} }
/** /**
...@@ -155,7 +156,7 @@ public class BatchUpdateException extends SQLException { ...@@ -155,7 +156,7 @@ public class BatchUpdateException extends SQLException {
* @since 1.2 * @since 1.2
*/ */
public BatchUpdateException(int[] updateCounts) { public BatchUpdateException(int[] updateCounts) {
this(null, null, 0, updateCounts, null); this(null, null, 0, updateCounts);
} }
/** /**
...@@ -170,7 +171,7 @@ public class BatchUpdateException extends SQLException { ...@@ -170,7 +171,7 @@ public class BatchUpdateException extends SQLException {
* @since 1.2 * @since 1.2
*/ */
public BatchUpdateException() { public BatchUpdateException() {
this(null, null, 0, null, null); this(null, null, 0, null);
} }
/** /**
......
...@@ -40,8 +40,7 @@ import javax.accessibility.*; ...@@ -40,8 +40,7 @@ import javax.accessibility.*;
import sun.awt.AppContext; import sun.awt.AppContext;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.security.PrivilegedAction; import java.security.*;
import java.security.AccessController;
/** /**
* An implementation of the Icon interface that paints Icons * An implementation of the Icon interface that paints Icons
...@@ -81,32 +80,51 @@ public class ImageIcon implements Icon, Serializable, Accessible { ...@@ -81,32 +80,51 @@ public class ImageIcon implements Icon, Serializable, Accessible {
ImageObserver imageObserver; ImageObserver imageObserver;
String description = null; String description = null;
// Fields for twisted backward compatibility only. DO NOT USE.
protected final static Component component; protected final static Component component;
protected final static MediaTracker tracker; protected final static MediaTracker tracker;
static { static {
component = new Component() {}; component = AccessController.doPrivileged(new PrivilegedAction<Component>() {
AccessController.doPrivileged(new PrivilegedAction<Object>() { public Component run() {
public Object run() {
try { try {
final Component component = createNoPermsComponent();
// 6482575 - clear the appContext field so as not to leak it // 6482575 - clear the appContext field so as not to leak it
Field appContextField = Field appContextField =
Component.class.getDeclaredField("appContext");
Component.class.getDeclaredField("appContext");
appContextField.setAccessible(true); appContextField.setAccessible(true);
appContextField.set(component, null); appContextField.set(component, null);
}
catch (NoSuchFieldException e) { return component;
e.printStackTrace(); } catch (Throwable e) {
} // We don't care about component.
catch (IllegalAccessException e) { // So don't prevent class initialisation.
e.printStackTrace(); e.printStackTrace();
return null;
} }
return null;
} }
}); });
tracker = new MediaTracker(component); tracker = new MediaTracker(component);
} }
private static Component createNoPermsComponent() {
// 7020198 - set acc field to no permissions and no subject
// Note, will have appContext set.
return AccessController.doPrivileged(
new PrivilegedAction<Component>() {
public Component run() {
return new Component() {
};
}
},
new AccessControlContext(new ProtectionDomain[]{
new ProtectionDomain(null, null)
})
);
}
/** /**
* Id used in loading images from MediaTracker. * Id used in loading images from MediaTracker.
*/ */
......
...@@ -588,6 +588,10 @@ public class NimbusLookAndFeel extends SynthLookAndFeel { ...@@ -588,6 +588,10 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
} }
private void addDefault(String key, Object value) { private void addDefault(String key, Object value) {
if (compiledDefaults == null) {
return;
}
String prefix = parsePrefix(key); String prefix = parsePrefix(key);
if (prefix != null) { if (prefix != null) {
Map<String, Object> keys = compiledDefaults.get(prefix); Map<String, Object> keys = compiledDefaults.get(prefix);
......
...@@ -337,8 +337,7 @@ public class Utilities { ...@@ -337,8 +337,7 @@ public class Utilities {
// x before x0, return. // x before x0, return.
return 0; return 0;
} }
int currX = x0; int nextX = x0;
int nextX = currX;
// s may be a shared segment, so it is copied prior to calling // s may be a shared segment, so it is copied prior to calling
// the tab expander // the tab expander
char[] txt = s.array; char[] txt = s.array;
...@@ -388,19 +387,45 @@ public class Utilities { ...@@ -388,19 +387,45 @@ public class Utilities {
} else { } else {
nextX += metrics.charWidth(txt[i]); nextX += metrics.charWidth(txt[i]);
} }
if ((x >= currX) && (x < nextX)) { if (x < nextX) {
// found the hit position... return the appropriate side // found the hit position... return the appropriate side
int offset = ((round == false) || ((x - currX) < (nextX - x))) ? int offset;
(i - txtOffset) : (i + 1 - txtOffset);
// the length of the string measured as a whole may differ from // the length of the string measured as a whole may differ from
// the sum of individual character lengths, for example if // the sum of individual character lengths, for example if
// fractional metrics are enabled; and we must guard from this. // fractional metrics are enabled; and we must guard from this.
while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) { if (round) {
offset--; offset = i + 1 - txtOffset;
int width = metrics.charsWidth(txt, txtOffset, offset);
int span = x - x0;
if (span < width) {
while (offset > 0) {
int nextWidth = offset > 1 ? metrics.charsWidth(txt, txtOffset, offset - 1) : 0;
if (span >= nextWidth) {
if (span - nextWidth < width - span) {
offset--;
}
break;
}
width = nextWidth;
offset--;
}
}
} else {
offset = i - txtOffset;
while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) {
offset--;
}
} }
return offset; return offset;
} }
currX = nextX;
} }
// didn't find, return end offset // didn't find, return end offset
......
...@@ -180,7 +180,6 @@ public class FileFontStrike extends PhysicalStrike { ...@@ -180,7 +180,6 @@ public class FileFontStrike extends PhysicalStrike {
pScalerContext = NullFontScaler.getNullScalerContext(); pScalerContext = NullFontScaler.getNullScalerContext();
} else { } else {
pScalerContext = fileFont.getScaler().createScalerContext(matrix, pScalerContext = fileFont.getScaler().createScalerContext(matrix,
fileFont instanceof TrueTypeFont,
desc.aaHint, desc.fmHint, desc.aaHint, desc.fmHint,
boldness, italic, disableHinting); boldness, italic, disableHinting);
} }
......
...@@ -242,7 +242,6 @@ public abstract class FontScaler implements DisposerRecord { ...@@ -242,7 +242,6 @@ public abstract class FontScaler implements DisposerRecord {
freed when corresponding strike is being released. freed when corresponding strike is being released.
*/ */
abstract long createScalerContext(double[] matrix, abstract long createScalerContext(double[] matrix,
boolean fontType,
int aa, int fm, int aa, int fm,
float boldness, float italic, float boldness, float italic,
boolean disableHinting); boolean disableHinting);
......
...@@ -210,12 +210,12 @@ class FreetypeFontScaler extends FontScaler { ...@@ -210,12 +210,12 @@ class FreetypeFontScaler extends FontScaler {
return getUnitsPerEMNative(nativeScaler); return getUnitsPerEMNative(nativeScaler);
} }
long createScalerContext(double[] matrix, boolean fontType, long createScalerContext(double[] matrix,
int aa, int fm, float boldness, float italic, int aa, int fm, float boldness, float italic,
boolean disableHinting) { boolean disableHinting) {
if (nativeScaler != 0L) { if (nativeScaler != 0L) {
return createScalerContextNative(nativeScaler, matrix, return createScalerContextNative(nativeScaler, matrix,
fontType, aa, fm, boldness, italic); aa, fm, boldness, italic);
} }
return NullFontScaler.getNullScalerContext(); return NullFontScaler.getNullScalerContext();
} }
...@@ -254,7 +254,7 @@ class FreetypeFontScaler extends FontScaler { ...@@ -254,7 +254,7 @@ class FreetypeFontScaler extends FontScaler {
private native long getUnitsPerEMNative(long pScaler); private native long getUnitsPerEMNative(long pScaler);
native long createScalerContextNative(long pScaler, double[] matrix, native long createScalerContextNative(long pScaler, double[] matrix,
boolean fontType, int aa, int fm, float boldness, float italic); int aa, int fm, float boldness, float italic);
/* Freetype scaler context does not contain any pointers that /* Freetype scaler context does not contain any pointers that
has to be invalidated if native scaler is bad */ has to be invalidated if native scaler is bad */
......
...@@ -66,7 +66,7 @@ class NullFontScaler extends FontScaler { ...@@ -66,7 +66,7 @@ class NullFontScaler extends FontScaler {
long getLayoutTableCache() {return 0L;} long getLayoutTableCache() {return 0L;}
long createScalerContext(double[] matrix, boolean fontType, int aa, long createScalerContext(double[] matrix, int aa,
int fm, float boldness, float italic, boolean disableHinting) { int fm, float boldness, float italic, boolean disableHinting) {
return getNullScalerContext(); return getNullScalerContext();
} }
......
...@@ -29,6 +29,8 @@ import java.lang.invoke.MethodHandle; ...@@ -29,6 +29,8 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
...@@ -38,7 +40,17 @@ import java.util.List; ...@@ -38,7 +40,17 @@ import java.util.List;
public class ValueConversions { public class ValueConversions {
private static final Class<?> THIS_CLASS = ValueConversions.class; private static final Class<?> THIS_CLASS = ValueConversions.class;
// Do not adjust this except for special platforms: // Do not adjust this except for special platforms:
private static final int MAX_ARITY = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255); private static final int MAX_ARITY;
static {
final Object[] values = { 255 };
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
return null;
}
});
MAX_ARITY = (Integer) values[0];
}
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
...@@ -198,27 +210,30 @@ public class ValueConversions { ...@@ -198,27 +210,30 @@ public class ValueConversions {
return unbox(Wrapper.forPrimitiveType(type), true, false); return unbox(Wrapper.forPrimitiveType(type), true, false);
} }
static private final Integer ZERO_INT = 0, ONE_INT = 1;
/// Primitive conversions /// Primitive conversions
public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) { public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
// Maybe merge this code with Wrapper.convert/cast. // Maybe merge this code with Wrapper.convert/cast.
Number res = null; Number res = null;
if (x == null) { if (x == null) {
if (!cast) return null; if (!cast) return null;
x = wrap.zero(); return ZERO_INT;
} }
if (x instanceof Number) { if (x instanceof Number) {
res = (Number) x; res = (Number) x;
} else if (x instanceof Boolean) { } else if (x instanceof Boolean) {
res = ((boolean)x ? 1 : 0); res = ((boolean)x ? ONE_INT : ZERO_INT);
} else if (x instanceof Character) { } else if (x instanceof Character) {
res = (int)(char)x; res = (int)(char)x;
} else { } else {
// this will fail with the required ClassCastException: // this will fail with the required ClassCastException:
res = (Number) x; res = (Number) x;
} }
if (!cast && !wrap.isConvertibleFrom(Wrapper.forWrapperType(x.getClass()))) Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
// this will fail with the required ClassCastException: // this will fail with the required ClassCastException:
res = (Number) wrap.wrapperType().cast(x); return (Number) wrap.wrapperType().cast(x);
return res; return res;
} }
......
...@@ -154,9 +154,10 @@ public class VerifyAccess { ...@@ -154,9 +154,10 @@ public class VerifyAccess {
* @return whether they are in the same package * @return whether they are in the same package
*/ */
public static boolean isSamePackage(Class<?> class1, Class<?> class2) { public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
assert(!class1.isArray() && !class2.isArray());
if (class1 == class2) if (class1 == class2)
return true; return true;
if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader())) if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader(), false))
return false; return false;
String name1 = class1.getName(), name2 = class2.getName(); String name1 = class1.getName(), name2 = class2.getName();
int dot = name1.lastIndexOf('.'); int dot = name1.lastIndexOf('.');
...@@ -169,6 +170,16 @@ public class VerifyAccess { ...@@ -169,6 +170,16 @@ public class VerifyAccess {
return true; return true;
} }
/** Return the package name for this class.
*/
public static String getPackageName(Class<?> cls) {
assert(!cls.isArray());
String name = cls.getName();
int dot = name.lastIndexOf('.');
if (dot < 0) return "";
return name.substring(0, dot);
}
/** /**
* Test if two classes are defined as part of the same package member (top-level class). * Test if two classes are defined as part of the same package member (top-level class).
* If this is true, they can share private access with each other. * If this is true, they can share private access with each other.
...@@ -193,18 +204,33 @@ public class VerifyAccess { ...@@ -193,18 +204,33 @@ public class VerifyAccess {
return pkgmem; return pkgmem;
} }
private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) { private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,
if (loader1 == loader2 || loader1 == null || loader2 == null) { boolean loader1MustBeParent) {
if (loader1 == loader2 || loader1 == null
|| (loader2 == null && !loader1MustBeParent)) {
return true; return true;
} }
for (ClassLoader scan1 = loader1;
scan1 != null; scan1 = scan1.getParent()) {
if (scan1 == loader2) return true;
}
for (ClassLoader scan2 = loader2; for (ClassLoader scan2 = loader2;
scan2 != null; scan2 = scan2.getParent()) { scan2 != null; scan2 = scan2.getParent()) {
if (scan2 == loader1) return true; if (scan2 == loader1) return true;
} }
if (loader1MustBeParent) return false;
// see if loader2 is a parent of loader1:
for (ClassLoader scan1 = loader1;
scan1 != null; scan1 = scan1.getParent()) {
if (scan1 == loader2) return true;
}
return false; return false;
} }
/**
* Is the class loader of parentClass identical to, or an ancestor of,
* the class loader of childClass?
* @param parentClass
* @param childClass
* @return whether parentClass precedes or equals childClass in class loader order
*/
public static boolean classLoaderIsAncestor(Class<?> parentClass, Class<?> childClass) {
return loadersAreRelated(parentClass.getClassLoader(), childClass.getClassLoader(), true);
}
} }
...@@ -135,7 +135,7 @@ public enum Wrapper { ...@@ -135,7 +135,7 @@ public enum Wrapper {
* <li>any type converted to {@code void} (i.e., dropping a method call's value) * <li>any type converted to {@code void} (i.e., dropping a method call's value)
* <li>boxing conversion followed by widening reference conversion to {@code Object} * <li>boxing conversion followed by widening reference conversion to {@code Object}
* </ul> * </ul>
* These are the cases allowed by MethodHandle.asType and convertArguments. * These are the cases allowed by MethodHandle.asType.
*/ */
public boolean isConvertibleFrom(Wrapper source) { public boolean isConvertibleFrom(Wrapper source) {
if (this == source) return true; if (this == source) return true;
......
/* /*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
/* /*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
...@@ -509,6 +509,9 @@ public class DrawImage implements DrawImagePipe ...@@ -509,6 +509,9 @@ public class DrawImage implements DrawImagePipe
* edges thus has to be h*2+2 in length * edges thus has to be h*2+2 in length
*/ */
int edges[] = new int[(dy2-dy1)*2+2]; int edges[] = new int[(dy2-dy1)*2+2];
// It is important that edges[0]=edges[1]=0 when we call
// Transform in case it must return early and we would
// not want to render anything on an error condition.
helper.Transform(tmpmaskblit, srcData, tmpData, helper.Transform(tmpmaskblit, srcData, tmpData,
AlphaComposite.Src, null, AlphaComposite.Src, null,
itx, interpType, itx, interpType,
......
/* /*
* Copyright (c) 2003, 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
...@@ -532,15 +532,11 @@ public class URLClassPath { ...@@ -532,15 +532,11 @@ public class URLClassPath {
uc = url.openConnection(); uc = url.openConnection();
InputStream in = uc.getInputStream(); InputStream in = uc.getInputStream();
if (uc instanceof JarURLConnection) { if (uc instanceof JarURLConnection) {
/* JarURLConnection.getInputStream() returns a separate /* Need to remember the jar file so it can be closed
* instance on each call. So we have to close this here.
* The jar file cache will keep the file open.
* Also, need to remember the jar file so it can be closed
* in a hurry. * in a hurry.
*/ */
JarURLConnection juc = (JarURLConnection)uc; JarURLConnection juc = (JarURLConnection)uc;
jarfile = juc.getJarFile(); jarfile = juc.getJarFile();
in.close();
} }
} catch (Exception e) { } catch (Exception e) {
return null; return null;
......
此差异已折叠。
...@@ -238,4 +238,14 @@ abstract public class URLConnection extends java.net.URLConnection { ...@@ -238,4 +238,14 @@ abstract public class URLConnection extends java.net.URLConnection {
public void close() { public void close() {
url = null; url = null;
} }
private static HashMap<String,Void> proxiedHosts = new HashMap<>();
public synchronized static void setProxiedHost(String host) {
proxiedHosts.put(host.toLowerCase(), null);
}
public synchronized static boolean isProxiedHost(String host) {
return proxiedHosts.containsKey(host.toLowerCase());
}
} }
...@@ -301,7 +301,11 @@ public class HttpClient extends NetworkClient { ...@@ -301,7 +301,11 @@ public class HttpClient extends NetworkClient {
} else { } else {
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
security.checkConnect(url.getHost(), url.getPort()); if (ret.proxy == Proxy.NO_PROXY || ret.proxy == null) {
security.checkConnect(InetAddress.getByName(url.getHost()).getHostAddress(), url.getPort());
} else {
security.checkConnect(url.getHost(), url.getPort());
}
} }
ret.url = url; ret.url = url;
} }
...@@ -457,6 +461,7 @@ public class HttpClient extends NetworkClient { ...@@ -457,6 +461,7 @@ public class HttpClient extends NetworkClient {
protected synchronized void openServer() throws IOException { protected synchronized void openServer() throws IOException {
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
security.checkConnect(host, port); security.checkConnect(host, port);
} }
...@@ -469,6 +474,7 @@ public class HttpClient extends NetworkClient { ...@@ -469,6 +474,7 @@ public class HttpClient extends NetworkClient {
url.getProtocol().equals("https") ) { url.getProtocol().equals("https") ) {
if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) { if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) {
sun.net.www.URLConnection.setProxiedHost(host);
privilegedOpenServer((InetSocketAddress) proxy.address()); privilegedOpenServer((InetSocketAddress) proxy.address());
usingProxy = true; usingProxy = true;
return; return;
...@@ -484,6 +490,7 @@ public class HttpClient extends NetworkClient { ...@@ -484,6 +490,7 @@ public class HttpClient extends NetworkClient {
* ftp url. * ftp url.
*/ */
if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) { if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) {
sun.net.www.URLConnection.setProxiedHost(host);
privilegedOpenServer((InetSocketAddress) proxy.address()); privilegedOpenServer((InetSocketAddress) proxy.address());
usingProxy = true; usingProxy = true;
return; return;
......
/* /*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -653,6 +653,13 @@ final class Config { ...@@ -653,6 +653,13 @@ final class Config {
} }
} }
debug(keyword + ": " + lib); debug(keyword + ": " + lib);
// Check to see if full path is specified to prevent the DLL
// preloading attack
if (!(new File(lib)).isAbsolute()) {
throw new ConfigurationException(
"Absolute path required for library value: " + lib);
}
return lib; return lib;
} }
......
/* /*
* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "jni.h" #include "jni.h"
#include "jvm.h" #include "jvm.h"
#include "jdk_util_md.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
......
...@@ -1971,6 +1971,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage ...@@ -1971,6 +1971,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
return data->abortFlag; return data->abortFlag;
} }
if (cinfo->output_components <= 0 ||
cinfo->image_width > (0xffffffffu / (unsigned int)cinfo->output_components))
{
JNU_ThrowByName(env, "javax/imageio/IIOException",
"Invalid number of output components");
return data->abortFlag;
}
// Allocate a 1-scanline buffer // Allocate a 1-scanline buffer
scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->output_components); scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->output_components);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册