提交 bd11b4f3 编写于 作者: M mullan

Merge

......@@ -118,3 +118,4 @@ d80954a89b49fda47c0c5cace65a17f5a758b8bd jdk7-b139
63eeefe118da18c75ba3d36266768cd1ccaaca6b jdk7-b141
312612e89ece62633f4809706dec00bcd5fe7c2d jdk7-b142
efbf75c24b0f31847c9c403f6dc07dc80551908d jdk7-b143
23bdcede4e3945894574892e80b848bd9f15b5f3 jdk7-b144
......@@ -49,5 +49,16 @@ RUNTIME_NAME = $(PRODUCT_NAME) $(PRODUCT_SUFFIX)
JRE_REDUCED_HEADLESS_IMAGE_DIR = $(ABS_OUTPUTDIR)/j2re-reduced-headless-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
......@@ -53,25 +53,30 @@ $(NOT_HEADLESS_RT_JAR_LIST): $(NOT_RT_JAR_LIST)
$(RM) $(HEADLESS_CLASSLIST)
$(RM) $(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/X11/" >> $@
$(ECHO) "sun/applet/" >> $@
$(ECHO) "sun/java2d/opengl/" >> $@
$(ECHO) "com/sun/java/swing/plaf/" >> $@
$(ECHO) "sun/awt/motif/MFontConfiguration" >$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppContextCreator" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppletAudioClip" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData"\$$"GLXOffScreenSurfaceData" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXVolatileSurfaceManager" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/OGLSurfaceData" >>$(HEADLESS_CLASSLIST)
# List all the individual classes to be included
$(ECHO) "sun/awt/motif/MFontConfiguration.class" >$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppContextCreator.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/applet/AppletAudioClip.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData.class" >>$(HEADLESS_CLASSLIST)
$(ECHO) "sun/java2d/opengl/GLXSurfaceData"\$$"GLXOffScreenSurfaceData.class" >>$(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)
$(prep-target)
$(RM) $@.temp
$(CD) $(CLASSBINDIR) ; \
$(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 $@
@$(CD) $(CLASSBINDIR); $(java-vm-cleanup)
......@@ -124,13 +129,9 @@ NOT_REDUCEDJRE_LIB = \
$(LIBARCH)/libjavaplugin_nscp.so \
$(LIBARCH)/libjavaplugin_oji.so
ifeq ($(PLATFORM), linux)
STRIP_OPTS = --strip-unneeded
else
STRIP_OPTS = -x
endif
# JRE docs that don't get included in reduced jre image top directory
NOT_REDUCEDJRE_DOC = \
Welcome.html
reduced-image-jre::
@$(ECHO) Starting to Produce Reduced JRE
......@@ -142,12 +143,6 @@ reduced-image-jre::
$(CD) $(JRE_IMAGE_DIR); \
$(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
@# reduced JRE
......@@ -158,6 +153,9 @@ endif
for l in $(NOT_REDUCEDJRE_LIB) ; do \
$(RM) $(JRE_REDUCED_IMAGE_DIR)/lib/$$l ; \
done
for l in $(NOT_REDUCEDJRE_DOC) ; do \
$(RM) $(JRE_REDUCED_IMAGE_DIR)/$$l ; \
done
@# Remove misc. other files
$(RM) -r $(JRE_REDUCED_IMAGE_DIR)/man
......
." 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.
."
." 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.
."
." This code is free software; you can redistribute it and/or modify it
......
......@@ -56,9 +56,9 @@ FileChooser.deleteFileButtonMnemonic=76
FileChooser.renameFileButtonText=Rename File
FileChooser.renameFileButtonMnemonic=82
FileChooser.cancelButtonText=Cancel
#FileChooser.cancelButtonMnemonic=67
FileChooser.cancelButtonMnemonic=67
FileChooser.saveButtonText=OK
#FileChooser.saveButtonMnemonic=79
FileChooser.saveButtonMnemonic=79
FileChooser.openButtonText=OK
FileChooser.openButtonMnemonic=79
FileChooser.saveDialogTitleText=Save
......@@ -79,5 +79,5 @@ FileChooser.renameFileDialogText=Rename file "{0}" to
FileChooser.renameFileErrorTitle=Error
FileChooser.renameFileErrorText=Error renaming file "{0}" to "{1}"
#OptionPane.okButtonMnemonic=79
#OptionPane.cancelButtonMnemonic=67
OptionPane.okButtonMnemonic=79
OptionPane.cancelButtonMnemonic=67
......@@ -1857,7 +1857,7 @@ public abstract class Toolkit {
/**
* Adds the specified property change listener for the named desktop
* property. When a {@link PropertyChangeListenerProxy} object is added,
* property. When a {@link java.beans.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},
* no exception is thrown and no action is performed.
......@@ -1874,7 +1874,7 @@ public abstract class Toolkit {
/**
* Removes the specified property change listener for the named
* desktop property. When a {@link PropertyChangeListenerProxy} object
* desktop property. When a {@link java.beans.PropertyChangeListenerProxy} object
* is removed, its property name is ignored, and
* the wrapped listener is removed.
* If {@code name} is {@code null} or {@code pcl} is {@code null},
......@@ -1893,11 +1893,11 @@ public abstract class Toolkit {
/**
* Returns an array of all the property change listeners
* 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.
*
* @return all of this toolkit's {@ code PropertyChangeListener}
* objects wrapped in {@code PropertyChangeListenerProxy} objects
* @return all of this toolkit's {@link PropertyChangeListener}
* objects wrapped in {@code java.beans.PropertyChangeListenerProxy} objects
* or an empty array if no listeners are added
*
* @see PropertyChangeSupport#getPropertyChangeListeners()
......
/*
* %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.
*/
......
......@@ -39,14 +39,14 @@ public class BootstrapMethodError extends LinkageError {
private static final long serialVersionUID = 292L;
/**
* Constructs an {@code BootstrapMethodError} with no detail message.
* Constructs a {@code BootstrapMethodError} with no detail message.
*/
public BootstrapMethodError() {
super();
}
/**
* Constructs an {@code BootstrapMethodError} with the specified
* Constructs a {@code BootstrapMethodError} with the specified
* detail message.
*
* @param s the detail message.
......
......@@ -38,6 +38,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* @since 1.7
*/
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}.
* <p>
......@@ -100,7 +107,7 @@ public abstract class ClassValue<T> {
* If this value is subsequently {@linkplain #get read} for the same class,
* its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
* 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>
* 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
......@@ -193,6 +200,7 @@ public abstract class ClassValue<T> {
= new WeakHashMap<Class<?>, ClassValueMap>();
private static ClassValueMap getMap(Class<?> type) {
type.getClass(); // test for null
return ROOT.get(type);
}
......
......@@ -29,6 +29,8 @@ import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import sun.invoke.util.ValueConversions;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
......@@ -62,7 +64,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// the target and change its type, instead of adding another layer.
/** 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) {
// same number of args, of course
......@@ -92,7 +94,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
/** 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) {
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
......@@ -141,7 +143,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
while (lastConv >= 0) {
Class<?> src = newType.parameterType(lastConv); // source type
Class<?> dst = oldType.parameterType(lastConv); // destination type
if (VerifyType.isNullConversion(src, dst)) {
if (isTrivialConversion(src, dst, level)) {
--lastConv;
} else {
break;
......@@ -150,7 +152,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
Class<?> needReturn = newType.returnType();
Class<?> haveReturn = oldType.returnType();
boolean retConv = !VerifyType.isNullConversion(haveReturn, needReturn);
boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
// Now build a chain of one or more adapters.
MethodHandle adapter = target, adapter2;
......@@ -158,7 +160,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
for (int i = 0; i <= lastConv; i++) {
Class<?> src = newType.parameterType(i); // source type
Class<?> dst = midType.parameterType(i); // destination type
if (VerifyType.isNullConversion(src, dst)) {
if (isTrivialConversion(src, dst, level)) {
// do nothing: difference is trivial
continue;
}
......@@ -219,6 +221,22 @@ class AdapterMethodHandle extends BoundMethodHandle {
return adapter;
}
private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) {
if (src == dst || dst == void.class) return true;
if (!VerifyType.isNullConversion(src, dst)) return false;
if (level > 1) return true; // explicitCastArguments
boolean sp = src.isPrimitive();
boolean dp = dst.isPrimitive();
if (sp != dp) return false;
if (sp) {
// in addition to being a null conversion, forbid boolean->int etc.
return Wrapper.forPrimitiveType(dst)
.isConvertibleFrom(Wrapper.forPrimitiveType(src));
} else {
return dst.isAssignableFrom(src);
}
}
private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) {
MethodHandle adjustReturn;
if (haveReturn == void.class) {
......@@ -530,6 +548,11 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
MethodType type = target.type();
int last = type.parameterCount() - 1;
if (type.parameterType(last) != arrayType)
target = target.asType(type.changeParameterType(last, arrayType));
target = target.asFixedArity(); // make sure this attribute is turned off
return new AsVarargsCollector(target, arrayType);
}
......@@ -550,6 +573,11 @@ class AdapterMethodHandle extends BoundMethodHandle {
return true;
}
@Override
public MethodHandle asFixedArity() {
return target;
}
@Override
public MethodHandle asType(MethodType newType) {
MethodType type = this.type();
......@@ -574,14 +602,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
cache = collector;
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?
......@@ -596,7 +616,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
|| !VerifyType.isNullConversion(castType, dst))
return false;
int diff = diffTypes(newType, targetType, false);
return (diff == arg+1); // arg is sole non-trivial diff
return (diff == arg+1) || (diff == 0); // arg is sole non-trivial diff
}
/** Can an primitive conversion adapter validly convert src to dst? */
static boolean canCheckCast(Class<?> src, Class<?> dst) {
......@@ -727,8 +747,31 @@ class AdapterMethodHandle extends BoundMethodHandle {
if (!canUnboxArgument(newType, oldType, arg, convType, level))
return null;
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);
}
long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
if (castDone == newType)
......@@ -897,6 +940,20 @@ class AdapterMethodHandle extends BoundMethodHandle {
if (swapArg1 == swapArg2)
return target;
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] => [a b c y x] => [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);
if (argc == 2) return rot1;
MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
return rot2;
}
if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
return null;
Class<?> swapType = newType.parameterType(swapArg1);
......@@ -926,7 +983,6 @@ class AdapterMethodHandle extends BoundMethodHandle {
static boolean canRotateArguments(MethodType newType, MethodType targetType,
int firstArg, int argCount, int rotateBy) {
if (!convOpSupported(OP_ROT_ARGS)) return false;
if (argCount <= 2) return false; // must be a swap, not a rotate
rotateBy = positiveRotation(argCount, rotateBy);
if (rotateBy == 0) return false; // no rotation
if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
......@@ -972,6 +1028,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// From here on out, it assumes a single-argument shift.
assert(MAX_ARG_ROTATION == 1);
int srcArg, dstArg;
int dstSlot;
byte basicType;
if (chunk2Slots <= chunk1Slots) {
// Rotate right/down N (rotateBy = +N, N small, c2 small):
......@@ -979,6 +1036,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
// out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
srcArg = limit-1;
dstArg = firstArg;
dstSlot = depth0 - chunk2Slots;
basicType = basicType(newType.parameterType(srcArg));
assert(chunk2Slots == type2size(basicType));
} else {
......@@ -987,10 +1045,10 @@ class AdapterMethodHandle extends BoundMethodHandle {
// out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
srcArg = firstArg;
dstArg = limit-1;
dstSlot = depth2;
basicType = basicType(newType.parameterType(srcArg));
assert(chunk1Slots == type2size(basicType));
}
int dstSlot = newType.parameterSlotDepth(dstArg + 1);
long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
return new AdapterMethodHandle(target, newType, conv);
}
......@@ -1033,8 +1091,9 @@ class AdapterMethodHandle extends BoundMethodHandle {
Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
// FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
MethodType targetType = target.type();
if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
return null;
assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
: "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
+ Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount);
// dest is not significant; remove?
int dest = T_VOID;
for (int i = 0; i < spreadArgCount; i++) {
......@@ -1127,7 +1186,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
}
@Override
public String toString() {
String debugString() {
return getNameString(nonAdapter((MethodHandle)vmtarget), this);
}
......
......@@ -151,11 +151,11 @@ class BoundMethodHandle extends MethodHandle {
final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
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
public String toString() {
String debugString() {
return addTypeString(baseName(), this);
}
......
......@@ -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
* @throws NullPointerException if the proposed target is null
*/
......@@ -121,6 +121,25 @@ public class CallSite {
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.
* 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 {
* @return the type of the current target, which is also the type of any future target
*/
public MethodType type() {
// warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
return target.type();
}
......@@ -294,8 +314,8 @@ public class CallSite {
} else {
throw new ClassCastException("bootstrap method failed to produce a CallSite");
}
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
if (!site.getTarget().type().equals(type))
throw new WrongMethodTypeException("wrong type: "+site.getTarget());
} catch (Throwable ex) {
BootstrapMethodError bex;
if (ex instanceof BootstrapMethodError)
......
......@@ -32,6 +32,8 @@ package java.lang.invoke;
* @author John Rose, JSR 292 EG
*/
public class ConstantCallSite extends CallSite {
private final boolean isFrozen;
/**
* Creates a call site with a permanent target.
* @param target the target to be permanently associated with this call site
......@@ -39,6 +41,45 @@ public class ConstantCallSite extends CallSite {
*/
public ConstantCallSite(MethodHandle 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 {
* to the constructor call which created this instance.
*
* @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() {
if (!isFrozen) throw new IllegalStateException();
return target;
}
......@@ -61,7 +103,7 @@ public class ConstantCallSite extends CallSite {
* @throws UnsupportedOperationException because this kind of call site cannot change its target
*/
@Override public final void setTarget(MethodHandle ignore) {
throw new UnsupportedOperationException("ConstantCallSite");
throw new UnsupportedOperationException();
}
/**
......@@ -69,6 +111,7 @@ public class ConstantCallSite extends CallSite {
* Since that target will never change, this is a correct implementation
* of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
* @return the immutable linkage state of this call site, a constant method handle
* @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
*/
@Override
public final MethodHandle dynamicInvoker() {
......
......@@ -234,7 +234,7 @@ class FilterGeneric {
protected final MethodHandle target; // ultimate target
@Override
public String toString() {
String debugString() {
return addTypeString(target, this);
}
......
......@@ -41,7 +41,7 @@ class FilterOneArgument extends BoundMethodHandle {
protected final MethodHandle target; // Object -> Object
@Override
public String toString() {
String debugString() {
return target.toString();
}
......
......@@ -260,7 +260,7 @@ class FromGeneric {
protected final MethodHandle target; // (any**N) => R
@Override
public String toString() {
String debugString() {
return addTypeString(target, this);
}
......
......@@ -129,20 +129,17 @@ class InvokeGeneric {
if (needType == erasedCallerType.returnType())
return false; // no conversions possible, since must be primitive or Object
Class<?> haveType = target.type().returnType();
if (VerifyType.isNullConversion(haveType, needType))
if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface())
return false;
return true;
}
private MethodHandle addReturnConversion(MethodHandle target, Class<?> type) {
if (true) throw new RuntimeException("NYI");
private MethodHandle addReturnConversion(MethodHandle finisher, Class<?> type) {
// FIXME: This is slow because it creates a closure node on every call that requires a return cast.
MethodType targetType = target.type();
MethodType finisherType = finisher.type();
MethodHandle caster = ValueConversions.identity(type);
caster = caster.asType(MethodType.methodType(type, targetType.returnType()));
// Drop irrelevant arguments, because we only care about the return value:
caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList());
MethodHandle result = MethodHandles.foldArguments(caster, target);
return result.asType(target.type());
caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType()));
finisher = MethodHandles.filterReturnValue(finisher, caster);
return finisher.asType(finisherType);
}
public String toString() {
......
......@@ -46,7 +46,10 @@ class Invokers {
// general invoker for the outgoing call
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;
// invoker for an unbound callsite
......@@ -67,45 +70,56 @@ class Invokers {
/*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker;
try {
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());
invoker = lookupInvoker("invokeExact");
exactInvoker = invoker;
return invoker;
}
/*non-public*/ MethodHandle generalInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = generalInvoker;
if (invoker != null) return invoker;
MethodType generalType = targetType.generic();
invoker = invoker1.asType(invokerType(generalType));
invoker = lookupInvoker("invoke");
generalInvoker = 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() {
MethodHandle invoker1 = exactInvoker();
MethodHandle xinvoker = exactInvoker();
MethodHandle invoker = erasedInvoker;
if (invoker != null) return invoker;
MethodType erasedType = targetType.erase();
if (erasedType == targetType.generic())
invoker = generalInvoker();
else
invoker = invoker1.asType(invokerType(erasedType));
invoker = xinvoker.asType(invokerType(erasedType));
erasedInvoker = invoker;
return invoker;
}
/*non-public*/ MethodHandle spreadInvoker(int objectArgCount) {
MethodHandle vaInvoker = spreadInvokers[objectArgCount];
/*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
if (vaInvoker != null) return vaInvoker;
MethodHandle gInvoker = generalInvoker();
vaInvoker = gInvoker.asSpreader(Object[].class, targetType.parameterCount() - objectArgCount);
spreadInvokers[objectArgCount] = vaInvoker;
int spreadArgCount = targetType.parameterCount() - leadingArgCount;
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;
}
......
......@@ -506,8 +506,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
if (from != null) message += ", from " + from;
return new IllegalAccessException(message);
}
public ReflectiveOperationException makeAccessException(String message) {
message = message + ": "+ toString();
private String message() {
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())
return new IllegalAccessException(message);
else if (isConstructor())
......@@ -641,7 +651,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null)
return result;
ReflectiveOperationException ex = m.makeAccessException("no access");
ReflectiveOperationException ex = m.makeAccessException();
if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
throw nsmClass.cast(ex);
}
......
......@@ -82,20 +82,44 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
if (!mh.isValid())
throw method.makeAccessException("no access", lookupClass);
throw method.makeAccessException("no direct method handle", lookupClass);
assert(mh.type() == mtype);
if (!method.isVarargs())
return mh;
else
return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
int argc = mtype.parameterCount();
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
MethodHandle makeAllocator(MethodHandle rawConstructor) {
MethodType rawConType = rawConstructor.type();
Class<?> allocateClass = rawConType.parameterType(0);
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
if (AdapterMethodHandle.canCollectArguments(rawConType, MethodType.methodType(allocateClass), 0, true)) {
// allocator(arg...)
// [fold]=> cookedConstructor(obj=allocate(C), arg...)
// [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
MethodHandle returner = MethodHandles.identity(allocateClass);
MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass);
MethodHandle cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false);
assert(cookedConstructor.type().equals(ctype));
ctype = ctype.dropParameterTypes(0, 1);
cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
MethodHandle allocator = new AllocateObject(allocateClass);
// allocate() => new C(void)
assert(allocator.type().equals(MethodType.methodType(allocateClass)));
ctype = ctype.dropParameterTypes(0, 1);
MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator);
return fold;
}
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodHandle allocator
= AllocateObject.make(rawConType.parameterType(0), rawConstructor);
= AllocateObject.make(allocateClass, rawConstructor);
assert(allocator.type()
.equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
return allocator;
......@@ -112,8 +136,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
super(invoker);
this.allocateClass = allocateClass;
this.rawConstructor = rawConstructor;
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
}
// for allocation only:
private AllocateObject(Class<C> allocateClass) {
super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
this.allocateClass = allocateClass;
this.rawConstructor = null;
}
static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodType rawConType = rawConstructor.type();
assert(rawConType.parameterType(0) == allocateClass);
MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
......@@ -129,14 +161,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType conType = CON_TYPES[nargs];
MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
MethodHandle gcon = spreadArgumentsFromPos(rawConstructor, conType, 1);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
return collectArguments(galloc, newType, 1, null);
}
}
@Override
public String toString() {
String debugString() {
return addTypeString(allocateClass.getSimpleName(), this);
}
@SuppressWarnings("unchecked")
......@@ -214,9 +246,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// For testing use this:
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
static final MethodHandle VARARGS_INVOKE;
static final MethodHandle ALLOCATE;
static {
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0));
} catch (ReflectiveOperationException ex) {
throw uncaughtException(ex);
}
......@@ -278,7 +312,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.base = staticBase(field);
}
@Override
public String toString() { return addTypeString(name, this); }
String debugString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
......@@ -309,8 +343,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
try {
// FIXME: Should not have to create 'f' to get this value.
f = c.getDeclaredField(field.getName());
// Note: Previous line might invalidly throw SecurityException (7042829)
return unsafe.staticFieldBase(f);
} catch (Exception ee) {
} catch (NoSuchFieldException ee) {
throw uncaughtException(ee);
}
}
......@@ -455,14 +490,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
*/
static
MethodHandle bindReceiver(MethodHandle target, Object receiver) {
if (receiver == null) return null;
if (target instanceof AdapterMethodHandle &&
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
) {
Object info = MethodHandleNatives.getTargetInfo(target);
if (info instanceof DirectMethodHandle) {
DirectMethodHandle dmh = (DirectMethodHandle) info;
if (receiver == null ||
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
if (dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
MethodType newType = target.type().dropParameterTypes(0, 1);
return convertArguments(bmh, newType, bmh.type(), 0);
......@@ -668,7 +703,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if (target == null) throw newIllegalArgumentException("cannot drop");
oldType = target.type();
}
return convertArguments(target, newType, oldType, 0);
target = convertArguments(target, newType, oldType, 0);
assert(target != null);
return target;
}
/*non-public*/ static
......@@ -747,7 +784,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
.insertParameterTypes(keepPosArgs, arrayType);
return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
}
static MethodHandle spreadArguments(MethodHandle target, MethodType newType, int spreadArgPos) {
static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
int arrayLength = target.type().parameterCount() - spreadArgPos;
return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
}
......@@ -761,9 +798,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// spread the last argument of newType to oldType
assert(arrayLength == oldType.parameterCount() - spreadArgPos);
assert(newType.parameterType(spreadArgPos) == arrayType);
MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
if (res == null) throw new IllegalArgumentException("spread on "+target+" with "+arrayType.getSimpleName());
return res;
return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
}
static MethodHandle collectArguments(MethodHandle target,
......@@ -771,6 +806,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle collector) {
MethodType type = target.type();
Class<?> collectType = collector.type().returnType();
assert(collectType != void.class); // else use foldArguments
if (collectType != type.parameterType(collectArg))
target = target.asType(type.changeParameterType(collectArg, collectType));
MethodType newType = type
......@@ -879,11 +915,15 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.target = target;
this.fallback = fallback;
}
// FIXME: Build the control flow out of foldArguments.
static boolean preferRicochetFrame(MethodType type) {
return (type.parameterCount() >= INVOKES.length || type.hasPrimitives());
}
static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
MethodType type = target.type();
int nargs = type.parameterCount();
if (nargs < INVOKES.length) {
if (preferRicochetFrame(type))
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodHandle invoke = INVOKES[nargs];
MethodType gtype = type.generic();
assert(invoke.type().dropParameterTypes(0,1) == gtype);
......@@ -894,19 +934,20 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
return convertArguments(gguard, type, gtype, 0);
} else {
assert(MethodHandleNatives.workaroundWithoutRicochetFrames()); // this code is deprecated
MethodHandle invoke = VARARGS_INVOKE;
MethodType gtype = MethodType.genericMethodType(1);
assert(invoke.type().dropParameterTypes(0,1) == gtype);
MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
MethodHandle gtarget = spreadArguments(target, gtype, 0);
MethodHandle gfallback = spreadArguments(fallback, gtype, 0);
MethodHandle gtest = spreadArgumentsFromPos(test, gtype.changeReturnType(boolean.class), 0);
MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
MethodHandle gfallback = spreadArgumentsFromPos(fallback, gtype, 0);
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
if (gtest == null || gtarget == null || gfallback == null) return null;
return collectArguments(gguard, type, 0, null);
}
}
@Override
public String toString() {
String debugString() {
return addTypeString(target, this);
}
private Object invoke_V(Object... av) throws Throwable {
......@@ -989,10 +1030,50 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
}
static
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
return testResult ? target : fallback;
}
static MethodHandle SELECT_ALTERNATIVE;
static MethodHandle selectAlternative() {
if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE;
try {
SELECT_ALTERNATIVE
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
return SELECT_ALTERNATIVE;
}
static
MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
// gwt(arg...)
// [fold]=> continueAfterTest(z=test(arg...), arg...)
// [filter]=> (tf=select(z))(arg...)
// where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
// [tailcall]=> tf(arg...)
assert(test.type().returnType() == boolean.class);
MethodType targetType = target.type();
MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)
&& GuardWithTest.preferRicochetFrame(targetType)) {
// working backwards, as usual:
assert(target.type().equals(fallback.type()));
MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
MethodHandle select = selectAlternative();
select = bindArgument(select, 2, fallback);
select = bindArgument(select, 1, target);
// select(z: boolean) => (z ? target : fallback)
MethodHandle filter = filterArgument(tailcall, 0, select);
assert(filter.type().parameterType(0) == boolean.class);
MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
return fold;
}
return GuardWithTest.make(test, target, fallback);
}
......@@ -1012,7 +1093,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
this.catcher = catcher;
}
@Override
public String toString() {
String debugString() {
return addTypeString(target, this);
}
private Object invoke_V(Object... av) throws Throwable {
......@@ -1144,11 +1225,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} else {
MethodType gtype = MethodType.genericMethodType(0, true);
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
MethodHandle gtarget = spreadArguments(target, gtype, 0);
MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1);
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null;
return collectArguments(gguard, type, 0, null);
return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
}
}
......@@ -1178,8 +1260,4 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static MethodHandle getBootstrap(Class<?> callerClass) {
return MethodHandleNatives.getBootstrap(callerClass);
}
static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
}
}
......@@ -400,7 +400,7 @@ class MethodHandleNatives {
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);
throw new InternalError("bad MethodHandle constant "+name+" : "+type);
} catch (ReflectiveOperationException ex) {
Error err = new IncompatibleClassChangeError();
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;
}
}
......@@ -35,6 +35,8 @@ package java.lang.invoke;
private MethodHandleStatics() { } // do not instantiate
static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
/*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
if (type == null)
type = target.type();
......
......@@ -163,7 +163,13 @@ class MethodType implements java.io.Serializable {
public static
MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
boolean notrust = false; // random List impl. could return evil ptypes array
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
return makeImpl(rtype, listToArray(ptypes), notrust);
}
private static Class<?>[] listToArray(List<Class<?>> ptypes) {
// sanity check the size before the toArray call, since size might be huge
checkSlotCount(ptypes.size());
return ptypes.toArray(NO_PTYPES);
}
/**
......@@ -228,7 +234,7 @@ class MethodType implements java.io.Serializable {
*/
/*trusted*/ static
MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
if (ptypes == null || ptypes.length == 0) {
if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
}
MethodType mt1 = new MethodType(rtype, ptypes);
......@@ -267,7 +273,7 @@ class MethodType implements java.io.Serializable {
* @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[]}
* @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)
*/
public static
......@@ -372,7 +378,7 @@ class MethodType implements java.io.Serializable {
* @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
*/
public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES));
return insertParameterTypes(num, listToArray(ptypesToInsert));
}
/**
......@@ -449,7 +455,8 @@ class MethodType implements java.io.Serializable {
/**
* Reports if this type contains a wrapper argument or return value.
* 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
*/
public boolean hasWrappers() {
......@@ -641,14 +648,57 @@ class MethodType implements java.io.Serializable {
}
return true;
}
private static boolean canConvert(Class<?> src, Class<?> dst) {
if (src == dst || dst == void.class) return true;
if (src.isPrimitive() && dst.isPrimitive()) {
if (!Wrapper.forPrimitiveType(dst)
.isConvertibleFrom(Wrapper.forPrimitiveType(src)))
/*non-public*/
static boolean canConvert(Class<?> src, Class<?> dst) {
// short-circuit a few cases:
if (src == dst || dst == Object.class) return true;
// the remainder of this logic is documented in MethodHandle.asType
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;
} else {
// R->R always works, since null is always valid dynamically
return true;
}
return true;
}
/// Queries which have to do with the bytecode architecture
......@@ -733,15 +783,21 @@ class MethodType implements java.io.Serializable {
* @param descriptor a bytecode-level type descriptor string "(T...)T"
* @param loader the class loader in which to look up the types
* @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 TypeNotPresentException if a named type cannot be found
*/
public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException
{
if (!descriptor.startsWith("(") || // also generates NPE if needed
descriptor.indexOf(')') < 0 ||
descriptor.indexOf('.') >= 0)
throw new IllegalArgumentException("not a method descriptor: "+descriptor);
List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
Class<?> rtype = types.remove(types.size() - 1);
Class<?>[] ptypes = types.toArray(NO_PTYPES);
checkSlotCount(types.size());
Class<?>[] ptypes = listToArray(types);
return makeImpl(rtype, ptypes, true);
}
......
......@@ -448,6 +448,8 @@ class MethodTypeForm {
Class<?>[] cs = null;
for (int imax = ts.length, i = 0; i < imax; i++) {
Class<?> c = canonicalize(ts[i], how);
if (c == void.class)
c = null; // a Void parameter was unwrapped to void; ignore
if (c != null) {
if (cs == null)
cs = ts.clone();
......
......@@ -37,12 +37,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p>
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
* <!-- JavaDocExamplesTest.testMutableCallSite -->
* <blockquote><pre>
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
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()
.findVirtual(String.class, "toUpperCase", MT_str2);
.findVirtual(String.class, "toUpperCase", MT_str1);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact());
......@@ -53,8 +54,10 @@ assertEquals("FRED", (String) worker1.invokeExact());
* <p>
* The same call site may be used in several places at once.
* <blockquote><pre>
MethodHandle MH_dear = MethodHandles.lookup()
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
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);
assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
......
......@@ -126,7 +126,7 @@ class SpreadGeneric {
return spreadGen;
}
public String toString() {
String debugString() {
return getClass().getSimpleName()+targetType+"["+spreadCount+"]";
}
......@@ -224,7 +224,7 @@ class SpreadGeneric {
protected final MethodHandle target; // (any**N) => R
@Override
public String toString() {
String debugString() {
return addTypeString(target, this);
}
......
......@@ -56,16 +56,17 @@ package java.lang.invoke;
* <p>
* Here is an example of a switch point in action:
* <blockquote><pre>
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
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();
assert(spt.isValid());
// the following steps may be repeated to re-use the same switch point:
MethodHandle worker1 = strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0);
MethodHandle worker1 = MH_strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
MethodHandle worker = spt.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(!spt.isValid());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* </pre></blockquote>
* <p style="font-size:smaller;">
......@@ -124,6 +125,19 @@ public class SwitchPoint {
this.mcsInvoker = mcs.dynamicInvoker();
}
/**
* Determines if this switch point is still valid.
* <p>
* Since invalidation is a global and immediate operation,
* this query must be sequenced with any
* other threads that could invalidate this switch point.
* It may therefore be expensive.
* @return true if this switch point has never been invalidated
*/
public boolean isValid() {
return (mcs.getTarget() == K_true);
}
/**
* 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.
......@@ -136,6 +150,7 @@ public class SwitchPoint {
* @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
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the two method types do not match
* @see MethodHandles#guardWithTest
*/
public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
......
......@@ -258,7 +258,7 @@ class ToGeneric {
return toGen;
}
public String toString() {
String debugString() {
return "ToGeneric"+entryType
+(primsAtEndOrder!=null?"[reorder]":"");
}
......@@ -340,7 +340,7 @@ class ToGeneric {
protected final MethodHandle convert; // Object -> R
@Override
public String toString() {
String debugString() {
return target == null ? "prototype:"+convert : addTypeString(target, this);
}
......
......@@ -460,15 +460,13 @@ public interface Path
/**
* Returns a URI to represent this path.
*
* <p> This method constructs a hierarchical {@link URI} that is absolute
* with a non-empty path component. Its {@link URI#getScheme() scheme} is
* equal to the URI scheme that identifies the provider. The exact form of
* the other URI components is highly provider dependent. In particular, it
* is implementation dependent if its query, fragment, and authority
* components are defined or undefined.
*
* <p> For the default provider the {@link URI#getPath() path} component
* will represent the {@link #toAbsolutePath absolute} path; the query,
* <p> This method constructs an absolute {@link URI} with a {@link
* URI#getScheme() scheme} equal to the URI scheme that identifies the
* provider. The exact form of the scheme specific part is highly provider
* dependent.
*
* <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
* fragment components are undefined. Whether the authority component is
* 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}.
......@@ -497,7 +495,7 @@ public interface Path
* A format for compound URIs is not defined in this release; such a scheme
* 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
* if an I/O error occurs obtaining the absolute path, or where a
......
......@@ -588,6 +588,10 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
}
private void addDefault(String key, Object value) {
if (compiledDefaults == null) {
return;
}
String prefix = parsePrefix(key);
if (prefix != null) {
Map<String, Object> keys = compiledDefaults.get(prefix);
......
......@@ -337,8 +337,7 @@ public class Utilities {
// x before x0, return.
return 0;
}
int currX = x0;
int nextX = currX;
int nextX = x0;
// s may be a shared segment, so it is copied prior to calling
// the tab expander
char[] txt = s.array;
......@@ -388,19 +387,45 @@ public class Utilities {
} else {
nextX += metrics.charWidth(txt[i]);
}
if ((x >= currX) && (x < nextX)) {
if (x < nextX) {
// found the hit position... return the appropriate side
int offset = ((round == false) || ((x - currX) < (nextX - x))) ?
(i - txtOffset) : (i + 1 - txtOffset);
int offset;
// the length of the string measured as a whole may differ from
// the sum of individual character lengths, for example if
// fractional metrics are enabled; and we must guard from this.
while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) {
offset--;
if (round) {
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;
}
currX = nextX;
}
// didn't find, return end offset
......
......@@ -180,7 +180,6 @@ public class FileFontStrike extends PhysicalStrike {
pScalerContext = NullFontScaler.getNullScalerContext();
} else {
pScalerContext = fileFont.getScaler().createScalerContext(matrix,
fileFont instanceof TrueTypeFont,
desc.aaHint, desc.fmHint,
boldness, italic, disableHinting);
}
......
......@@ -242,7 +242,6 @@ public abstract class FontScaler implements DisposerRecord {
freed when corresponding strike is being released.
*/
abstract long createScalerContext(double[] matrix,
boolean fontType,
int aa, int fm,
float boldness, float italic,
boolean disableHinting);
......
......@@ -210,12 +210,12 @@ class FreetypeFontScaler extends FontScaler {
return getUnitsPerEMNative(nativeScaler);
}
long createScalerContext(double[] matrix, boolean fontType,
long createScalerContext(double[] matrix,
int aa, int fm, float boldness, float italic,
boolean disableHinting) {
if (nativeScaler != 0L) {
return createScalerContextNative(nativeScaler, matrix,
fontType, aa, fm, boldness, italic);
aa, fm, boldness, italic);
}
return NullFontScaler.getNullScalerContext();
}
......@@ -254,7 +254,7 @@ class FreetypeFontScaler extends FontScaler {
private native long getUnitsPerEMNative(long pScaler);
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
has to be invalidated if native scaler is bad */
......
......@@ -66,7 +66,7 @@ class NullFontScaler extends FontScaler {
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) {
return getNullScalerContext();
}
......
......@@ -198,27 +198,30 @@ public class ValueConversions {
return unbox(Wrapper.forPrimitiveType(type), true, false);
}
static private final Integer ZERO_INT = 0, ONE_INT = 1;
/// Primitive conversions
public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
// Maybe merge this code with Wrapper.convert/cast.
Number res = null;
if (x == null) {
if (!cast) return null;
x = wrap.zero();
return ZERO_INT;
}
if (x instanceof Number) {
res = (Number) x;
} else if (x instanceof Boolean) {
res = ((boolean)x ? 1 : 0);
res = ((boolean)x ? ONE_INT : ZERO_INT);
} else if (x instanceof Character) {
res = (int)(char)x;
} else {
// this will fail with the required ClassCastException:
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:
res = (Number) wrap.wrapperType().cast(x);
return (Number) wrap.wrapperType().cast(x);
return res;
}
......
......@@ -154,9 +154,10 @@ public class VerifyAccess {
* @return whether they are in the same package
*/
public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
assert(!class1.isArray() && !class2.isArray());
if (class1 == class2)
return true;
if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader(), false))
return false;
String name1 = class1.getName(), name2 = class2.getName();
int dot = name1.lastIndexOf('.');
......@@ -169,6 +170,16 @@ public class VerifyAccess {
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).
* If this is true, they can share private access with each other.
......@@ -193,18 +204,33 @@ public class VerifyAccess {
return pkgmem;
}
private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) {
if (loader1 == loader2 || loader1 == null || loader2 == null) {
private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,
boolean loader1MustBeParent) {
if (loader1 == loader2 || loader1 == null
|| (loader2 == null && !loader1MustBeParent)) {
return true;
}
for (ClassLoader scan1 = loader1;
scan1 != null; scan1 = scan1.getParent()) {
if (scan1 == loader2) return true;
}
for (ClassLoader scan2 = loader2;
scan2 != null; scan2 = scan2.getParent()) {
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;
}
/**
* 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 {
* <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}
* </ul>
* These are the cases allowed by MethodHandle.asType and convertArguments.
* These are the cases allowed by MethodHandle.asType.
*/
public boolean isConvertibleFrom(Wrapper source) {
if (this == source) return true;
......@@ -258,7 +258,7 @@ public enum Wrapper {
}
/** Return the wrapper that wraps values into the given wrapper type.
* If it is {@code Object} or an interface, return {@code OBJECT}.
* If it is {@code Object}, return {@code OBJECT}.
* Otherwise, it must be a wrapper type.
* The type must not be a primitive type.
* @throws IllegalArgumentException for unexpected types
......@@ -277,8 +277,6 @@ public enum Wrapper {
if (w != null && w.wrapperType == type) {
return w;
}
if (type.isInterface())
return OBJECT;
return null;
}
......
/*
* 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.
*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......
......@@ -367,7 +367,7 @@ static double euclidianDistance(double a, double b) {
JNIEXPORT jlong JNICALL
Java_sun_font_FreetypeFontScaler_createScalerContextNative(
JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix,
jboolean ttFont, jint aa, jint fm, jfloat boldness, jfloat italic) {
jint aa, jint fm, jfloat boldness, jfloat italic) {
double dmat[4], ptsz;
FTScalerContext *context =
(FTScalerContext*) calloc(1, sizeof(FTScalerContext));
......
......@@ -29,8 +29,6 @@ import java.awt.FileDialog;
import java.awt.peer.FileDialogPeer;
import java.io.File;
import java.io.FilenameFilter;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import sun.awt.AWTAccessor;
/**
......@@ -107,9 +105,7 @@ class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
if (b) {
Thread t = new Thread() {
public void run() {
GtkFileDialogPeer.this.run(fd.getTitle(), fd.getMode(),
fd.getDirectory(), fd.getFile(), fd.getFilenameFilter(), fd.isMultipleMode(),
fd.getX(), fd.getY());
showNativeDialog();
fd.setVisible(false);
}
};
......@@ -146,4 +142,30 @@ class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
// We do not implement this method because we
// have delegated to FileDialog#setFilenameFilter
}
private void showNativeDialog() {
String dirname = fd.getDirectory();
// File path has a priority against directory path.
String filename = fd.getFile();
if (filename != null) {
final File file = new File(filename);
if (fd.getMode() == FileDialog.LOAD
&& dirname != null
&& file.getParent() == null) {
// File path for gtk_file_chooser_set_filename.
filename = dirname + (dirname.endsWith(File.separator) ? "" :
File.separator) + filename;
}
if (fd.getMode() == FileDialog.SAVE && file.getParent() != null) {
// Filename for gtk_file_chooser_set_current_name.
filename = file.getName();
// Directory path for gtk_file_chooser_set_current_folder.
dirname = file.getParent();
}
}
GtkFileDialogPeer.this.run(fd.getTitle(), fd.getMode(), dirname,
filename, fd.getFilenameFilter(),
fd.isMultipleMode(), fd.getX(), fd.getY());
}
}
......@@ -121,7 +121,7 @@ public class X11GraphicsEnvironment
// only attempt to initialize Xrender if it was requested
if (xRenderRequested) {
xRenderAvailable = initXRender();
xRenderAvailable = initXRender(xRenderVerbose);
if (xRenderVerbose && !xRenderAvailable) {
System.out.println(
"Could not enable XRender pipeline");
......@@ -159,7 +159,7 @@ public class X11GraphicsEnvironment
private static boolean xRenderVerbose;
private static boolean xRenderAvailable;
private static native boolean initXRender();
private static native boolean initXRender(boolean verbose);
public static boolean isXRenderAvailable() {
return xRenderAvailable;
}
......
." 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.
."
." 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.
."
." This code is free software; you can redistribute it and/or modify it
......
......@@ -66,9 +66,10 @@ typedef struct _XRadialGradient {
} XRadialGradient;
#endif
#include <dlfcn.h>
#ifdef __solaris__
/* Solaris 10 will not have these symbols at runtime */
#include <dlfcn.h>
#include <link.h>
typedef Picture (*XRenderCreateLinearGradientFuncType)
......@@ -104,12 +105,20 @@ static
TRANSFORM.matrix[2][2] = 1<<16; \
}
/* The xrender pipleine requires libXrender.so version 0.9.3 or later. */
#define REQUIRED_XRENDER_VER1 0
#define REQUIRED_XRENDER_VER2 9
#define REQUIRED_XRENDER_VER3 3
static jboolean IsXRenderAvailable() {
#define PKGINFO_LINE_LEN_MAX 256
#define PKGINFO_LINE_CNT_MAX 50
static jboolean IsXRenderAvailable(jboolean verbose) {
void *xrenderlib;
int major_opcode, first_event, first_error;
jboolean available = JNI_TRUE;
if (!XQueryExtension(awt_display, "RENDER",
&major_opcode, &first_event, &first_error)) {
......@@ -120,23 +129,113 @@ static jboolean IsXRenderAvailable() {
xrenderlib = dlopen("libXrender.so",RTLD_GLOBAL|RTLD_LAZY);
if (xrenderlib != NULL) {
XRenderCreateLinearGradientFunc =
(XRenderCreateLinearGradientFuncType)
dlsym(xrenderlib, "XRenderCreateLinearGradient");
XRenderCreateLinearGradientFunc =
(XRenderCreateLinearGradientFuncType)
dlsym(xrenderlib, "XRenderCreateLinearGradient");
XRenderCreateRadialGradientFunc =
(XRenderCreateRadialGradientFuncType)
dlsym(xrenderlib, "XRenderCreateRadialGradient");
XRenderCreateRadialGradientFunc =
(XRenderCreateRadialGradientFuncType)
dlsym(xrenderlib, "XRenderCreateRadialGradient");
if (XRenderCreateLinearGradientFunc == NULL ||
XRenderCreateRadialGradientFunc == NULL)
{
available = JNI_FALSE;
}
dlclose(xrenderlib);
} else {
available = JNI_FALSE;
}
#else
Dl_info info;
jboolean versionInfoIsFound = JNI_FALSE;
memset(&info, 0, sizeof(Dl_info));
if (dladdr(&XRenderChangePicture, &info) && info.dli_fname != NULL) {
char pkgInfoPath[FILENAME_MAX];
char *pkgFileName = "/pkgconfig/xrender.pc";
size_t pkgFileNameLen = strlen(pkgFileName);
size_t pos, len = strlen(info.dli_fname);
pos = len;
while (pos > 0 && info.dli_fname[pos] != '/') {
pos -= 1;
}
if (XRenderCreateLinearGradientFunc == NULL ||
XRenderCreateRadialGradientFunc == NULL)
if (pos > 0 && pos < (FILENAME_MAX - pkgFileNameLen - 1)) {
struct stat stat_info;
// compose absolute filename to package config
strncpy(pkgInfoPath, info.dli_fname, pos);
strcpy(pkgInfoPath + pos, pkgFileName);
pkgInfoPath[pos + pkgFileNameLen] = '\0';
// check whether the config file exist and is a regular file
if ((stat(pkgInfoPath, &stat_info)== 0) &&
S_ISREG(stat_info.st_mode))
{
dlclose(xrenderlib);
return JNI_FALSE;
FILE *fp = fopen(pkgInfoPath, "r");
if (fp != NULL) {
char line[PKGINFO_LINE_LEN_MAX];
int lineCount = PKGINFO_LINE_CNT_MAX;
char *versionPrefix = "Version: ";
size_t versionPrefixLen = strlen(versionPrefix);
// look for version
while(fgets(line,sizeof(line),fp) != NULL && --lineCount > 0) {
size_t lineLen = strlen(line);
if (lineLen > versionPrefixLen &&
strncmp(versionPrefix, line, versionPrefixLen) == 0)
{
int v1 = 0, v2 = 0, v3 = 0;
int numNeeded = 3,numProcessed;
char* version = line + versionPrefixLen;
numProcessed = sscanf(version, "%d.%d.%d", &v1, &v2, &v3);
if (numProcessed == numNeeded) {
// we successfuly read the library version
versionInfoIsFound = JNI_TRUE;
if (REQUIRED_XRENDER_VER1 == v1 &&
((REQUIRED_XRENDER_VER2 > v2) ||
((REQUIRED_XRENDER_VER2 == v2) && (REQUIRED_XRENDER_VER3 > v3))))
{
available = JNI_FALSE;
if (verbose) {
printf("INFO: the version %d.%d.%d of libXrender.so is "
"not supported.\n\tSee release notes for more details.\n",
v1, v2, v3);
fflush(stdout);
}
} else {
if (verbose) {
printf("INFO: The version of libXrender.so "
"is detected as %d.%d%d\n", v1, v2, v3);
fflush(stdout);
}
}
}
break;
}
}
fclose(fp);
}
}
}
}
if (verbose && !versionInfoIsFound) {
printf("WARNING: The version of libXrender.so cannot be detected.\n,"
"The pipe line will be enabled, but note that versions less than 0.9.3\n"
"may cause hangs and crashes\n"
"\tSee the release notes for more details.\n");
fflush(stdout);
}
#endif
return JNI_TRUE;
return available;
}
/*
* Class: sun_awt_X11GraphicsEnvironment
......@@ -145,7 +244,7 @@ static jboolean IsXRenderAvailable() {
*/
JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsEnvironment_initXRender
(JNIEnv *env, jclass x11ge)
(JNIEnv *env, jclass x11ge, jboolean verbose)
{
#ifndef HEADLESS
static jboolean xrenderAvailable = JNI_FALSE;
......@@ -153,7 +252,7 @@ Java_sun_awt_X11GraphicsEnvironment_initXRender
if (firstTime) {
AWT_LOCK();
xrenderAvailable = IsXRenderAvailable();
xrenderAvailable = IsXRenderAvailable(verbose);
AWT_UNLOCK();
firstTime = JNI_FALSE;
}
......
......@@ -3715,7 +3715,10 @@ void AwtComponent::OpenCandidateWindow(int x, int y)
SetCandidateWindow(iCandType, x-rc.left, y-rc.top);
}
if (m_bitsCandType != 0) {
::DefWindowProc(GetHWnd(), WM_IME_NOTIFY, IMN_OPENCANDIDATE, m_bitsCandType);
HWND proxy = GetProxyFocusOwner();
// REMIND: is there any chance GetProxyFocusOwner() returns NULL here?
::DefWindowProc((proxy != NULL) ? proxy : GetHWnd(),
WM_IME_NOTIFY, IMN_OPENCANDIDATE, m_bitsCandType);
}
}
......
......@@ -69,9 +69,12 @@ void AwtObject::_Dispose(jobject self)
CriticalSection::Lock l(AwtToolkit::GetInstance().GetSyncCS());
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jobject selfGlobalRef = env->NewGlobalRef(self);
// value 0 of lParam means that we should not attempt to enter the
// SyncCall critical section, as it was entered someshere earlier
AwtToolkit::GetInstance().SendMessage(WM_AWT_DISPOSE, (WPARAM)self, (LPARAM)0);
AwtToolkit::GetInstance().SendMessage(WM_AWT_DISPOSE, (WPARAM)selfGlobalRef, (LPARAM)0);
CATCH_BAD_ALLOC;
}
......
......@@ -741,7 +741,9 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
}
if (canDispose) {
if(wParam != NULL) {
AwtObject *o = (AwtObject *) JNI_GET_PDATA((jobject)wParam);
jobject self = (jobject)wParam;
AwtObject *o = (AwtObject *) JNI_GET_PDATA(self);
env->DeleteGlobalRef(self);
if(o != NULL && theAwtObjectList.Remove(o)) {
o->Dispose();
}
......
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 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
......
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
......
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
......
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
......
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
......
/*
* Copyright (c) 2007, 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
......
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2009, 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
......@@ -16,10 +16,10 @@
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
......
......@@ -51,10 +51,10 @@ public class Test6991596 {
return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
}
static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
return MethodHandles.explicitCastArguments(mh1, MethodType.methodType(ret, arg));
}
static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) {
return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
return MethodHandles.explicitCastArguments(mh1, MethodType.methodType(ret, arg));
}
// test adapter_opt_i2i
......
......@@ -164,6 +164,7 @@ public class Test6998541 {
private static boolean canDoAsType(Class<?> src, Class<?> dst) {
if (src == dst) return true;
if (dst == void.class) return true;
if (src == void.class) return true; // allow void->zero
if (!src.isPrimitive() || !dst.isPrimitive()) return true;
// primitive conversion works for asType only when it's widening
if (src == boolean.class || dst == boolean.class) return false;
......@@ -451,7 +452,6 @@ public class Test6998541 {
private final static MethodHandle mh_dv = mh(double.class );
private static void void2prim(int i) throws Throwable {
if (!DO_CASTS) return;
assertEquals( false, (boolean) mh_zv.invokeExact()); // void -> boolean
assertEquals((byte) 0, (byte) mh_bv.invokeExact()); // void -> byte
assertEquals((char) 0, (char) mh_cv.invokeExact()); // void -> char
......@@ -463,15 +463,7 @@ public class Test6998541 {
}
private static void void2prim_invalid(double x) throws Throwable {
if (DO_CASTS) return;
try { assertEquals( false, (boolean) mh_zv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> boolean
try { assertEquals((byte) 0, (byte) mh_bv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> byte
try { assertEquals((char) 0, (char) mh_cv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> char
try { assertEquals((short) 0, (short) mh_sv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> short
try { assertEquals( 0, (int) mh_iv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> int
try { assertEquals( 0L, (long) mh_jv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> long
try { assertEquals( 0.0f, (float) mh_fv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> float
try { assertEquals( 0.0d, (double) mh_dv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> double
// no cases
}
private static MethodHandle mh_v(Class arg) { return mh(void.class, arg); }
......
......@@ -106,8 +106,10 @@ public class InvokeDynamicPrintArgs {
"Done printing argument lists."
};
private static boolean doPrint = true;
private static void printArgs(Object bsmInfo, Object... args) {
System.out.println(bsmInfo+Arrays.deepToString(args));
String message = bsmInfo+Arrays.deepToString(args);
if (doPrint) System.out.println(message);
}
private static MethodHandle MH_printArgs() throws ReflectiveOperationException {
shouldNotCallThis();
......@@ -129,11 +131,48 @@ public class InvokeDynamicPrintArgs {
return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
}
private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws ReflectiveOperationException {
/* Example of a constant call site with user-data.
* In this case, the user data is exactly the BSM data.
* Note that a CCS with user data must use the "hooked" constructor
* to bind the CCS itself into the resulting target.
* A normal constructor would not allow a circular relation
* between the CCS and its target.
*/
public static class PrintingCallSite extends ConstantCallSite {
final Lookup caller;
final String name;
final Object[] staticArgs;
PrintingCallSite(Lookup caller, String name, MethodType type, Object... staticArgs) throws Throwable {
super(type, MH_createTarget());
this.caller = caller;
this.name = name;
this.staticArgs = staticArgs;
}
public MethodHandle createTarget() {
try {
return lookup().bind(this, "runTarget", genericMethodType(0, true)).asType(type());
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
public Object runTarget(Object... dynamicArgs) {
List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type()));
bsmInfo.addAll(Arrays.asList(staticArgs));
printArgs(bsmInfo, dynamicArgs);
return null;
}
private static MethodHandle MH_createTarget() throws ReflectiveOperationException {
shouldNotCallThis();
return lookup().findVirtual(lookup().lookupClass(), "createTarget", methodType(MethodHandle.class));
}
}
private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws Throwable {
// ignore caller and name, but match the type:
List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type));
bsmInfo.addAll(Arrays.asList((Object[])arg));
return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
return new PrintingCallSite(caller, name, type, arg);
}
private static MethodType MT_bsm2() {
shouldNotCallThis();
......@@ -146,33 +185,33 @@ public class InvokeDynamicPrintArgs {
private static MethodHandle INDY_nothing() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm().invokeGeneric(lookup(),
return ((CallSite) MH_bsm().invoke(lookup(),
"nothing", methodType(void.class)
)).dynamicInvoker();
}
private static MethodHandle INDY_foo() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm().invokeGeneric(lookup(),
return ((CallSite) MH_bsm().invoke(lookup(),
"foo", methodType(void.class, String.class)
)).dynamicInvoker();
}
private static MethodHandle INDY_bar() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
return ((CallSite) MH_bsm2().invoke(lookup(),
"bar", methodType(void.class, String.class, int.class)
, Void.class, "void type!", 1, 234.5F, 67.5, (long)89
)).dynamicInvoker();
}
private static MethodHandle INDY_bar2() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
return ((CallSite) MH_bsm2().invoke(lookup(),
"bar2", methodType(void.class, String.class, int.class)
, Void.class, "void type!", 1, 234.5F, 67.5, (long)89
)).dynamicInvoker();
}
private static MethodHandle INDY_baz() throws Throwable {
shouldNotCallThis();
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
return ((CallSite) MH_bsm2().invoke(lookup(),
"baz", methodType(void.class, String.class, int.class, double.class)
, 1234.5
)).dynamicInvoker();
......
......@@ -53,9 +53,9 @@ public class InvokeGenericTest {
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
public static void main(String... av) throws Throwable {
new InvokeGenericTest().testFirst();
}
// public static void main(String... av) throws Throwable {
// new InvokeGenericTest().testFirst();
// }
@Test
public void testFirst() throws Throwable {
......@@ -314,7 +314,7 @@ public class InvokeGenericTest {
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
Collections.fill(argTypes.subList(beg, end), argType);
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
return MethodHandles.convertArguments(target, ttype2);
return target.asType(ttype2);
}
// This lookup is good for all members in and under InvokeGenericTest.
......@@ -378,7 +378,7 @@ public class InvokeGenericTest {
String[] args = { "one", "two" };
MethodHandle mh = callable(Object.class, String.class);
Object res; List resl;
res = resl = (List) mh.invokeGeneric((String)args[0], (Object)args[1]);
res = resl = (List) mh.invoke((String)args[0], (Object)args[1]);
//System.out.println(res);
assertEquals(Arrays.asList(args), res);
}
......@@ -470,8 +470,6 @@ public class InvokeGenericTest {
return allMethodTypes(argc, argc, types);
}
interface RandomInterface { }
MethodHandle toString_MH;
@Test
......@@ -480,33 +478,62 @@ public class InvokeGenericTest {
toString_MH = LOOKUP.
findVirtual(Object.class, "toString", MethodType.methodType(String.class));
Object[] args = { "one", "two" };
for (MethodType type : allMethodTypes(2, Object.class, String.class, RandomInterface.class)) {
for (MethodType type : allMethodTypes(2, Object.class, String.class, CharSequence.class)) {
testReferenceConversions(type, args);
}
}
public void testReferenceConversions(MethodType type, Object... args) throws Throwable {
countTest();
if (verbosity > 3) System.out.println("target type: "+type);
int nargs = args.length;
List<Object> argList = Arrays.asList(args);
String expectString = argList.toString();
if (verbosity > 3) System.out.println("target type: "+type+expectString);
MethodHandle mh = callable(type.parameterList());
MethodHandle tsdrop = MethodHandles.dropArguments(toString_MH, 1, type.parameterList());
mh = MethodHandles.foldArguments(tsdrop, mh);
mh = MethodHandles.filterReturnValue(mh, toString_MH);
mh = mh.asType(type);
Object res = mh.invoke((String)args[0], (Object)args[1]);
Object res = null;
if (nargs == 2) {
res = mh.invoke((Object)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = mh.invoke((String)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = mh.invoke((Object)args[0], (String)args[1]);
assertEquals(expectString, res);
res = mh.invoke((String)args[0], (String)args[1]);
assertEquals(expectString, res);
res = mh.invoke((String)args[0], (CharSequence)args[1]);
assertEquals(expectString, res);
res = mh.invoke((CharSequence)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = (String) mh.invoke((Object)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = (String) mh.invoke((String)args[0], (Object)args[1]);
assertEquals(expectString, res);
res = (CharSequence) mh.invoke((String)args[0], (Object)args[1]);
assertEquals(expectString, res);
} else {
assert(false); // write this code
}
//System.out.println(res);
assertEquals(Arrays.asList(args).toString(), res);
}
@Test @Ignore("known failure pending 6939861")
@Test
public void testBoxConversions() throws Throwable {
startTest("testBoxConversions");
countTest();
Object[] args = { 1, 2 };
MethodHandle mh = callable(Object.class, int.class);
Object res; List resl;
Object res; List resl; int resi;
res = resl = (List) mh.invoke((int)args[0], (Object)args[1]);
//System.out.println(res);
assertEquals(Arrays.asList(args), res);
mh = MethodHandles.identity(int.class);
mh = MethodHandles.dropArguments(mh, 1, int.class);
res = resi = (int) mh.invoke((Object) args[0], (Object) args[1]);
assertEquals(args[0], res);
res = resi = (int) mh.invoke((int) args[0], (Object) args[1]);
assertEquals(args[0], res);
}
}
/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 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
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册